Linux bluetooth development
 help / color / mirror / Atom feed
* [BlueZ v10 15/16] github: Add docs deployment
From: Bastien Nocera @ 2026-05-05  8:45 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <20260505085741.2497401-1-hadess@hadess.net>

---
 .github/workflows/docs.yml | 54 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 54 insertions(+)
 create mode 100644 .github/workflows/docs.yml

diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml
new file mode 100644
index 000000000000..07169d0bc5c9
--- /dev/null
+++ b/.github/workflows/docs.yml
@@ -0,0 +1,54 @@
+name: Deploy Docs
+
+on:
+  push:
+    branches:
+      - master
+  workflow_dispatch:
+
+permissions:
+  contents: read
+  pages: write
+  id-token: write
+
+concurrency:
+  group: pages
+  cancel-in-progress: true
+
+jobs:
+  build:
+    runs-on: ubuntu-latest
+    steps:
+      - name: Checkout
+        uses: actions/checkout@v4
+
+      - name: Set up Python
+        uses: actions/setup-python@v5
+        with:
+          python-version: "3.12"
+
+      - name: Install deps
+        run: |
+          sudo apt-get update
+          sudo apt install -y libglib2.0-dev libdbus-1-dev meson python3-docutils furo python3-sphinx python3-sphinx-copybutton python3-sphinxext-opengraph
+
+      - name: Build site
+        run: |
+          meson setup --prefix /tmp/bluez-install --libdir lib -Dudev=disabled -Dauto_features=disabled -Dtools=disabled -Dclient=disabled -Ddaemon=disabled -Dmonitor=disabled -Ddeprecated=disabled -Dexperimental=disabled -Ddocumentation=enabled -Dlocalstatedir=/var _build
+          meson compile -C _build
+
+      - name: Upload Pages artifact
+        uses: actions/upload-pages-artifact@v3
+        with:
+          path: _build/doc/html/
+
+  deploy:
+    runs-on: ubuntu-latest
+    needs: build
+    environment:
+      name: github-pages
+      url: ${{ steps.deployment.outputs.page_url }}
+    steps:
+      - name: Deploy to GitHub Pages
+        id: deployment
+        uses: actions/deploy-pages@v4
-- 
2.54.0


^ permalink raw reply related

* [BlueZ v10 12/16] build: Only build gdbus library if there is a user
From: Bastien Nocera @ 2026-05-05  8:45 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <20260505085741.2497401-1-hadess@hadess.net>

---
 meson.build | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/meson.build b/meson.build
index d67abfe32430..e98e78d68e4c 100644
--- a/meson.build
+++ b/meson.build
@@ -265,7 +265,9 @@ configure_file(
 )
 
 subdir('lib')
-subdir('gdbus')
+if not get_option('tools').disabled() or get_option('client').enabled() or get_option('obex').enabled() or not get_option('tests').disabled() or not get_option('daemon').disabled()
+  subdir('gdbus')
+endif
 subdir('attrib')
 subdir('btio')
 subdir('plugins')
-- 
2.54.0


^ permalink raw reply related

* [BlueZ v10 10/16] unit: Make gobex-transfer tests run concurrently
From: Bastien Nocera @ 2026-05-05  8:45 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <20260505085741.2497401-1-hadess@hadess.net>

---
 unit/meson.build | 21 ++++++++++++++++++++-
 1 file changed, 20 insertions(+), 1 deletion(-)

diff --git a/unit/meson.build b/unit/meson.build
index 1bd3b7a85992..92e1c6f66caa 100644
--- a/unit/meson.build
+++ b/unit/meson.build
@@ -71,15 +71,18 @@ tests3 = [
   [ 'test-avctp.c', '../src/log.c', 'avctp.c' ],
   [ 'test-util.c' ],
 ]
+tests4 = []
 
 if ical_dep.found()
   tests3 += [
     [ 'test-gobex.c', 'util.c', gobex_sources ],
     [ 'test-gobex-packet.c', 'util.c', gobex_sources ],
     [ 'test-gobex-header.c', 'util.c', gobex_sources ],
-    [ 'test-gobex-transfer.c', 'util.c', gobex_sources ],
     [ 'test-gobex-apparam.c', 'util.c', gobex_sources ],
   ]
+  tests4 = [
+    [ 'test-gobex-transfer.c', 'util.c', gobex_sources ],
+  ]
 endif
 
 foreach t: tests3
@@ -93,6 +96,22 @@ foreach t: tests3
   test(test_name, exe)
 endforeach
 
+foreach t: tests4
+  test_name = t[0].substring(0, -2)
+  exe = executable(test_name,
+    sources: t,
+    c_args: [ '-DSTORAGEDIR="@0"'.format(storagedir) ],
+    include_directories: '../lib',
+    dependencies: libshared_glib_dep
+  )
+
+  r = run_command(sh, unittest_list, t, check: true)
+  unit_tests = r.stdout().strip().split(' ')
+  foreach ut: unit_tests
+    test(ut, exe, args: [ '-p', ut ])
+  endforeach
+endforeach
+
 exe = executable('test-gdbus-client',
   sources: 'test-gdbus-client.c',
   dependencies: [ libgdbus_internal_dep, libshared_glib_dep ]
-- 
2.54.0


^ permalink raw reply related

* [BlueZ v10 11/16] build: Only build profiles if the daemon is built
From: Bastien Nocera @ 2026-05-05  8:45 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <20260505085741.2497401-1-hadess@hadess.net>

---
 meson.build | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/meson.build b/meson.build
index 391cba6962bb..d67abfe32430 100644
--- a/meson.build
+++ b/meson.build
@@ -269,7 +269,9 @@ subdir('gdbus')
 subdir('attrib')
 subdir('btio')
 subdir('plugins')
-subdir('profiles')
+if get_option('daemon').enabled()
+  subdir('profiles')
+endif
 subdir('src')
 subdir('client')
 if get_option('monitor').allowed()
-- 
2.54.0


^ permalink raw reply related

* [BlueZ v10 08/16] build: Add option to allow disabling bluetoothd
From: Bastien Nocera @ 2026-05-05  8:45 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <20260505085741.2497401-1-hadess@hadess.net>

This makes it possible to build, for example, just the library, or the
command-line client, without also building and installing bluetoothd.
---
 doc/meson.build   |   3 +-
 meson.build       |   8 ++-
 meson_options.txt |   1 +
 src/meson.build   | 164 +++++++++++++++++++++++-----------------------
 4 files changed, 92 insertions(+), 84 deletions(-)

diff --git a/doc/meson.build b/doc/meson.build
index 3d5ccd7d3034..498b6a479067 100644
--- a/doc/meson.build
+++ b/doc/meson.build
@@ -146,7 +146,8 @@ bluetoothd_rst = configure_file(
   output: 'bluetoothd.rst',
   configuration: man_conf
 )
-if rst2man.found()
+
+if get_option('daemon').enabled() and rst2man.found()
   custom_target(
     input: bluetoothd_rst,
     output: 'bluetoothd.8',
diff --git a/meson.build b/meson.build
index 915dd32a37c6..c26dd5740488 100644
--- a/meson.build
+++ b/meson.build
@@ -299,8 +299,12 @@ endif
 # Fix permissions on install
 install = find_program('install')
 sh = find_program('sh')
-meson.add_install_script(sh, '-c', 'install -dm755 ${DESTDIR}/' + configdir)
-meson.add_install_script(sh, '-c', 'install -dm700 ${DESTDIR}/' + storagedir)
+if get_option('daemon').enabled()
+  meson.add_install_script(sh, '-c', 'install -dm755 ${DESTDIR}/' + configdir)
+endif
+if get_option('daemon').enabled() or get_option('mesh').enabled()
+  meson.add_install_script(sh, '-c', 'install -dm700 ${DESTDIR}/' + storagedir)
+endif
 if get_option('mesh').enabled()
   meson.add_install_script(sh, '-c', 'install -dm700 ${DESTDIR}/' + meshstoragedir)
 endif
diff --git a/meson_options.txt b/meson_options.txt
index 54cfdbb0d7c1..79e75e33ddaf 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -6,6 +6,7 @@ option('tests', type: 'feature', value: 'auto', description: 'Enable testing too
 option('tools', type: 'feature', value: 'enabled', description: 'Enable Bluetooth tools')
 option('monitor', type: 'feature', value: 'enabled', description: 'Enable Bluetooth monitor')
 option('client', type: 'feature', value: 'enabled', description: 'Enable command line client')
+option('daemon', type: 'feature', value: 'enabled', description: 'Enable bluetoothd daemon')
 option('systemd', type: 'feature', value: 'enabled', description: 'Install systemd service files')
 option('logind', type: 'feature', value: 'enabled', description: 'Enable logind integration in obexd')
 option('udev', type: 'feature', value: 'enabled', description: 'Enable udev device support in tools')
diff --git a/src/meson.build b/src/meson.build
index 65b7131c86b4..4962b782a7b6 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -1,88 +1,90 @@
 subdir('shared')
 
-if get_option('datafiles').allowed()
-  install_data('bluetooth.conf',
-    install_dir: dbusconfdir / 'dbus-1/system.d'
-  )
-  install_data('main.conf',
-    install_dir: configdir
-  )
-endif
+if get_option('daemon').allowed()
+  if get_option('datafiles').allowed()
+    install_data('bluetooth.conf',
+      install_dir: dbusconfdir / 'dbus-1/system.d'
+    )
+    install_data('main.conf',
+      install_dir: configdir
+    )
+  endif
 
-if systemd_dep.found()
-  configure_file(
-    input: 'bluetooth.service.in',
-    output: 'bluetooth.service',
-    install: true,
-    install_dir: systemdsystemunitdir,
-    configuration: service_conf
+  if systemd_dep.found()
+    configure_file(
+      input: 'bluetooth.service.in',
+      output: 'bluetooth.service',
+      install: true,
+      install_dir: systemdsystemunitdir,
+      configuration: service_conf
+    )
+
+    install_data('org.bluez.service',
+      install_dir: dbussystembusdir
+    )
+  endif
+
+  genbuiltin = find_program('genbuiltin')
+  builtin_h = custom_target('src-builtin.h',
+    output: 'builtin.h',
+    capture: true,
+    command: [ genbuiltin, builtin_modules ]
   )
 
-  install_data('org.bluez.service',
-    install_dir: dbussystembusdir
+  executable('bluetoothd',
+    sources: [ builtin_sources,
+      attrib_sources,
+      btio_sources,
+      builtin_h,
+      'main.c',
+      'log.c',
+      'backtrace.c',
+      'rfkill.c',
+      'sdpd-server.c',
+      'sdpd-request.c',
+      'sdpd-service.c',
+      'sdpd-database.c',
+      'gatt-database.c',
+      'sdp-xml.c',
+      'sdp-client.c',
+      'textfile.c',
+      'uuid-helper.c',
+      'plugin.c',
+      'storage.c',
+      'advertising.c',
+      'agent.c',
+      'bearer.c',
+      'error.c',
+      'adapter.c',
+      'profile.c',
+      'service.c',
+      'gatt-client.c',
+      'device.c',
+      'dbus-common.c',
+      'eir.c',
+      'adv_monitor.c',
+      'battery.c',
+      'settings.c',
+      'set.c' ],
+    dependencies: [
+      libbluetooth_internal_dep,
+      libgdbus_internal_dep,
+      libshared_glib_dep,
+      backtrace_dep,
+      glib_dep,
+      dbus_dep,
+      udevlib_dep,
+      builtin_deps
+    ],
+    override_options: [ 'b_lundef=false' ],
+    c_args: [
+      '-DBLUETOOTH_PLUGIN_BUILTIN',
+      '-DPLUGINDIR="@0@"'.format(plugindir),
+      '-DSTORAGEDIR="@0@"'.format(storagedir),
+      '-DCONFIGDIR="@0@"'.format(configdir)
+    ],
+    link_args: [ '-Wl,--gc-sections', external_plugins_link_args ],
+    install: true,
+    install_dir: pkglibexecdir
   )
 endif
-
-genbuiltin = find_program('genbuiltin')
-builtin_h = custom_target('src-builtin.h',
-  output: 'builtin.h',
-  capture: true,
-  command: [ genbuiltin, builtin_modules ]
-)
-
-executable('bluetoothd',
-  sources: [ builtin_sources,
-    attrib_sources,
-    btio_sources,
-    builtin_h,
-    'main.c',
-    'log.c',
-    'backtrace.c',
-    'rfkill.c',
-    'sdpd-server.c',
-    'sdpd-request.c',
-    'sdpd-service.c',
-    'sdpd-database.c',
-    'gatt-database.c',
-    'sdp-xml.c',
-    'sdp-client.c',
-    'textfile.c',
-    'uuid-helper.c',
-    'plugin.c',
-    'storage.c',
-    'advertising.c',
-    'agent.c',
-    'bearer.c',
-    'error.c',
-    'adapter.c',
-    'profile.c',
-    'service.c',
-    'gatt-client.c',
-    'device.c',
-    'dbus-common.c',
-    'eir.c',
-    'adv_monitor.c',
-    'battery.c',
-    'settings.c',
-    'set.c' ],
-  dependencies: [
-    libbluetooth_internal_dep,
-    libgdbus_internal_dep,
-    libshared_glib_dep,
-    backtrace_dep,
-    glib_dep,
-    dbus_dep,
-    udevlib_dep,
-    builtin_deps
-  ],
-  override_options: [ 'b_lundef=false' ],
-  c_args: [
-    '-DBLUETOOTH_PLUGIN_BUILTIN',
-    '-DPLUGINDIR="@0@"'.format(plugindir),
-    '-DSTORAGEDIR="@0@"'.format(storagedir),
-    '-DCONFIGDIR="@0@"'.format(configdir)
-  ],
-  link_args: [ '-Wl,--gc-sections', external_plugins_link_args ],
-  install: true,
-  install_dir: pkglibexecdir
-)
-- 
2.54.0


^ permalink raw reply related

* [BlueZ v10 09/16] unit: Run test-bap tests concurrently
From: Bastien Nocera @ 2026-05-05  8:45 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <20260505085741.2497401-1-hadess@hadess.net>

---
 meson.build           |  2 +-
 unit/meson.build      | 25 ++++++++++++++++++++++---
 unit/unittest_list.sh | 15 +++++++++++++++
 3 files changed, 38 insertions(+), 4 deletions(-)
 create mode 100644 unit/unittest_list.sh

diff --git a/meson.build b/meson.build
index c26dd5740488..391cba6962bb 100644
--- a/meson.build
+++ b/meson.build
@@ -291,6 +291,7 @@ endif
 if rst2man.found()
   subdir('doc')
 endif
+sh = find_program('sh', required: true)
 if get_option('tests').allowed()
   subdir('test')
   subdir('unit')
@@ -298,7 +299,6 @@ endif
 
 # Fix permissions on install
 install = find_program('install')
-sh = find_program('sh')
 if get_option('daemon').enabled()
   meson.add_install_script(sh, '-c', 'install -dm755 ${DESTDIR}/' + configdir)
 endif
diff --git a/unit/meson.build b/unit/meson.build
index c8198574147d..1bd3b7a85992 100644
--- a/unit/meson.build
+++ b/unit/meson.build
@@ -7,7 +7,6 @@ tests1 = [
   [ 'test-avrcp.c', '../src/log.c', 'avctp.c', 'avrcp-lib.c' ],
   [ 'test-lib.c' ],
   [ 'test-gatt.c' ],
-  [ 'test-bap.c' ],
   [ 'test-micp.c' ],
   [ 'test-bass.c' ],
   [ 'test-vcp.c' ],
@@ -39,6 +38,26 @@ foreach t: tests1
 endforeach
 
 tests2 = [
+  [ 'test-bap.c' ],
+]
+
+unittest_list = find_program('unittest_list.sh')
+
+foreach t: tests2
+  test_name = t[0].substring(0, -2)
+  exe = executable(test_name,
+    sources: t,
+    dependencies: [ libshared_glib_dep, libbluetooth_internal_dep ],
+  )
+
+  r = run_command(sh, unittest_list, t, check: true)
+  unit_tests = r.stdout().strip().split(' ')
+  foreach ut: unit_tests
+    test(ut, exe, args: [ '-p', ut ])
+  endforeach
+endforeach
+
+tests3 = [
   [ 'test-textfile.c', '../src/textfile.c' ],
   [ 'test-crc.c', '../monitor/crc.c' ],
   [ 'test-crypto.c' ],
@@ -54,7 +73,7 @@ tests2 = [
 ]
 
 if ical_dep.found()
-  tests2 += [
+  tests3 += [
     [ 'test-gobex.c', 'util.c', gobex_sources ],
     [ 'test-gobex-packet.c', 'util.c', gobex_sources ],
     [ 'test-gobex-header.c', 'util.c', gobex_sources ],
@@ -63,7 +82,7 @@ if ical_dep.found()
   ]
 endif
 
-foreach t: tests2
+foreach t: tests3
   test_name = t[0].substring(0, -2)
   exe = executable(test_name,
     sources: t,
diff --git a/unit/unittest_list.sh b/unit/unittest_list.sh
new file mode 100644
index 000000000000..c478edc9d3e4
--- /dev/null
+++ b/unit/unittest_list.sh
@@ -0,0 +1,15 @@
+#!/bin/sh
+
+if [ $# -lt 1 ] ; then
+	echo "Usage: $0 FILE..."
+	exit 1
+fi
+
+TESTS=$(grep '^[[:space:]]*define_test[_a-z]*("' $* | cut -d \" -f 2 | cut -d " " -f 1)
+if [ -z "$TESTS" ] ; then
+	TESTS=$(grep '^[[:space:]]*tester_add("' $* | cut -d \" -f 2 | cut -d " " -f 1)
+fi
+if [ -z "$TESTS" ] ; then
+	TESTS=$(grep '^[[:space:]]*g_test_add_*func("' $* | cut -d \" -f 2 | cut -d " " -f 1)
+fi
+echo $TESTS
-- 
2.54.0


^ permalink raw reply related

* [BlueZ v10 04/16] build: Separate systemd and libsystemd dependencies
From: Bastien Nocera @ 2026-05-05  8:45 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <20260505085741.2497401-1-hadess@hadess.net>

One is to install systemd service files, the other to enable deeper
logind integration into obexd.
---
 meson.build       | 3 ++-
 meson_options.txt | 3 ++-
 2 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/meson.build b/meson.build
index 15508a868636..915dd32a37c6 100644
--- a/meson.build
+++ b/meson.build
@@ -144,7 +144,8 @@ readline_dep = dependency('readline',
   required: get_option('client').enabled() or
     get_option('mesh').enabled())
 systemd_dep = dependency('systemd', required: get_option('systemd'))
-libsystemd_dep = dependency('libsystemd', required: get_option('systemd'))
+libsystemd_dep = dependency('libsystemd',
+  required: get_option('obex').enabled() and get_option('logind').enabled())
 
 ell_args = {
   'version': '>= 0.39',
diff --git a/meson_options.txt b/meson_options.txt
index 4a0c726c2098..54cfdbb0d7c1 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -6,7 +6,8 @@ option('tests', type: 'feature', value: 'auto', description: 'Enable testing too
 option('tools', type: 'feature', value: 'enabled', description: 'Enable Bluetooth tools')
 option('monitor', type: 'feature', value: 'enabled', description: 'Enable Bluetooth monitor')
 option('client', type: 'feature', value: 'enabled', description: 'Enable command line client')
-option('systemd', type: 'feature', value: 'enabled', description: 'Enable systemd integration')
+option('systemd', type: 'feature', value: 'enabled', description: 'Install systemd service files')
+option('logind', type: 'feature', value: 'enabled', description: 'Enable logind integration in obexd')
 option('udev', type: 'feature', value: 'enabled', description: 'Enable udev device support in tools')
 option('datafiles', type: 'feature', value: 'enabled', description: 'Install configuration and data files')
 option('manpages', type: 'feature', value: 'auto', description: 'Enable building of manual pages')
-- 
2.54.0


^ permalink raw reply related

* [BlueZ v10 06/16] tools: Install avinfo tool by default
From: Bastien Nocera @ 2026-05-05  8:45 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <20260505085741.2497401-1-hadess@hadess.net>

It's used for checking which audio codecs are supported by a Bluetooth
audio device, which is more useful now that PulseAudio/PipeWire support
alternative codecs like LDAC or aptX).

Fixes:
https://bugzilla.redhat.com/show_bug.cgi?id=1699680
---
 tools/meson.build | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/tools/meson.build b/tools/meson.build
index 5f092e7e1b5c..1c2595a31f77 100644
--- a/tools/meson.build
+++ b/tools/meson.build
@@ -61,7 +61,6 @@ if udevlib_hid2hci_dep.found()
 endif
 
 tools_names = [
-  'avinfo',
   'avtest',
   'scotest',
   'hwdb',
@@ -82,6 +81,7 @@ tools_names = [
 ]
 
 inst_tools_names = [
+  'avinfo',
   'rctest',
   'l2test',
   'l2ping',
-- 
2.54.0


^ permalink raw reply related

* [BlueZ v10 07/16] emulator: Install the emulator if built
From: Bastien Nocera @ 2026-05-05  8:45 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <20260505085741.2497401-1-hadess@hadess.net>

It's useful for testing.
---
 emulator/meson.build | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/emulator/meson.build b/emulator/meson.build
index 40544567e4e4..5ed734c5d69d 100644
--- a/emulator/meson.build
+++ b/emulator/meson.build
@@ -17,7 +17,9 @@ if get_option('tests').allowed()
       'smp.c',
       'phy.c',
       'le.c' ],
-    dependencies: [ libbluetooth_internal_dep, libshared_mainloop_dep ]
+    dependencies: [ libbluetooth_internal_dep, libshared_mainloop_dep ],
+    install: true,
+    install_dir: pkglibexecdir
   )
 
   executable('b1ee',
-- 
2.54.0


^ permalink raw reply related

* [BlueZ v10 05/16] tools: Install gatttool if deprecated tools are enabled
From: Bastien Nocera @ 2026-05-05  8:45 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <20260505085741.2497401-1-hadess@hadess.net>

Fixes:
https://bugzilla.redhat.com/show_bug.cgi?id=1141909
https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=720486
---
 tools/meson.build | 1 +
 1 file changed, 1 insertion(+)

diff --git a/tools/meson.build b/tools/meson.build
index 8fc0dc1d2fb5..5f092e7e1b5c 100644
--- a/tools/meson.build
+++ b/tools/meson.build
@@ -204,6 +204,7 @@ if get_option('tools').allowed()
     executable('gatttool',
       sources: gatttool_sources,
       dependencies: [ libbluetooth_internal_dep, libshared_glib_dep, readline_dep ],
+      install: true
     )
     executable('hciattach',
       sources: [
-- 
2.54.0


^ permalink raw reply related

* [BlueZ v10 02/16] build: Add meson build system
From: Bastien Nocera @ 2026-05-05  8:45 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <20260505085741.2497401-1-hadess@hadess.net>

The options default were selected to try and match the existing
autotools default as best as possible. Further commits will likely
change those defaults, but at least it should be clear what defaults
were changed from.

However, a number of options were removed:

--enable-pie is replaced by the meson base option "b_pie":
https://mesonbuild.com/Builtin-options.html#base-options

--enable-maintainer-mode is replaced by the "debug" build-types:
https://mesonbuild.com/Builtin-options.html#core-options

--enable-debug and --disable-optimization are replaced by the
debug build type:
https://mesonbuild.com/Builtin-options.html#details-for-buildtype

Each of the sanitisers have their own b_sanitize option:
- asan: b_sanitize=address
- lsan: b_sanitize=leak
- ubsan: b_sanitize=address,undefined
https://mesonbuild.com/Builtin-options.html#base-options

--enable-coverage is replaced by the b_coverage option:
https://mesonbuild.com/Builtin-options.html#base-options

--enable-valgrind can be replicated by running the test suite with:
meson test --setup valgrind
---
 attrib/meson.build           |  17 ++
 btio/meson.build             |   1 +
 client/btpclient/meson.build |  20 +++
 client/meson.build           |  33 ++++
 completion/meson.build       |   3 +
 doc/meson.build              | 172 ++++++++++++++++++++
 emulator/meson.build         |  34 ++++
 gdbus/meson.build            |  19 +++
 gobex/meson.build            |   8 +
 lib/meson.build              |  53 +++++++
 mesh/meson.build             |  60 +++++++
 meson.build                  | 299 +++++++++++++++++++++++++++++++++++
 meson_options.txt            |  52 ++++++
 monitor/meson.build          |  37 +++++
 obexd/meson.build            | 121 ++++++++++++++
 peripheral/meson.build       |  13 ++
 plugins/meson.build          |  29 ++++
 profiles/meson.build         | 168 ++++++++++++++++++++
 src/meson.build              |  88 +++++++++++
 src/shared/meson.build       |  85 ++++++++++
 test/meson.build             |  37 +++++
 tools/mesh/meson.build       |  16 ++
 tools/meson.build            | 261 ++++++++++++++++++++++++++++++
 tools/mpris-proxy.service.in |   2 +-
 unit/meson.build             | 126 +++++++++++++++
 25 files changed, 1753 insertions(+), 1 deletion(-)
 create mode 100644 attrib/meson.build
 create mode 100644 btio/meson.build
 create mode 100644 client/btpclient/meson.build
 create mode 100644 client/meson.build
 create mode 100644 completion/meson.build
 create mode 100644 doc/meson.build
 create mode 100644 emulator/meson.build
 create mode 100644 gdbus/meson.build
 create mode 100644 gobex/meson.build
 create mode 100644 lib/meson.build
 create mode 100644 mesh/meson.build
 create mode 100644 meson.build
 create mode 100644 meson_options.txt
 create mode 100644 monitor/meson.build
 create mode 100644 obexd/meson.build
 create mode 100644 peripheral/meson.build
 create mode 100644 plugins/meson.build
 create mode 100644 profiles/meson.build
 create mode 100644 src/meson.build
 create mode 100644 src/shared/meson.build
 create mode 100644 test/meson.build
 create mode 100644 tools/mesh/meson.build
 create mode 100644 tools/meson.build
 create mode 100644 unit/meson.build

diff --git a/attrib/meson.build b/attrib/meson.build
new file mode 100644
index 000000000000..0b7bc97933db
--- /dev/null
+++ b/attrib/meson.build
@@ -0,0 +1,17 @@
+attrib_sources = files(
+  'att.c',
+  'gatt.c',
+  'gattrib.c'
+)
+
+gatttool_sources = files(
+  'gatttool.c',
+  'att.c',
+  'gatt.c',
+  'gattrib.c',
+  'interactive.c',
+  'utils.c',
+  '../client/display.c',
+  '../btio/btio.c',
+  '../src/log.c'
+)
diff --git a/btio/meson.build b/btio/meson.build
new file mode 100644
index 000000000000..46ae5691f1d8
--- /dev/null
+++ b/btio/meson.build
@@ -0,0 +1 @@
+btio_sources = files('btio.c')
diff --git a/client/btpclient/meson.build b/client/btpclient/meson.build
new file mode 100644
index 000000000000..c2cab2734659
--- /dev/null
+++ b/client/btpclient/meson.build
@@ -0,0 +1,20 @@
+executable('btpclient',
+  sources: [
+    'btpclient.c',
+    'core.c',
+    'bap.c',
+    'gap.c',
+    'gatt.c',
+    '../../src/shared/btp.c' ],
+  include_directories: '..',
+  dependencies: [ libbluetooth_internal_dep, libshared_ell_dep ],
+)
+executable('btpclientctl',
+  sources: [ 'btpclientctl.c', '../../client/display.c' ],
+  dependencies: [
+    libshared_mainloop_dep,
+    libshared_glib_dep,
+    libbluetooth_internal_dep,
+    readline_dep
+  ]
+)
diff --git a/client/meson.build b/client/meson.build
new file mode 100644
index 000000000000..a7642d13fd8b
--- /dev/null
+++ b/client/meson.build
@@ -0,0 +1,33 @@
+if get_option('client').enabled()
+  executable('bluetoothctl',
+    sources: [
+      'main.c',
+      'print.c',
+      'display.c',
+      'agent.c',
+      'advertising.c',
+      'adv_monitor.c',
+      'gatt.c',
+      'admin.c',
+      'player.c',
+      'mgmt.c',
+      'assistant.c',
+      'hci.c',
+      'telephony.c'
+      ],
+    dependencies: [
+      libbluetooth_internal_dep,
+      libgdbus_internal_dep,
+      libshared_glib_dep,
+      glib_dep,
+      udevlib_dep,
+      dbus_dep,
+      readline_dep
+      ],
+    install: true,
+  )
+endif
+
+if get_option('btpclient').allowed() and ell_dep.found()
+  subdir('btpclient')
+endif
diff --git a/completion/meson.build b/completion/meson.build
new file mode 100644
index 000000000000..24b71518c67d
--- /dev/null
+++ b/completion/meson.build
@@ -0,0 +1,3 @@
+install_data('zsh/_bluetoothctl',
+  install_dir: zshcompletiondir
+)
diff --git a/doc/meson.build b/doc/meson.build
new file mode 100644
index 000000000000..3d5ccd7d3034
--- /dev/null
+++ b/doc/meson.build
@@ -0,0 +1,172 @@
+man_pages = [
+  'hci.7',
+  'iso.7',
+  'mgmt.7',
+  'l2cap.7',
+  'rfcomm.7',
+  'sco.7',
+  'btsnoop.7',
+  'org.bluez.Adapter.5',
+  'org.bluez.Bearer.LE.5',
+  'org.bluez.Bearer.BREDR.5',
+  'org.bluez.Device.5',
+  'org.bluez.DeviceSet.5',
+  'org.bluez.AgentManager.5',
+  'org.bluez.Agent.5',
+  'org.bluez.ProfileManager.5',
+  'org.bluez.Profile.5',
+  'org.bluez.NetworkServer.5',
+  'org.bluez.Network.5',
+  'org.bluez.Input.5',
+  'org.bluez.BatteryProviderManager.5',
+  'org.bluez.BatteryProvider.5',
+  'org.bluez.Battery.5',
+  'org.bluez.AdminPolicySet.5',
+  'org.bluez.AdminPolicyStatus.5',
+  'org.bluez.Media.5',
+  'org.bluez.MediaControl.5',
+  'org.bluez.MediaPlayer.5',
+  'org.bluez.MediaFolder.5',
+  'org.bluez.MediaItem.5',
+  'org.bluez.MediaEndpoint.5',
+  'org.bluez.MediaTransport.5',
+  'org.bluez.MediaAssistant.5',
+  'org.bluez.GattManager.5',
+  'org.bluez.GattProfile.5',
+  'org.bluez.GattService.5',
+  'org.bluez.GattCharacteristic.5',
+  'org.bluez.GattDescriptor.5',
+  'org.bluez.LEAdvertisingManager.5',
+  'org.bluez.LEAdvertisement.5',
+  'org.bluez.AdvertisementMonitorManager.5',
+  'org.bluez.AdvertisementMonitor.5',
+  'org.bluez.Telephony.5',
+  'org.bluez.Call.5',
+]
+
+obex_man_pages = [
+  'org.bluez.obex.Client.5',
+  'org.bluez.obex.Session.5',
+  'org.bluez.obex.Transfer.5',
+  'org.bluez.obex.ObjectPush.5',
+  'org.bluez.obex.FileTransfer.5',
+  'org.bluez.obex.Synchronization.5',
+  'org.bluez.obex.PhonebookAccess.5',
+  'org.bluez.obex.MessageAccess.5',
+  'org.bluez.obex.Message.5',
+  'org.bluez.obex.AgentManager.5',
+  'org.bluez.obex.Agent.5',
+  'org.bluez.obex.Image.5',
+]
+
+if get_option('obex').enabled()
+  man_pages += obex_man_pages
+endif
+
+monitor_man_pages = [ 'btmon.1' ]
+
+if get_option('monitor').allowed()
+  man_pages += monitor_man_pages
+endif
+
+tools_man_pages = [
+  'rctest.1',
+  'l2ping.1',
+  'btattach.1',
+  'isotest.1',
+  'bdaddr.1',
+]
+
+noinst_tools_man_pages = [ 'btmgmt.1' ]
+
+if get_option('tools').allowed()
+  man_pages += tools_man_pages
+  man_pages += noinst_tools_man_pages
+endif
+
+deprecated_tools_man_pages = [
+  'hciattach.1',
+  'hciconfig.1',
+  'hcitool.1',
+  'rfcomm.1',
+  'sdptool.1',
+  'ciptool.1',
+]
+
+if get_option('deprecated').allowed()
+  man_pages += deprecated_tools_man_pages
+endif
+
+hid2hci_man_pages = [ 'hid2hci.1' ]
+
+if get_option('hid2hci').enabled()
+  man_pages += 'hid2hci.1'
+endif
+
+client_man_pages = [
+  'bluetoothctl.1',
+  'bluetoothctl-mgmt.1',
+  'bluetoothctl-monitor.1',
+  'bluetoothctl-admin.1',
+  'bluetoothctl-advertise.1',
+  'bluetoothctl-endpoint.1',
+  'bluetoothctl-gatt.1',
+  'bluetoothctl-player.1',
+  'bluetoothctl-scan.1',
+  'bluetoothctl-transport.1',
+  'bluetoothctl-assistant.1',
+  'bluetoothctl-hci.1',
+  'bluetoothctl-telephony.1'
+]
+
+if get_option('client').enabled()
+  man_pages += client_man_pages
+endif
+
+if rst2man.found()
+  foreach man_page: man_pages
+    man_page_name = man_page.substring(0, -2)
+    man_section = man_page.substring(-1)
+    if man_section.to_int() == 7
+      man_page_name = man_page_name + '-protocol'
+    endif
+    install = not noinst_tools_man_pages.contains(man_page)
+    custom_target(man_page,
+      input: man_page_name + '.rst',
+      output: man_page,
+      command: rst2man_command,
+      install: install,
+      install_dir: get_option('mandir') / 'man@0@'.format(man_section)
+    )
+  endforeach
+endif
+
+bluetoothd_rst = configure_file(
+  input: 'bluetoothd.rst.in',
+  output: 'bluetoothd.rst',
+  configuration: man_conf
+)
+if rst2man.found()
+  custom_target(
+    input: bluetoothd_rst,
+    output: 'bluetoothd.8',
+    command: rst2man_command,
+    install: true,
+    install_dir: get_option('mandir') / 'man8'
+  )
+endif
+
+bluetooth_meshd_rst = configure_file(
+  input: 'bluetooth-meshd.rst.in',
+  output: 'bluetooth-meshd.rst',
+  configuration: man_conf
+)
+if get_option('mesh').enabled() and rst2man.found()
+  custom_target(
+    input: bluetooth_meshd_rst,
+    output: 'bluetooth-meshd.8',
+    command: rst2man_command,
+    install: true,
+    install_dir: get_option('mandir') / 'man8'
+  )
+endif
diff --git a/emulator/meson.build b/emulator/meson.build
new file mode 100644
index 000000000000..40544567e4e4
--- /dev/null
+++ b/emulator/meson.build
@@ -0,0 +1,34 @@
+emulator_sources = files(
+  'hciemu.c',
+  'vhci.c',
+  'btdev.c',
+  'bthost.c',
+  'smp.c',
+)
+
+if get_option('tests').allowed()
+  executable('btvirt',
+    sources: [ 'main.c',
+      'serial.c',
+      'server.c',
+      'vhci.c',
+      'btdev.c',
+      'bthost.c',
+      'smp.c',
+      'phy.c',
+      'le.c' ],
+    dependencies: [ libbluetooth_internal_dep, libshared_mainloop_dep ]
+  )
+
+  executable('b1ee',
+    sources: 'b1ee.c',
+    include_directories: '../lib',
+    dependencies: libshared_mainloop_dep
+  )
+
+  executable('hfp',
+    sources: 'hfp.c',
+    dependencies: libshared_mainloop_dep
+  )
+endif
+
diff --git a/gdbus/meson.build b/gdbus/meson.build
new file mode 100644
index 000000000000..dc7f2887a60f
--- /dev/null
+++ b/gdbus/meson.build
@@ -0,0 +1,19 @@
+gdbus_sources = [
+  'gdbus.h',
+  'mainloop.c',
+  'watch.c',
+  'object.c',
+  'client.c',
+  'polkit.c'
+]
+
+libgdbus_internal = static_library('gdbus_internal',
+  sources: gdbus_sources,
+  dependencies: [ glib_dep, dbus_dep ],
+  install: false
+)
+
+libgdbus_internal_dep = declare_dependency(
+  dependencies: dbus_dep,
+  link_with: libgdbus_internal
+)
diff --git a/gobex/meson.build b/gobex/meson.build
new file mode 100644
index 000000000000..0ff6238a7b8c
--- /dev/null
+++ b/gobex/meson.build
@@ -0,0 +1,8 @@
+gobex_sources = files(
+  'gobex.c',
+  'gobex-defs.c',
+  'gobex-packet.c',
+  'gobex-header.c',
+  'gobex-transfer.c',
+  'gobex-apparam.c'
+)
diff --git a/lib/meson.build b/lib/meson.build
new file mode 100644
index 000000000000..e8d11f342bd8
--- /dev/null
+++ b/lib/meson.build
@@ -0,0 +1,53 @@
+lib_sources = [
+  'bluetooth/bluetooth.c',
+  'bluetooth/hci.c',
+  'bluetooth/sdp.c',
+]
+
+lib_extra_sources = [
+  'bluetooth/uuid.c'
+]
+
+lib_headers = [
+  'bluetooth/bluetooth.h',
+  'bluetooth/hci.h',
+  'bluetooth/hci_lib.h',
+  'bluetooth/sco.h',
+  'bluetooth/l2cap.h',
+  'bluetooth/sdp.h',
+  'bluetooth/sdp_lib.h',
+  'bluetooth/rfcomm.h',
+  'bluetooth/bnep.h',
+  'bluetooth/cmtp.h',
+  'bluetooth/hidp.h'
+  ]
+
+if get_option('library').allowed()
+  lib_bluetooth = shared_library('bluetooth',
+    sources: lib_headers + lib_sources,
+    version: '3.19.15',
+    install: true
+  )
+
+  install_headers(lib_headers,
+    subdir: 'bluetooth'
+  )
+
+  pkgconfig = import('pkgconfig')
+  pkgconfig.generate(
+    name: 'bluez',
+    description: 'Bluetooth protocol stack for Linux',
+    version: meson.project_version(),
+    libraries: lib_bluetooth,
+  )
+endif
+
+libbluetooth_internal = static_library('bluetooth_internal',
+  sources: lib_headers + lib_sources + lib_extra_sources,
+  install: false
+)
+
+libbluetooth_internal_dep = declare_dependency(
+  link_with: libbluetooth_internal,
+  include_directories: '.'
+)
diff --git a/mesh/meson.build b/mesh/meson.build
new file mode 100644
index 000000000000..cb4c9012300d
--- /dev/null
+++ b/mesh/meson.build
@@ -0,0 +1,60 @@
+if get_option('datafiles').allowed()
+  install_data('bluetooth-mesh.conf',
+    install_dir: dbusdir)
+  install_data('mesh-main.conf',
+    install_dir: configdir)
+endif
+
+if systemd_dep.found()
+  configure_file(
+    input: 'bluetooth-mesh.service.in',
+    output: 'bluetooth-mesh.service',
+    install: true,
+    install_dir: systemdsystemunitdir,
+    configuration: service_conf
+  )
+  install_data('org.bluez.mesh.service',
+    install_dir: dbussystembusdir
+  )
+endif
+
+executable('bluetooth-meshd',
+  sources: [
+    builtin_h,
+    'main.c',
+    'mesh.c',
+    'net-keys.c',
+    'mesh-io.c',
+    'mesh-mgmt.c',
+    'mesh-io-unit.c',
+    'mesh-io-mgmt.c',
+    'mesh-io-generic.c',
+    'net.c',
+    'crypto.c',
+    'friend.c',
+    'appkey.c',
+    'node.c',
+    'model.c',
+    'cfgmod-server.c',
+    'remprv-server.c',
+    'mesh-config-json.c',
+    'util.c',
+    'dbus.c',
+    'agent.c',
+    'prov-acceptor.c',
+    'prov-initiator.c',
+    'manager.c',
+    'pb-adv.c',
+    'keyring.c',
+    'rpl.c',
+    'prvbeac-server.c'
+  ],
+  include_directories: '../lib',
+  dependencies: [ libshared_ell_dep, jsonc_dep ],
+  c_args: [
+    '-DCONFIGDIR="@0@"'.format(configdir),
+    '-DMESH_STORAGEDIR="@0@"'.format(meshstoragedir)
+  ],
+  install: true,
+  install_dir: pkglibexecdir
+)
diff --git a/meson.build b/meson.build
new file mode 100644
index 000000000000..d3c43d79141f
--- /dev/null
+++ b/meson.build
@@ -0,0 +1,299 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+project(
+  'bluez', 'c',
+  version: '5.86',
+  license: 'LGPL-2.1-or-later AND GPL-2.0-or-later',
+  meson_version: '>= 1.3.0'
+)
+
+datadir = get_option('datadir')
+storagedir = '/' / get_option('localstatedir') / 'lib/bluetooth'
+configdir = get_option('sysconfdir') / 'bluetooth'
+pkglibdir = get_option('libdir') / 'bluetooth'
+pkglibexecdir = get_option('libexecdir') / 'bluetooth'
+meshstoragedir = storagedir / 'mesh'
+
+fs = import('fs')
+service_conf = configuration_data()
+if not fs.is_absolute(pkglibexecdir)
+  pkglibexecdir = get_option('prefix') / pkglibexecdir
+endif
+service_conf.set('PKGLIBEXECDIR', pkglibexecdir)
+
+add_project_arguments('-DHAVE_CONFIG_H', language: 'c')
+config_h = configuration_data()
+
+cc = meson.get_compiler('c')
+
+required_funcs = [
+  'explicit_bzero',
+  'getrandom',
+  'rawmemchr',
+  'signalfd',
+]
+
+foreach func: required_funcs
+  cc.has_function(func, required: true)
+endforeach
+
+required_lib_funcs = [
+  [ 'clock_gettime', 'rt' ],
+  [ 'pthread_create', 'pthread' ],
+  [ 'dlopen', 'dl' ]
+]
+
+foreach func: required_lib_funcs
+  dep = cc.find_library(func[1], required: true)
+  cc.has_function(func[0], dependencies: dep, required: true)
+endforeach
+
+required_headers = [
+  'stdarg.h',
+  'stdio.h',
+  'string.h',
+  'linux/types.h',
+  'linux/if_alg.h',
+  'linux/uinput.h',
+  'linux/uhid.h',
+  'sys/random.h'
+]
+
+foreach header: required_headers
+  cc.has_header(header, required: true)
+endforeach
+
+# basename may be only available in libgen.h with the POSIX behavior,
+# not desired here
+config_h.set10('HAVE_DECL_BASENAME',
+  cc.has_function('basename', prefix: '#define _GNU_SOURCE 1\n#include <string.h>'))
+
+# To combine with -Wl,--gc-sections
+add_project_arguments([ '-ffunction-sections', '-fdata-sections' ] , language: 'c')
+
+# Maintainer mode
+if get_option('buildtype').contains('debug')
+  test_cflags = [
+    '-Wno-unused-parameter',
+    '-Wno-missing-field-initializers',
+    '-Wdeclaration-after-statement',
+    '-Wmissing-declarations',
+    '-Wredundant-decls',
+    '-Wcast-align',
+    '-Wswitch-enum',
+    '-Wformat',
+    '-Wformat-security',
+    '-Wstringop-overflow',
+  ]
+
+  if get_option('buildtype') == 'debugoptimized'
+    test_cflags += '-D_FORTIFY_SOURCE=3'
+  endif
+
+  common_flags = [
+    '-DG_DISABLE_DEPRECATED',
+    '-DGLIB_VERSION_MIN_REQUIRED=GLIB_VERSION_2_36',
+    '-DGLIB_VERSION_MAX_ALLOWED=GLIB_VERSION_2_36'
+  ]
+
+  common_flags += cc.get_supported_arguments(test_cflags)
+
+  add_project_arguments(common_flags, language: 'c')
+
+  config_h.set('HAVE_VALGRIND_MEMCHECK_H',
+    cc.has_header('valgrind/memcheck.h', required: get_option('valgrind')))
+endif
+
+test_cflags = [
+  '-ffunction-sections',
+  '-fdata-sections'
+]
+
+add_project_arguments(cc.get_supported_arguments(test_cflags), language: 'c')
+add_project_arguments('-I' + meson.project_build_root(), language: 'c')
+add_project_arguments('-I' + meson.project_source_root(), language: 'c')
+add_project_link_arguments('-Wl,--gc-sections', language: 'c')
+
+dummy_dep = dependency('dummy', required: false)
+glib_dep = dependency('glib-2.0', version: '>= 2.36')
+dbus_dep = dependency('dbus-1', version:'>= 1.10')
+
+cc.check_header('elfutils/libdwfl.h', required: get_option('backtrace'))
+backtrace_dep = cc.find_library('dw', required: get_option('backtrace'))
+config_h.set('HAVE_BACKTRACE_SUPPORT', backtrace_dep.found())
+
+config_h.set10('HAVE_DECL_SOF_TIMESTAMPING_TX_COMPLETION',
+  cc.has_header_symbol('linux/net_tstamp.h', 'SOF_TIMESTAMPING_TX_COMPLETION'))
+config_h.set10('HAVE_DECL_SCM_TSTAMP_COMPLETION',
+  cc.has_header_symbol('linux/errqueue.h', 'SCM_TSTAMP_COMPLETION', prefix: '#include <time.h>'))
+
+udevlib_dep = dependency('libudev', required: get_option('udev'))
+udevlib_sixaxis_dep = dependency('libudev', required: get_option('sixaxis'))
+udevlib_hid2hci_dep = dependency('libudev', required: get_option('hid2hci'))
+
+cups_dep = dependency('cups', required: get_option('cups'))
+jsonc_dep = dependency('json-c', version: '>= 0.13', required: get_option('mesh'))
+alsa_dep = dependency('alsa', required: get_option('midi'))
+ical_dep = dependency('libical', required: get_option('obex'))
+readline_dep = dependency('readline',
+  required: get_option('client').enabled() or
+    get_option('mesh').enabled())
+systemd_dep = dependency('systemd', required: get_option('systemd'))
+libsystemd_dep = dependency('libsystemd', required: get_option('systemd'))
+
+ell_args = {
+  'version': '>= 0.39',
+  'fallback' : ['ell', 'libell_dep'],
+  'default_options': [
+    'default_library=static',
+    'tests=false',
+    'cert-tests=false'
+  ]
+}
+ell_dep = dependency('ell',
+  kwargs: ell_args,
+  required: get_option('btpclient')
+)
+ell_mesh_dep = dependency('ell',
+  kwargs: ell_args,
+  required: get_option('mesh')
+)
+
+rst2man = find_program('rst2man', 'rst2man.py', required: get_option('manpages'))
+if rst2man.found()
+  rst2man_command = [
+    rst2man,
+    '--strict',
+    '--no-raw',
+    '--no-generator',
+    '--no-datestamp',
+    '@INPUT@',
+    '@OUTPUT@'
+  ]
+endif
+
+man_conf = configuration_data()
+man_conf.set('CONFIGDIR', get_option('prefix') / configdir)
+man_conf.set('MESH_STORAGEDIR', get_option('prefix') / meshstoragedir)
+
+if get_option('phonebook') == 'ebook'
+  ebook_dep = dependency('libebook-1.2', '>= 3.3', required: true)
+  edataserver_dep = dependency('libedataserver-1.2', '>= 3.3', required: true)
+else
+  ebook_dep = dummy_dep
+  edataserver_dep = dummy_dep
+endif
+
+plugindir = get_option('libdir') / 'bluetooth/plugins'
+
+dbusconfdir = get_option('dbusconfdir')
+if dbusconfdir == ''
+  dbusconfdir = dbus_dep.get_variable('datadir')
+endif
+dbusdir = dbusconfdir / 'dbus-1/system.d'
+
+dbussystembusdir = get_option('dbussystembusdir')
+if dbussystembusdir == ''
+  dbussystembusdir = dbus_dep.get_variable('system_bus_services_dir')
+endif
+
+dbussessionbusdir = get_option('dbussessionbusdir')
+if dbussessionbusdir == ''
+  dbussessionbusdir = dbus_dep.get_variable('session_bus_services_dir')
+endif
+
+service_in = configuration_data()
+service_in.set_quoted('PKGLIBEXECDIR', get_option('prefix') / pkglibexecdir)
+
+if systemd_dep.found()
+  systemdsystemunitdir = get_option('systemdsystemunitdir')
+  if systemdsystemunitdir == ''
+    systemdsystemunitdir = systemd_dep.get_variable('systemdsystemunitdir')
+  endif
+  systemduserunitdir = get_option('systemduserunitdir')
+  if systemduserunitdir == ''
+    systemduserunitdir = systemd_dep.get_variable('systemduserunitdir')
+  endif
+endif
+
+zshcompletiondir = get_option('zsh-completion-dir')
+if zshcompletiondir == ''
+  zshcompletiondir = datadir / 'zsh/site-functions'
+endif
+
+zsh_completions = fs.is_dir(zshcompletiondir)
+
+udev_dep = dependency('udev', version:'>= 196', required: udevlib_hid2hci_dep.found())
+if udev_dep.found()
+  udevdir = get_option('udevdir')
+  if udevdir == ''
+    udevdir = udev_dep.get_variable('udevdir')
+  endif
+endif
+
+if cups_dep.found()
+  cups_serverbin = get_option('cups_serverbin')
+  if cups_serverbin == ''
+    cups_serverbin = cups_dep.get_variable('cups_serverbin')
+  endif
+endif
+
+external_plugins_link_args = ''
+if get_option('external-plugins').enabled()
+  external_plugins_link_args = [
+    '-Wl,--export-dynamic',
+    '-Wl,--version-script=' + meson.project_source_root() / 'src/bluetooth.ver'
+  ]
+endif
+
+config_h.set('HAVE_A2DP', get_option('a2dp').allowed())
+config_h.set('HAVE_AVRCP', get_option('avrcp').allowed())
+config_h.set('HAVE_ASHA', get_option('asha').allowed())
+config_h.set('HAVE_VCP', get_option('vcp').allowed())
+config_h.set10('EXTERNAL_PLUGINS', get_option('external-plugins').enabled())
+config_h.set_quoted('VERSION', meson.project_version())
+
+configure_file(
+  output: 'config.h',
+  configuration: config_h
+)
+
+subdir('lib')
+subdir('gdbus')
+subdir('attrib')
+subdir('btio')
+subdir('plugins')
+subdir('profiles')
+subdir('src')
+subdir('client')
+if get_option('monitor').allowed()
+  subdir('monitor')
+endif
+subdir('emulator')
+subdir('gobex')
+subdir('tools')
+subdir('peripheral')
+if get_option('obex').enabled()
+  subdir('obexd')
+endif
+if zsh_completions
+  subdir('completion')
+endif
+if get_option('mesh').enabled()
+  subdir('mesh')
+endif
+if rst2man.found()
+  subdir('doc')
+endif
+if get_option('tests').allowed()
+  subdir('test')
+  subdir('unit')
+endif
+
+# Fix permissions on install
+install = find_program('install')
+sh = find_program('sh')
+meson.add_install_script(sh, '-c', 'install -dm755 ${DESTDIR}/' + configdir)
+meson.add_install_script(sh, '-c', 'install -dm700 ${DESTDIR}/' + storagedir)
+if get_option('mesh').enabled()
+  meson.add_install_script(sh, '-c', 'install -dm700 ${DESTDIR}/' + meshstoragedir)
+endif
diff --git a/meson_options.txt b/meson_options.txt
new file mode 100644
index 000000000000..4a0c726c2098
--- /dev/null
+++ b/meson_options.txt
@@ -0,0 +1,52 @@
+option('valgrind', type: 'feature', value: 'disabled', description: 'Enable valgrind memory checks')
+option('backtrace', type: 'feature', value: 'disabled', description: 'Enable backtrace support')
+option('library', type: 'feature', value: 'enabled', description: 'Install Bluetooth library')
+option('examples', type: 'feature', value: 'auto', description: 'Enable test/example scripts')
+option('tests', type: 'feature', value: 'auto', description: 'Enable testing tools')
+option('tools', type: 'feature', value: 'enabled', description: 'Enable Bluetooth tools')
+option('monitor', type: 'feature', value: 'enabled', description: 'Enable Bluetooth monitor')
+option('client', type: 'feature', value: 'enabled', description: 'Enable command line client')
+option('systemd', type: 'feature', value: 'enabled', description: 'Enable systemd integration')
+option('udev', type: 'feature', value: 'enabled', description: 'Enable udev device support in tools')
+option('datafiles', type: 'feature', value: 'enabled', description: 'Install configuration and data files')
+option('manpages', type: 'feature', value: 'auto', description: 'Enable building of manual pages')
+option('experimental', type: 'feature', value: 'disabled', description: 'Enable experimental tools')
+option('deprecated', type: 'feature', value: 'disabled', description: 'Enable deprecated tools')
+option('external-plugins', type: 'feature', value: 'enabled', description: 'Enable support for external plugins')
+
+option('dbusconfdir', type: 'string', value: '', description: 'D-Bus configuration directory')
+option('dbussystembusdir', type: 'string', value: '', description: 'D-Bus system bus services dir')
+option('dbussessionbusdir', type:'string', value: '', description: 'D-Bus session bus services dir')
+option('systemdsystemunitdir', type: 'string', value: '', description: 'path to systemd system unit directory')
+option('systemduserunitdir', type: 'string', value: '', description: 'systemd user unit dir')
+option('zsh-completion-dir', type:'string', value: '', description: 'Path to install zsh completions')
+option('udevdir', type: 'string', value: '', description: 'udev directory')
+option('cups_serverbin', type: 'string', value: '', description: 'CUPS directory')
+
+option('nfc', type: 'feature', value: 'disabled', description: 'Enable NFC pairing')
+option('a2dp', type: 'feature', value: 'auto', description: 'Enable A2DP profile')
+option('avrcp', type: 'feature', value: 'auto', description: 'Enable AVRCP profile')
+option('network', type: 'feature', value: 'auto', description: 'Enable network profiles')
+option('hid', type: 'feature', value: 'auto', description: 'Enable HID profile')
+option('hog', type: 'feature', value: 'auto', description: 'Enable HoG profile')
+option('bap', type: 'feature', value: 'auto', description: 'Enable BAP profile')
+option('bass', type: 'feature', value: 'auto', description: 'Enable BASS service')
+option('mcp', type: 'feature', value: 'auto', description: 'Enable MCP profile')
+option('ccp', type: 'feature', value: 'auto', description: 'Enable CCP profile')
+option('vcp', type: 'feature', value: 'auto', description: 'Enable VCP profile')
+option('micp', type: 'feature', value: 'auto', description: 'Enable MICP profile')
+option('csip', type: 'feature', value: 'auto', description: 'Enable CSIP profile')
+option('asha', type: 'feature', value: 'auto', description: 'Enable ASHA support')
+option('cups', type: 'feature', value: 'auto', description: 'Enable CUPS printer support')
+option('mesh', type: 'feature', value: 'auto', description: 'Enable Mesh profile support')
+option('midi', type: 'feature', value: 'auto', description: 'Enable MIDI support')
+option('obex', type: 'feature', value: 'auto', description: 'Enable OBEX profile support')
+option('tmap', type: 'feature', value: 'auto', description: 'Enable TMAP profile support')
+option('gmap', type: 'feature', value: 'auto', description: 'Enable GMAP profile support')
+option('hfp', type: 'feature', value: 'auto', description: 'Enable HFP profile support')
+option('btpclient', type: 'feature', value: 'auto', description: 'Enable BTP client')
+option('sixaxis', type: 'feature', value: 'auto', description: 'Enable sixaxis plugin')
+option('hid2hci', type: 'feature', value: 'auto', description: 'Enable hid2hci tool')
+option('logger', type: 'feature', value: 'disabled', description: 'Enable HCI logger service')
+option('admin', type: 'feature', value: 'auto', description: 'Enable admin policy plugin')
+option('phonebook', type: 'combo', choices: [ 'dummy', 'ebook' ], value: 'dummy', description: 'Obexd phonebook plugin')
diff --git a/monitor/meson.build b/monitor/meson.build
new file mode 100644
index 000000000000..44197f2d3ba2
--- /dev/null
+++ b/monitor/meson.build
@@ -0,0 +1,37 @@
+executable('btmon',
+  sources: [
+    'main.c',
+    'display.c',
+    'hcidump.c',
+    'ellisys.c',
+    'control.c',
+    'packet.c',
+    'vendor.c',
+    'lmp.c',
+    'crc.c',
+    'll.c',
+    'l2cap.c',
+    'sdp.c',
+    'avctp.c',
+    'avdtp.c',
+    'a2dp.c',
+    'rfcomm.c',
+    'bnep.c',
+    'hwdb.c',
+    'keys.c',
+    'analyze.c',
+    'intel.c',
+    'broadcom.c',
+    'msft.c',
+    'jlink.c',
+    'att.c',
+    '../src/log.c',
+    '../src/textfile.c',
+    '../src/settings.c'
+  ],
+  c_args: [
+    '-DSTORAGEDIR="@0"'.format(storagedir)
+  ],
+  dependencies: [ libbluetooth_internal_dep, libshared_mainloop_dep, udevlib_dep, glib_dep ],
+  install: true
+)
diff --git a/obexd/meson.build b/obexd/meson.build
new file mode 100644
index 000000000000..baddafcd8873
--- /dev/null
+++ b/obexd/meson.build
@@ -0,0 +1,121 @@
+if get_option('datafiles').allowed()
+  install_data('src/obex.conf',
+    install_dir: dbusconfdir / 'dbus-1/system.d'
+  )
+endif
+
+if systemd_dep.found()
+  configure_file(
+    input: 'src/obex.service.in',
+    output: 'obex.service',
+    install: true,
+    install_dir: systemduserunitdir,
+    configuration: service_conf
+  )
+  configure_file(
+    input: 'src/org.bluez.obex.service.in',
+    output: 'org.bluez.obex.service',
+    install: true,
+    install_dir: dbussessionbusdir,
+    configuration: service_conf
+  )
+  install_symlink('dbus-org.bluez.obex.service',
+    pointing_to: dbussessionbusdir / 'org.bluez.obex.service',
+    install_dir: systemduserunitdir
+  )
+endif
+
+obexd_builtin_modules = [
+  'filesystem',
+  'bluetooth',
+  'opp',
+  'ftp',
+  'irmc',
+  'pbap',
+  'mas',
+  'mns'
+]
+
+obexd_builtin_sources = [
+  'plugins/filesystem.c',
+  'plugins/bluetooth.c',
+  'plugins/opp.c',
+  'plugins/ftp.c',
+  'plugins/irmc.c',
+  'plugins/pbap.c',
+  'plugins/vcard.c',
+  'plugins/phonebook-@0@.c'.format(get_option('phonebook')),
+  'plugins/mas.c',
+  'plugins/messages-dummy.c',
+  'client/mns.c',
+]
+
+if get_option('experimental').allowed()
+  obexd_builtin_modules += 'pcsuite'
+  obexd_builtin_sources += 'plugins/pcsuite.c'
+endif
+
+obex_plugindir = get_option('libdir') / 'obex/plugins'
+
+obexd_genbuiltin = find_program('src/genbuiltin')
+obexd_builtin_h = custom_target('obexd-builtin.h',
+  output: 'builtin.h',
+  capture: true,
+  command: [ obexd_genbuiltin, obexd_builtin_modules ]
+)
+
+executable('obexd',
+  sources: [
+    btio_sources,
+    gobex_sources,
+    obexd_builtin_sources,
+    obexd_builtin_h,
+    'src/main.c',
+    'src/plugin.c',
+    'src/log.c',
+    'src/logind.c',
+    'src/manager.c',
+    'src/obex.c',
+    'src/mimetype.c',
+    'src/service.c',
+    'src/transport.c',
+    'src/server.c',
+    'client/manager.c',
+    'client/session.c',
+    'client/bluetooth.c',
+    'client/sync.c',
+    'client/pbap.c',
+    'client/ftp.c',
+    'client/opp.c',
+    'client/map.c',
+    'client/bip.c',
+    'client/bip-common.c',
+    'client/map-event.c',
+    'client/transfer.c',
+    'client/transport.c',
+    'client/driver.c'
+  ],
+  dependencies: [
+    libbluetooth_internal_dep,
+    libgdbus_internal_dep,
+    libshared_glib_dep,
+    ical_dep,
+    dbus_dep,
+    ebook_dep,
+    edataserver_dep,
+    glib_dep,
+    libsystemd_dep.found() ? libsystemd_dep : dummy_dep
+  ],
+  c_args: [
+    '-DOBEX_PLUGIN_BUILTIN',
+    '-DPLUGINDIR="@0@"'.format(obex_plugindir),
+    '-D_FILE_OFFSET_BITS=64',
+    '-DCONFIGDIR="@0@"'.format(configdir),
+    libsystemd_dep.found() ? '-DSYSTEMD' : ''
+  ],
+  link_args: external_plugins_link_args,
+  install: true,
+  install_dir: pkglibexecdir,
+)
+
+
diff --git a/peripheral/meson.build b/peripheral/meson.build
new file mode 100644
index 000000000000..6a9fdb4cbc66
--- /dev/null
+++ b/peripheral/meson.build
@@ -0,0 +1,13 @@
+if get_option('tests').allowed()
+  executable('btsensor',
+    sources: [
+      'main.c',
+      'efivars.c',
+      'attach.c',
+      'log.c',
+      'gap.c',
+      'gatt.c',
+    ],
+    dependencies: [ libshared_mainloop_dep, libbluetooth_internal_dep ]
+  )
+endif
diff --git a/plugins/meson.build b/plugins/meson.build
new file mode 100644
index 000000000000..d02fb8530af0
--- /dev/null
+++ b/plugins/meson.build
@@ -0,0 +1,29 @@
+builtin_modules = [
+  'hostname',
+  'autopair',
+  'policy',
+]
+
+builtin_sources = files(
+  'hostname.c',
+  'autopair.c',
+  'policy.c'
+)
+
+builtin_deps = []
+
+if get_option('admin').allowed()
+  builtin_modules += 'admin'
+  builtin_sources += files('admin.c')
+endif
+
+if get_option('nfc').allowed()
+  builtin_modules += 'neard'
+  builtin_sources += files('neard.c')
+endif
+
+if udevlib_sixaxis_dep.found()
+  builtin_modules += 'sixaxis'
+  builtin_sources += files('sixaxis.c')
+  builtin_deps += udevlib_sixaxis_dep
+endif
diff --git a/profiles/meson.build b/profiles/meson.build
new file mode 100644
index 000000000000..64e2da2bcfea
--- /dev/null
+++ b/profiles/meson.build
@@ -0,0 +1,168 @@
+builtin_modules += [
+  'gap',
+  'scanparam',
+  'deviceinfo',
+  'battery',
+  'rap',
+]
+
+builtin_sources += files(
+  'audio/media.c',
+  'audio/transport.c',
+  'audio/player.c',
+  'audio/avrcp-player.c',
+  'gap/gas.c',
+  'scanparam/scan.c',
+  'deviceinfo/deviceinfo.c',
+  'battery/battery.c',
+  'ranging/rap.c',
+  'ranging/rap_hci.c',
+)
+
+if get_option('a2dp').allowed()
+  builtin_modules += 'a2dp'
+  builtin_sources += files(
+    'audio/source.c',
+    'audio/sink.c',
+    'audio/a2dp.c',
+    'audio/avdtp.c'
+  )
+endif
+
+if get_option('avrcp').allowed()
+  builtin_modules += 'avrcp'
+  builtin_sources += files(
+    'audio/control.c',
+    'audio/avctp.c',
+    'audio/avctp.c',
+    'audio/avrcp.c'
+  )
+endif
+
+if get_option('network').allowed()
+  builtin_modules += 'network'
+  builtin_sources += files(
+    'network/manager.c',
+    'network/bnep.c',
+    'network/server.c',
+    'network/connection.c'
+  )
+  install_data('network/network.conf',
+    install_dir: configdir
+  )
+endif
+
+if get_option('hid').allowed()
+  builtin_modules += 'input'
+  builtin_sources += files(
+    'input/manager.c',
+    'input/server.c',
+    'input/device.c'
+  )
+
+  install_data('input/input.conf',
+    install_dir: configdir
+  )
+endif
+
+if get_option('hog').allowed()
+  builtin_modules += 'hog'
+  builtin_sources += files(
+    'input/hog.c',
+    'input/hog-lib.c',
+    'deviceinfo/dis.c',
+    'battery/bas.c',
+    'scanparam/scpp.c',
+    'input/suspend-none.c'
+  )
+endif
+
+if alsa_dep.found()
+  builtin_modules += 'midi'
+  builtin_sources += files(
+    'midi/midi.c',
+    'midi/libmidi.c'
+  )
+  builtin_deps += alsa_dep
+endif
+
+if get_option('bap').allowed()
+  builtin_modules += 'bap'
+  builtin_sources += files('audio/bap.c')
+endif
+
+if get_option('bass').allowed()
+  builtin_modules += 'bass'
+  builtin_sources += files('audio/bass.c')
+endif
+
+if get_option('mcp').allowed()
+  builtin_modules += 'mcp'
+  builtin_sources += files('audio/mcp.c')
+endif
+
+if get_option('vcp').allowed()
+  builtin_modules += 'vcp'
+  builtin_sources += files('audio/vcp.c')
+endif
+
+if get_option('micp').allowed()
+  builtin_modules += 'micp'
+  builtin_sources += files('audio/micp.c')
+endif
+
+if get_option('ccp').allowed()
+  builtin_modules += 'ccp'
+  builtin_sources += files('audio/ccp.c')
+endif
+
+if get_option('csip').allowed()
+  builtin_modules += 'csip'
+  builtin_sources += files('audio/csip.c')
+endif
+
+if get_option('asha').allowed()
+  builtin_modules += 'asha'
+  builtin_sources += files('audio/asha.c')
+endif
+
+if get_option('tmap').allowed()
+  builtin_modules += 'tmap'
+  builtin_sources += files('audio/tmap.c')
+endif
+
+if get_option('gmap').allowed()
+  builtin_modules += 'gmap'
+  builtin_sources += files('audio/gmap.c')
+endif
+
+if get_option('hfp').allowed()
+  builtin_modules += 'hfp'
+  builtin_sources += files('audio/telephony.c', 'audio/hfp-hf.c')
+endif
+
+if get_option('tools').allowed()
+  executable('iapd',
+    sources: 'iap/main.c',
+    dependencies: [ libgdbus_internal_dep, glib_dep, dbus_dep ]
+  )
+endif
+
+if cups_dep.found()
+  executable('bluetooth',
+    sources: [
+      'cups/main.c',
+      'cups/sdp.c',
+      'cups/spp.c',
+      'cups/hcrp.c'
+    ],
+    dependencies: [
+      libbluetooth_internal_dep,
+      libgdbus_internal_dep,
+      glib_dep,
+      dbus_dep
+    ],
+    install: true,
+    install_dir: cups_serverbin / 'backend'
+  )
+endif
diff --git a/src/meson.build b/src/meson.build
new file mode 100644
index 000000000000..65b7131c86b4
--- /dev/null
+++ b/src/meson.build
@@ -0,0 +1,88 @@
+subdir('shared')
+
+if get_option('datafiles').allowed()
+  install_data('bluetooth.conf',
+    install_dir: dbusconfdir / 'dbus-1/system.d'
+  )
+  install_data('main.conf',
+    install_dir: configdir
+  )
+endif
+
+if systemd_dep.found()
+  configure_file(
+    input: 'bluetooth.service.in',
+    output: 'bluetooth.service',
+    install: true,
+    install_dir: systemdsystemunitdir,
+    configuration: service_conf
+  )
+
+  install_data('org.bluez.service',
+    install_dir: dbussystembusdir
+  )
+endif
+
+genbuiltin = find_program('genbuiltin')
+builtin_h = custom_target('src-builtin.h',
+  output: 'builtin.h',
+  capture: true,
+  command: [ genbuiltin, builtin_modules ]
+)
+
+executable('bluetoothd',
+  sources: [ builtin_sources,
+    attrib_sources,
+    btio_sources,
+    builtin_h,
+    'main.c',
+    'log.c',
+    'backtrace.c',
+    'rfkill.c',
+    'sdpd-server.c',
+    'sdpd-request.c',
+    'sdpd-service.c',
+    'sdpd-database.c',
+    'gatt-database.c',
+    'sdp-xml.c',
+    'sdp-client.c',
+    'textfile.c',
+    'uuid-helper.c',
+    'plugin.c',
+    'storage.c',
+    'advertising.c',
+    'agent.c',
+    'bearer.c',
+    'error.c',
+    'adapter.c',
+    'profile.c',
+    'service.c',
+    'gatt-client.c',
+    'device.c',
+    'dbus-common.c',
+    'eir.c',
+    'adv_monitor.c',
+    'battery.c',
+    'settings.c',
+    'set.c' ],
+  dependencies: [
+    libbluetooth_internal_dep,
+    libgdbus_internal_dep,
+    libshared_glib_dep,
+    backtrace_dep,
+    glib_dep,
+    dbus_dep,
+    udevlib_dep,
+    builtin_deps
+  ],
+  override_options: [ 'b_lundef=false' ],
+  c_args: [
+    '-DBLUETOOTH_PLUGIN_BUILTIN',
+    '-DPLUGINDIR="@0@"'.format(plugindir),
+    '-DSTORAGEDIR="@0@"'.format(storagedir),
+    '-DCONFIGDIR="@0@"'.format(configdir)
+  ],
+  link_args: [ '-Wl,--gc-sections', external_plugins_link_args ],
+  install: true,
+  install_dir: pkglibexecdir
+)
diff --git a/src/shared/meson.build b/src/shared/meson.build
new file mode 100644
index 000000000000..ae9a65e1b5c6
--- /dev/null
+++ b/src/shared/meson.build
@@ -0,0 +1,85 @@
+shared_sources = [
+  'queue.c',
+  'util.c',
+  'mgmt.c',
+  'crypto.c',
+  'ecc.c',
+  'ringbuf.c',
+  'hci.c',
+  'hci-crypto.c',
+  'hfp.c',
+  'uhid.c',
+  'pcap.c',
+  'btsnoop.c',
+  'ad.c',
+  'att.c',
+  'gatt-helpers.c',
+  'gatt-client.c',
+  'gatt-server.c',
+  'gatt-db.c',
+  'gap.c',
+  'log.c',
+  'bap.c',
+  'bap-debug.c',
+  'mcp.c',
+  'vcp.c',
+  'micp.c',
+  'csip.c',
+  'bass.c',
+  'ccp.c',
+  'asha.c',
+  'battery.c',
+  'uinput.c',
+  'tmap.c',
+  'gmap.c',
+  'rap.c',
+]
+
+if readline_dep.found()
+  shared_sources += [ 'shell.c' ]
+endif
+
+libshared_glib = static_library('libshared-glib',
+  sources: [ shared_sources,
+    'io-glib.c',
+    'timeout-glib.c',
+    'mainloop-glib.c',
+    'mainloop-notify.c',
+    'tester.c' ],
+  include_directories: '../../lib',
+  dependencies: glib_dep
+)
+
+libshared_glib_dep = declare_dependency(
+  link_with: libshared_glib,
+  dependencies: glib_dep
+)
+
+libshared_mainloop = static_library('libshared-mainloop',
+  sources: [ shared_sources,
+    'io-mainloop.c',
+    'timeout-mainloop.c',
+    'mainloop.c',
+    'mainloop-notify.c' ],
+  include_directories: '../../lib',
+  dependencies: glib_dep
+)
+
+libshared_mainloop_dep = declare_dependency(
+  link_with: libshared_mainloop
+)
+
+if ell_dep.found()
+  libshared_ell = static_library('libshared-ell',
+    sources: [ shared_sources,
+      'io-ell.c',
+      'timeout-ell.c',
+      'mainloop-ell.c' ],
+    include_directories: [ '../..', '../../lib' ],
+    dependencies: [ glib_dep, ell_dep ]
+  )
+  libshared_ell_dep = declare_dependency(
+    link_with: libshared_ell,
+    dependencies: ell_dep
+  )
+endif
diff --git a/test/meson.build b/test/meson.build
new file mode 100644
index 000000000000..6f93cf8a36e0
--- /dev/null
+++ b/test/meson.build
@@ -0,0 +1,37 @@
+test_scripts = [
+  'bluezutils.py',
+  'dbusdef.py',
+  'monitor-bluetooth',
+  'list-devices',
+  'test-discovery',
+  'test-manager',
+  'test-adapter',
+  'test-device',
+  'simple-agent',
+  'simple-endpoint',
+  'test-network',
+  'test-profile',
+  'service-record.dtd',
+  'service-did.xml',
+  'service-spp.xml',
+  'service-opp.xml',
+  'service-ftp.xml',
+  'simple-player',
+  'test-nap',
+  'test-hfp',
+  'opp-client',
+  'ftp-client',
+  'pbap-client',
+  'map-client',
+  'example-advertisement',
+  'example-gatt-server',
+  'example-gatt-client',
+  'test-gatt-profile',
+  'test-mesh',
+  'agent.py'
+]
+
+install_data(
+  sources: test_scripts,
+  install_dir: pkglibdir / 'tests'
+)
diff --git a/tools/mesh/meson.build b/tools/mesh/meson.build
new file mode 100644
index 000000000000..ae1fbca6f6b6
--- /dev/null
+++ b/tools/mesh/meson.build
@@ -0,0 +1,16 @@
+if get_option('tools').allowed() and readline_dep.found()
+  executable('mesh-cfgclient',
+    sources: [ '../mesh-cfgclient.c',
+      'cfgcli.c',
+      'keys.c',
+      'util.c',
+      'remote.c',
+      'agent.c',
+      'mesh-db.c',
+      '../../mesh/util.c',
+      '../../mesh/crypto.c',
+    ],
+    dependencies: [ libbluetooth_internal_dep, libshared_mainloop_dep, ell_dep, dbus_dep, jsonc_dep, readline_dep ],
+    install: true
+  )
+endif
diff --git a/tools/meson.build b/tools/meson.build
new file mode 100644
index 000000000000..8fc0dc1d2fb5
--- /dev/null
+++ b/tools/meson.build
@@ -0,0 +1,261 @@
+if get_option('logger').allowed()
+  executable('btmon-logger',
+    [ 'btmon-logger.c' ],
+    dependencies: libshared_mainloop_dep,
+    include_directories: '../lib/',
+    install_dir: pkglibexecdir
+  )
+
+  if systemd_dep.found()
+    configure_file(
+      input: 'bluetooth-logger.service.in',
+      output: 'bluetooth-logger.service',
+      configuration: service_in,
+      install: true,
+      install_dir: systemdsystemunitdir
+    )
+  endif
+endif
+
+executable('3dsp',
+  sources: '3dsp.c',
+  dependencies: libshared_mainloop_dep
+)
+
+tester_tools = [
+  'mgmt',
+  'mesh',
+  'l2cap',
+  'rfcomm',
+  'bnep',
+  'smp',
+  'gap',
+  'sco',
+  'userchan',
+  'iso',
+  'ioctl',
+  'hci',
+  '6lowpan',
+]
+
+if get_option('tests').allowed()
+  foreach tool: tester_tools
+    executable(tool + '-tester',
+      sources: [ tool + '-tester.c', emulator_sources ],
+      dependencies: [ libbluetooth_internal_dep, libshared_glib_dep, libgdbus_internal_dep, glib_dep ]
+    )
+  endforeach
+endif
+
+if udevlib_hid2hci_dep.found()
+  executable('hid2hci',
+    sources: 'hid2hci.c',
+    dependencies: udevlib_hid2hci_dep,
+    install: true,
+    install_dir: udevdir
+  )
+  install_data('hid2hci.rules',
+    install_dir: udevdir / 'rules.d',
+    rename: '97-hid2hci.rules'
+  )
+endif
+
+tools_names = [
+  'avinfo',
+  'avtest',
+  'scotest',
+  'hwdb',
+  'hcieventmask',
+  'btinfo',
+  'btconfig',
+  'btsnoop',
+  'btproxy',
+  'cltest',
+  'oobtest',
+  'advtest',
+  'seq2bseq',
+  'nokfw',
+  'rtlfw',
+  'create-image',
+  'eddystone',
+  'ibeacon',
+]
+
+inst_tools_names = [
+  'rctest',
+  'l2test',
+  'l2ping',
+  'bluemoon',
+  'hex2hcd',
+  'mpris-proxy',
+  'btattach',
+  'isotest'
+]
+
+if get_option('tools').allowed()
+  foreach tool: tools_names
+    executable(tool,
+      sources: tool + '.c',
+      dependencies: [ libbluetooth_internal_dep, libshared_mainloop_dep ]
+    )
+  endforeach
+
+  foreach tool: inst_tools_names
+    executable(tool,
+      sources: tool + '.c',
+      dependencies: [ libbluetooth_internal_dep, libshared_mainloop_dep, libgdbus_internal_dep, dbus_dep, glib_dep ],
+      install: true
+    )
+  endforeach
+
+  if udevlib_dep.found()
+    executable('bdaddr',
+      sources: [ 'bdaddr.c', '../src/oui.c' ],
+      dependencies: [ libbluetooth_internal_dep, udevlib_dep ]
+    )
+  endif
+  executable('btiotest',
+    sources: [ 'btiotest.c', btio_sources ],
+    dependencies: [ libbluetooth_internal_dep, glib_dep ]
+  )
+  executable('bneptest',
+    sources: [ 'bneptest.c', btio_sources, '../src/log.c', '../profiles/network/bnep.c' ],
+    dependencies: [ libbluetooth_internal_dep, libshared_mainloop_dep, glib_dep ]
+  )
+  executable('btgatt-client',
+    sources: [ 'btgatt-client.c', '../src/uuid-helper.c' ],
+    dependencies: [ libbluetooth_internal_dep, libshared_mainloop_dep ]
+  )
+  executable('btgatt-server',
+    sources: [ 'btgatt-server.c', '../src/uuid-helper.c' ],
+    dependencies: [ libbluetooth_internal_dep, libshared_mainloop_dep ]
+  )
+  if udevlib_dep.found()
+    executable('gatt-service',
+      sources: 'gatt-service.c',
+      dependencies: [ libbluetooth_internal_dep, libshared_mainloop_dep, glib_dep, libgdbus_internal_dep, udevlib_dep ]
+    )
+  endif
+  executable('test-runner',
+    sources: 'test-runner.c',
+    dependencies: [ libbluetooth_internal_dep ]
+  )
+
+  if readline_dep.found()
+    executable('btmgmt',
+      sources: [ 'btmgmt.c', '../src/uuid-helper.c', '../client/display.c', '../client/mgmt.c' ],
+      dependencies: [ libbluetooth_internal_dep, libshared_glib_dep, readline_dep ]
+    )
+    executable('obex-client-tool',
+      sources: [ 'obex-client-tool.c', gobex_sources, btio_sources ],
+      dependencies: [ libbluetooth_internal_dep, libshared_glib_dep, readline_dep, glib_dep ]
+    )
+    executable('obex-server-tool',
+      sources: [ 'obex-server-tool.c', gobex_sources, btio_sources ],
+      dependencies: [ libbluetooth_internal_dep, libshared_glib_dep, glib_dep ]
+    )
+    executable('bluetooth-player',
+      sources: [ 'bluetooth-player.c', '../client/print.c', '../client/player.c' ],
+      dependencies: [ libbluetooth_internal_dep, libshared_glib_dep, libgdbus_internal_dep, readline_dep ]
+    )
+    executable('obexctl',
+      sources: [ 'obexctl.c' ],
+      dependencies: [ libbluetooth_internal_dep, libshared_glib_dep, libgdbus_internal_dep, readline_dep ]
+    )
+    if get_option('mesh').enabled()
+      executable('mesh-cfgtest',
+        sources: 'mesh-cfgtest.c',
+        dependencies: [ libbluetooth_internal_dep, dbus_dep, ell_dep ],
+        include_directories: '..',
+        install: true
+      )
+      if get_option('deprecated').allowed()
+        executable('meshctl',
+          sources: [
+            'meshctl.c',
+            'mesh/agent.c',
+            'mesh-gatt/node.c',
+            'mesh-gatt/gatt.c',
+            'mesh-gatt/crypto.c',
+            'mesh-gatt/net.c',
+            'mesh-gatt/prov.c',
+            'mesh-gatt/util.c',
+            'mesh-gatt/prov-db.c',
+            'mesh-gatt/config-client.c',
+            'mesh-gatt/config-server.c',
+            'mesh-gatt/onoff-model.c'
+            ],
+          dependencies: [
+            libgdbus_internal_dep,
+            libshared_glib_dep,
+            libbluetooth_internal_dep,
+            glib_dep,
+            dbus_dep,
+            jsonc_dep,
+            readline_dep
+            ],
+          install: true
+        )
+      endif
+    endif
+  endif
+
+  if get_option('deprecated').allowed()
+    executable('gatttool',
+      sources: gatttool_sources,
+      dependencies: [ libbluetooth_internal_dep, libshared_glib_dep, readline_dep ],
+    )
+    executable('hciattach',
+      sources: [
+        'hciattach.c',
+        'hciattach_st.c',
+        'hciattach_ti.c',
+        'hciattach_tialt.c',
+        'hciattach_ath3k.c',
+        'hciattach_qualcomm.c',
+        'hciattach_intel.c',
+        'hciattach_bcm43xx.c'
+      ],
+      dependencies: libbluetooth_internal_dep,
+      install: true
+    )
+    if udevlib_dep.found()
+      executable('hcitool',
+        sources: [ 'hcitool.c', '../src/oui.c' ],
+        dependencies: [ libbluetooth_internal_dep, udevlib_dep ],
+        install: true
+      )
+    endif
+    executable('sdptool',
+      sources: [ 'sdptool.c', '../src/sdp-xml.c' ],
+      dependencies: [ libbluetooth_internal_dep, glib_dep ],
+      install: true
+    )
+    deprecated_tools = [
+      'ciptool',
+      'hciconfig',
+      'rfcomm'
+    ]
+    foreach tool: deprecated_tools
+      executable(tool,
+        sources: tool + '.c',
+        dependencies: libbluetooth_internal_dep,
+        install: true
+      )
+    endforeach
+  endif
+
+  if systemd_dep.found()
+    configure_file(
+      input: 'mpris-proxy.service.in',
+      output: 'mpris-proxy.service',
+      configuration: service_in,
+      install: true,
+      install_dir: systemduserunitdir
+    )
+  endif
+endif
+
+if get_option('mesh').enabled()
+  subdir('mesh')
+endif
diff --git a/tools/mpris-proxy.service.in b/tools/mpris-proxy.service.in
index 6ae56c6720b9..a55f0254014a 100644
--- a/tools/mpris-proxy.service.in
+++ b/tools/mpris-proxy.service.in
@@ -8,7 +8,7 @@ ConditionUser=!@system
 
 [Service]
 Type=simple
-ExecStart=@PKGBINDIR@/mpris-proxy
+ExecStart=@PKGLIBEXECDIR@/mpris-proxy
 
 [Install]
 WantedBy=default.target
diff --git a/unit/meson.build b/unit/meson.build
new file mode 100644
index 000000000000..c8198574147d
--- /dev/null
+++ b/unit/meson.build
@@ -0,0 +1,126 @@
+
+tests1 = [
+  [ 'test-tester.c' ],
+  [ 'test-uuid.c' ],
+  [ 'test-eir.c', '../src/eir.c', '../src/uuid-helper.c' ],
+  [ 'test-sdp.c', '../src/sdpd-database.c', '../src/log.c', '../src/sdpd-service.c', '../src/sdpd-request.c' ],
+  [ 'test-avrcp.c', '../src/log.c', 'avctp.c', 'avrcp-lib.c' ],
+  [ 'test-lib.c' ],
+  [ 'test-gatt.c' ],
+  [ 'test-bap.c' ],
+  [ 'test-micp.c' ],
+  [ 'test-bass.c' ],
+  [ 'test-vcp.c' ],
+  [ 'test-battery.c' ],
+  [ 'test-tmap.c' ],
+  [ 'test-gmap.c' ],
+  [ 'test-rap.c' ],
+  [ 'test-mcp.c' ],
+  [ 'test-hog.c',
+    btio_sources,
+    '../profiles/input/hog-lib.c',
+    '../profiles/scanparam/scpp.c',
+    '../profiles/battery/bas.c',
+    '../profiles/deviceinfo/dis.c',
+    '../src/log.c',
+    '../attrib/att.c',
+    '../attrib/gatt.c',
+    '../attrib/gattrib.c'
+  ],
+]
+
+foreach t: tests1
+  test_name = t[0].substring(0, -2)
+  exe = executable(test_name,
+    sources: t,
+    dependencies: [ libshared_glib_dep, libbluetooth_internal_dep ],
+  )
+  test(test_name, exe)
+endforeach
+
+tests2 = [
+  [ 'test-textfile.c', '../src/textfile.c' ],
+  [ 'test-crc.c', '../monitor/crc.c' ],
+  [ 'test-crypto.c' ],
+  [ 'test-ecc.c' ],
+  [ 'test-ringbuf.c' ],
+  [ 'test-queue.c' ],
+  [ 'test-mgmt.c' ],
+  [ 'test-uhid.c' ],
+  [ 'test-hfp.c' ],
+  [ 'test-avdtp.c', '../src/log.c', 'avdtp.c' ],
+  [ 'test-avctp.c', '../src/log.c', 'avctp.c' ],
+  [ 'test-util.c' ],
+]
+
+if ical_dep.found()
+  tests2 += [
+    [ 'test-gobex.c', 'util.c', gobex_sources ],
+    [ 'test-gobex-packet.c', 'util.c', gobex_sources ],
+    [ 'test-gobex-header.c', 'util.c', gobex_sources ],
+    [ 'test-gobex-transfer.c', 'util.c', gobex_sources ],
+    [ 'test-gobex-apparam.c', 'util.c', gobex_sources ],
+  ]
+endif
+
+foreach t: tests2
+  test_name = t[0].substring(0, -2)
+  exe = executable(test_name,
+    sources: t,
+    c_args: [ '-DSTORAGEDIR="@0"'.format(storagedir) ],
+    include_directories: '../lib',
+    dependencies: libshared_glib_dep
+  )
+  test(test_name, exe)
+endforeach
+
+exe = executable('test-gdbus-client',
+  sources: 'test-gdbus-client.c',
+  dependencies: [ libgdbus_internal_dep, libshared_glib_dep ]
+)
+dbus_run_session = find_program('dbus-run-session')
+if dbus_run_session.found()
+  test('test-gdbus-client', dbus_run_session, args: [ '--', exe ])
+else
+  test('test-gdbus-client', exe)
+endif
+
+exe = executable('test-gattrib',
+  sources: [ 'test-gattrib.c', '../attrib/gattrib.c', btio_sources, '../src/log.c' ],
+  dependencies: [ libshared_glib_dep, libbluetooth_internal_dep ]
+)
+test('test-gattrib', exe)
+
+exe = executable('test-profile',
+  sources: [ 'test-profile.c', 'btd.c', '../src/profile.c' ],
+  dependencies: [ dbus_dep, libshared_glib_dep, libbluetooth_internal_dep ]
+)
+test('test-profile', exe)
+
+if alsa_dep.found()
+  exe = executable('test-midi',
+    sources: [ 'test-midi.c', '../profiles/midi/libmidi.c' ],
+    c_args: [ '-DMIDI_TEST' ],
+    dependencies: [ libshared_glib_dep, alsa_dep ]
+  )
+  test('test-midi', exe)
+endif
+
+if get_option('mesh').enabled()
+  exe = executable('test-mesh-crypto',
+    sources: [ 'test-mesh-crypto.c' ],
+    dependencies: [ ell_dep ]
+  )
+  test('test-mesh-crypto', exe)
+endif
+
+add_test_setup(
+  'valgrind',
+  exe_wrapper: [
+    'valgrind', '--quiet', '--leak-check=full', '--trace-children=yes',
+    '--suppressions=@0@'.format(meson.current_source_dir() / 'valgrind.supp'),
+    '--num-callers=30', '--show-reachable=no', '--error-exitcode=1',
+  ],
+  # default timeout in meson is 30s
+  timeout_multiplier: 4,
+)
-- 
2.54.0


^ permalink raw reply related

* [BlueZ v10 01/16] build: Add meson wrap for libell
From: Bastien Nocera @ 2026-05-05  8:45 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <20260505085741.2497401-1-hadess@hadess.net>

Rather than relying on libell being able to build with meson from
upstream, apply the meson build patches on top of the latest upstream
release.

The build should still fallback to the system libell if available, and
will fail to build if a system libell is not available, and no network
access is available, as in many build systems.
---
 subprojects/ell.wrap                          |  11 +
 .../0001-build-Add-meson-build-system.patch   | 922 ++++++++++++++++++
 2 files changed, 933 insertions(+)
 create mode 100644 subprojects/ell.wrap
 create mode 100644 subprojects/packagefiles/0001-build-Add-meson-build-system.patch

diff --git a/subprojects/ell.wrap b/subprojects/ell.wrap
new file mode 100644
index 000000000000..f2ff070085f2
--- /dev/null
+++ b/subprojects/ell.wrap
@@ -0,0 +1,11 @@
+[wrap-file]
+directory = ell-0.82
+source_url = https://www.kernel.org/pub/linux/libs/ell/ell-0.82.tar.xz
+source_filename = ell-0.82.tar.xz
+source_hash = 133a9273151090b4cc37676063cc00ff350a093032ba20a2aaf8b3c5fd6f8b6d
+
+# Maintained in https://github.com/hadess/ell/tree/wip/hadess/add-meson
+diff_files = 0001-build-Add-meson-build-system.patch
+
+[provide]
+dependency_names = ell
diff --git a/subprojects/packagefiles/0001-build-Add-meson-build-system.patch b/subprojects/packagefiles/0001-build-Add-meson-build-system.patch
new file mode 100644
index 000000000000..c06896515795
--- /dev/null
+++ b/subprojects/packagefiles/0001-build-Add-meson-build-system.patch
@@ -0,0 +1,922 @@
+From 84f74ee4f0e199a6e80719f9eb365c45be405d96 Mon Sep 17 00:00:00 2001
+From: Bastien Nocera <hadess@hadess.net>
+Date: Thu, 17 Jul 2025 11:31:22 +0200
+Subject: [PATCH] build: Add meson build system
+
+--enable-pie is replaced by the meson base option "b_pie":
+https://mesonbuild.com/Builtin-options.html#base-options
+
+--enable-maintainer-mode is replaced by the "debug" build-types:
+https://mesonbuild.com/Builtin-options.html#core-options
+
+--enable-debug and --disable-optimization are replaced by the
+debug build type:
+https://mesonbuild.com/Builtin-options.html#details-for-buildtype
+
+Each of the sanitisers have their own b_sanitize option:
+- asan: b_sanitize=address
+- lsan: b_sanitize=leak
+- ubsan: b_sanitize=address,undefined
+https://mesonbuild.com/Builtin-options.html#base-options
+
+--enable-coverage is replaced by the b_coverage option:
+https://mesonbuild.com/Builtin-options.html#base-options
+---
+ ell/meson.build              | 187 +++++++++++++
+ examples/meson.build         |  32 +++
+ meson.build                  |  69 +++++
+ meson_options.txt            |   5 +
+ tools/meson.build            |  18 ++
+ unit/gen-cert-expired-pem.sh |  14 +
+ unit/meson.build             | 501 +++++++++++++++++++++++++++++++++++
+ unit/xxd.sh                  |   3 +
+ 8 files changed, 829 insertions(+)
+ create mode 100644 ell/meson.build
+ create mode 100644 examples/meson.build
+ create mode 100644 meson.build
+ create mode 100644 meson_options.txt
+ create mode 100644 tools/meson.build
+ create mode 100755 unit/gen-cert-expired-pem.sh
+ create mode 100644 unit/meson.build
+ create mode 100755 unit/xxd.sh
+
+diff --git a/ell/meson.build b/ell/meson.build
+new file mode 100644
+index 000000000000..ba61a39a8cc3
+--- /dev/null
++++ b/ell/meson.build
+@@ -0,0 +1,187 @@
++lib_headers = [
++  'ell.h',
++  'util.h',
++  'test.h',
++  'strv.h',
++  'utf8.h',
++  'queue.h',
++  'hashmap.h',
++  'string.h',
++  'settings.h',
++  'main.h',
++  'idle.h',
++  'signal.h',
++  'timeout.h',
++  'io.h',
++  'ringbuf.h',
++  'log.h',
++  'checksum.h',
++  'netlink.h',
++  'genl.h',
++  'rtnl.h',
++  'dbus.h',
++  'dbus-service.h',
++  'dbus-client.h',
++  'hwdb.h',
++  'cipher.h',
++  'random.h',
++  'uintset.h',
++  'base64.h',
++  'pem.h',
++  'tls.h',
++  'uuid.h',
++  'key.h',
++  'file.h',
++  'dir.h',
++  'net.h',
++  'dhcp.h',
++  'dhcp6.h',
++  'cert.h',
++  'ecc.h',
++  'ecdh.h',
++  'time.h',
++  'gpio.h',
++  'path.h',
++  'icmp6.h',
++  'acd.h',
++  'tester.h',
++  'cleanup.h',
++  'netconfig.h',
++  'sysctl.h',
++  'minheap.h',
++  'notifylist.h'
++]
++
++lib_sources = [
++  'private.h',
++  'useful.h',
++  'missing.h',
++  'util.c',
++  'test-private.h',
++  'test.c',
++  'test-dbus.c',
++  'strv.c',
++  'utf8.c',
++  'queue.c',
++  'hashmap.c',
++  'string.c',
++  'settings.c',
++  'main-private.h',
++  'main.c',
++  'idle.c',
++  'signal.c',
++  'timeout.c',
++  'io.c',
++  'ringbuf.c',
++  'log.c',
++  'checksum.c',
++  'netlink-private.h',
++  'netlink.c',
++  'genl.c',
++  'rtnl-private.h',
++  'rtnl.c',
++  'dbus-private.h',
++  'dbus.c',
++  'dbus-message.c',
++  'dbus-util.c',
++  'dbus-service.c',
++  'dbus-client.c',
++  'dbus-name-cache.c',
++  'dbus-filter.c',
++  'gvariant-private.h',
++  'gvariant-util.c',
++  'siphash-private.h',
++  'siphash.c',
++  'hwdb.c',
++  'cipher.c',
++  'random.c',
++  'uintset.c',
++  'base64.c',
++  'asn1-private.h',
++  'pem-private.h',
++  'pem.c',
++  'tls-private.h',
++  'tls.c',
++  'tls-record.c',
++  'tls-extensions.c',
++  'tls-suites.c',
++  'uuid.c',
++  'key.c',
++  'file.c',
++  'dir.c',
++  'net-private.h',
++  'net.c',
++  'dhcp-private.h',
++  'dhcp.c',
++  'dhcp-transport.c',
++  'dhcp-lease.c',
++  'dhcp6-private.h',
++  'dhcp6.c',
++  'dhcp6-transport.c',
++  'dhcp6-lease.c',
++  'dhcp-util.c',
++  'dhcp-server.c',
++  'cert-private.h',
++  'cert.c',
++  'cert-crypto.c',
++  'ecc-private.h',
++  'ecc.h',
++  'ecc-external.c',
++  'ecc.c',
++  'ecdh.c',
++  'time.c',
++  'time-private.h',
++  'gpio.c',
++  'path.c',
++  'icmp6.c',
++  'icmp6-private.h',
++  'acd.c',
++  'tester.c',
++  'netconfig.c',
++  'sysctl.c',
++  'minheap.c',
++  'notifylist.c'
++]
++
++linux_headers = [
++  '../linux/gpio.h'
++]
++
++libell = library('ell',
++  sources: lib_headers + lib_sources + linux_headers,
++  include_directories: include_directories('..'),
++  implicit_include_directories: false,
++  gnu_symbol_visibility: 'hidden',
++  version: '0.2.0',
++  install: get_option('default_library') != 'static'
++)
++
++libell_dep = declare_dependency(include_directories: include_directories('..'),
++  link_with: libell)
++
++if get_option('default_library') != 'static'
++  install_headers(lib_headers,
++    subdir: 'ell'
++  )
++
++  pkgconfig = import('pkgconfig')
++  pkgconfig.generate(
++    name: 'ell',
++    description: 'Embedded Linux library',
++    version: meson.project_version(),
++    libraries: libell,
++    # FIXME requires meson 1.9.0
++    # license: meson.project_license()
++  )
++endif
++
++libell_private = static_library('ell_private',
++  sources: lib_headers + lib_sources + linux_headers,
++  include_directories: include_directories('..'),
++  implicit_include_directories: false,
++  install: false
++)
++
++libell_private_dep = declare_dependency(
++  link_with: libell_private
++)
+diff --git a/examples/meson.build b/examples/meson.build
+new file mode 100644
+index 000000000000..831abb58be46
+--- /dev/null
++++ b/examples/meson.build
+@@ -0,0 +1,32 @@
++examples = [
++  'dbus-service',
++  'https-client-test',
++  'https-server-test',
++  'dbus-client',
++  'dhcp-client',
++  'dhcp6-client',
++  'dhcp-server',
++  'acd-client',
++  'netconfig-test',
++]
++
++if get_option('examples')
++  foreach example: examples
++    exe = executable(example,
++      '@0@.c'.format(example),
++      include_directories: include_directories('..'),
++      dependencies: libell_private_dep,
++      install: false
++    )
++  endforeach
++endif
++
++if get_option('glib') and get_option('examples')
++  exe = executable('glib-eventloop',
++    'glib-eventloop.c',
++    include_directories: include_directories('..'),
++    dependencies: [ libell_private_dep, glib_dep ],
++    install: false
++  )
++endif
++
+diff --git a/meson.build b/meson.build
+new file mode 100644
+index 000000000000..8427d4fe6ec9
+--- /dev/null
++++ b/meson.build
+@@ -0,0 +1,69 @@
++# SPDX-License-Identifier: LGPL-2.1-or-later
++project(
++  'ell', 'c',
++  version: '0.82',
++  license: 'LGPL-2.1-or-later',
++  default_options: [
++    'buildtype=debugoptimized',
++    'default_library=shared'
++  ],
++  meson_version: '>= 1.3.0'
++)
++
++cc = meson.get_compiler('c')
++find_program('awk', required: true)
++config_h = configuration_data()
++
++checked_funcs = [
++  'explicit_bzero',
++  'rawmemchr',
++]
++
++foreach func: checked_funcs
++  config_h.set('HAVE_' + func.to_upper(), cc.has_function(func))
++endforeach
++
++required_funcs = [
++  'getrandom',
++  'signalfd',
++  'timerfd_create',
++  'epoll_create'
++]
++
++foreach func: required_funcs
++  cc.has_function(func, required: true)
++endforeach
++
++required_headers = [
++  'linux/types.h',
++  'linux/if_alg.h'
++]
++
++foreach header: required_headers
++  cc.has_header(header, required: true)
++endforeach
++
++glib_dep = dependency('glib-2.0', version: '>= 2.32', required: get_option('glib'))
++openssl = find_program('openssl', required: get_option('cert-tests'))
++sh = find_program('sh', required: get_option('cert-tests'))
++xxd = find_program('xxd', required: get_option('cert-tests'))
++
++if openssl.found()
++  r = run_command(openssl, 'list', '-providers', check: false)
++  if r.returncode() == 0
++    openssl_legacy = [ '-provider', 'legacy', '-provider', 'default' ]
++  else
++    openssl_legacy = ''
++  endif
++endif
++
++add_project_arguments('-DHAVE_CONFIG_H', language: 'c')
++configure_file(
++  output: 'config.h',
++  configuration: config_h
++)
++
++subdir('ell')
++subdir('tools')
++subdir('unit')
++subdir('examples')
+diff --git a/meson_options.txt b/meson_options.txt
+new file mode 100644
+index 000000000000..5effa15916b4
+--- /dev/null
++++ b/meson_options.txt
+@@ -0,0 +1,5 @@
++option('glib', type: 'boolean', value: true, description: 'Enable ell/glib main loop example')
++option('tests', type: 'boolean', value: true, description: 'Enable unit tests compilation')
++option('cert-tests', type: 'boolean', value: true, description: 'Enable OpenSSL cert tests')
++option('tools', type: 'boolean', value: true, description: 'Enable extra tools compilation')
++option('examples', type: 'boolean', value: true, description: 'Enable code examples compilation')
+diff --git a/tools/meson.build b/tools/meson.build
+new file mode 100644
+index 000000000000..01505f266631
+--- /dev/null
++++ b/tools/meson.build
+@@ -0,0 +1,18 @@
++tools = [
++  'certchain-verify',
++  'genl-discover',
++  'genl-watch',
++  'genl-request',
++  'gpio'
++]
++
++if get_option('tools')
++  foreach tool: tools
++      exe = executable(tool,
++        '@0@.c'.format(tool),
++        include_directories: include_directories('..'),
++        dependencies: libell_private_dep,
++        install: false
++      )
++  endforeach
++endif
+diff --git a/unit/gen-cert-expired-pem.sh b/unit/gen-cert-expired-pem.sh
+new file mode 100755
+index 000000000000..f3e0b9d28424
+--- /dev/null
++++ b/unit/gen-cert-expired-pem.sh
+@@ -0,0 +1,14 @@
++#!/bin/sh -e
++
++echo -n > cert-ca-index.txt
++OUTDIR=`mktemp -d`
++openssl ca -batch \
++	-config "$4" -name example \
++	-cert "$2" \
++	-keyfile "$3" \
++	-outdir $OUTDIR \
++	-rand_serial -extensions cert_ext \
++	-extfile "$5" -md sha256 \
++	-startdate 000101120000Z -enddate 010101120000Z \
++	-preserveDN -notext -in "$1" -out "$6"
++rm -rf $OUTDIR cert-ca-index.txt*
+diff --git a/unit/meson.build b/unit/meson.build
+new file mode 100644
+index 000000000000..be9f2655f010
+--- /dev/null
++++ b/unit/meson.build
+@@ -0,0 +1,501 @@
++tests = [
++  'test-unit',
++  'test-queue',
++  'test-hashmap',
++  'test-endian',
++  'test-string',
++  'test-utf8',
++  'test-main',
++  'test-io',
++  'test-ringbuf',
++  'test-checksum',
++  'test-settings',
++  'test-netlink',
++  'test-genl-msg',
++  'test-rtnl',
++  'test-siphash',
++  'test-cipher',
++  'test-random',
++  'test-util',
++  'test-uintset',
++  'test-base64',
++  'test-uuid',
++  'test-pbkdf2',
++  'test-dhcp',
++  'test-dhcp6',
++  'test-dir-watch',
++  'test-ecc',
++  'test-ecdh',
++  'test-time',
++  'test-path',
++  'test-net',
++  'test-sysctl',
++  'test-minheap',
++  'test-notifylist',
++  'test-hwdb',
++  'test-dbus',
++  'test-dbus-util',
++  'test-dbus-message',
++  'test-dbus-message-fds',
++  'test-dbus-properties',
++  'test-dbus-service',
++  'test-dbus-watch',
++  'test-gvariant-util',
++  'test-gvariant-message'
++]
++
++gen_headers = []
++test_pem_cert_deps = []
++
++if get_option('cert-tests')
++  tests += [
++    'test-pem',
++    'test-tls',
++    'test-key'
++  ]
++
++  cert_server_key_pem_tgt = custom_target('cert-server-key.pem',
++    output: 'cert-server-key.pem',
++    command: [ openssl, 'genrsa', '-out', '@OUTPUT@' ]
++  )
++
++  ec_cert_server_key_pem_tgt = custom_target('ec-cert-server-key.pem',
++    output: 'ec-cert-server-key.pem',
++    command: [ openssl, 'ecparam', '-out', '@OUTPUT@', '-name', 'secp384r1', '-genkey' ]
++  )
++
++  cert_server_key_pkcs8_pem_tgt = custom_target('cert-server-key-pkcs8.pem',
++    input: cert_server_key_pem_tgt,
++    output: 'cert-server-key-pkcs8.pem',
++    command: [ openssl, 'pkcs8', '-topk8', '-nocrypt', '-in', '@INPUT@', '-out', '@OUTPUT@' ]
++  )
++
++  cert_server_csr_tgt = custom_target('cert-server.csr',
++    input: cert_server_key_pem_tgt,
++    output: 'cert-server.csr',
++    command: [ openssl, 'req', '-new', '-extensions', 'cert_ext',
++      '-config', files('gencerts.cnf'),
++      '-subj', '/O=Foo Example Organization/CN=Foo Example Organization/emailAddress=foo@mail.example',
++      '-key', '@INPUT@', '-out', '@OUTPUT@' ]
++  )
++
++  ec_cert_server_csr_tgt = custom_target('ec-cert-server.csr',
++    input: ec_cert_server_key_pem_tgt,
++    output: 'ec-cert-server.csr',
++    command: [ openssl, 'req', '-new', '-extensions', 'cert_ext',
++      '-config', files('gencerts.cnf'),
++      '-subj', '/O=Foo Example Organization/CN=Foo Example Organization/emailAddress=foo@mail.example',
++      '-key', '@INPUT@', '-out', '@OUTPUT@' ]
++  )
++
++  cert_ca_key_pem_tgt = custom_target('cert-ca-key.pem',
++    output: 'cert-ca-key.pem',
++    command: [ openssl, 'genrsa', '-out', '@OUTPUT@', '2048' ]
++  )
++
++  cert_ca_pem_tgt = custom_target('cert-ca.pem',
++    input: cert_ca_key_pem_tgt,
++    output: 'cert-ca.pem',
++    command: [ openssl, 'req', '-x509', '-new', '-nodes', '-extensions', 'ca_ext',
++      '-config', files('gencerts.cnf'), '-subj', '/O=International Union of Example Organizations/CN=Certificate issuer guy/emailAddress=ca@mail.example',
++      '-key', '@INPUT@', '-sha256', '-days', '10000', '-out', '@OUTPUT@' ],
++  )
++
++  cert_server_pem_tgt = custom_target('cert-server.pem',
++    input: [ cert_server_csr_tgt, cert_ca_pem_tgt, cert_ca_key_pem_tgt ],
++    output: 'cert-server.pem',
++    command: [ openssl, 'x509', '-req', '-extensions', 'server_ext',
++      '-extfile', files('gencerts.cnf'),
++      '-in', '@INPUT0@', '-CA', '@INPUT1@',
++      '-CAkey', '@INPUT2@',
++      '-CAserial', 'cert-ca.srl',
++      '-CAcreateserial', '-sha256', '-days', '10000', '-out', '@OUTPUT@' ]
++  )
++
++  ec_cert_ca_key_pem_tgt = custom_target('ec-cert-ca-key.pem',
++    output: 'ec-cert-ca-key.pem',
++    command: [ openssl, 'ecparam', '-out', '@OUTPUT@', '-name', 'secp384r1', '-genkey' ]
++  )
++
++  ec_cert_ca_pem_tgt = custom_target('ec-cert-ca.pem',
++  input: ec_cert_ca_key_pem_tgt,
++  output: 'ec-cert-ca.pem',
++  command: [ openssl, 'req', '-x509', '-new', '-nodes', '-extensions', 'ca_ext',
++    '-config', files('gencerts.cnf'), '-subj', '/O=International Union of Example Organizations/CN=Certificate issuer guy/emailAddress=ca@mail.example',
++    '-key', '@INPUT@', '-sha256', '-days', '10000', '-out', '@OUTPUT@' ]
++  )
++
++  ec_cert_server_pem_tgt = custom_target('ec-cert-server.pem',
++    input: [ ec_cert_server_csr_tgt, ec_cert_ca_pem_tgt, ec_cert_ca_key_pem_tgt ],
++    output: 'ec-cert-server.pem',
++    command: [ openssl, 'x509', '-req', '-extensions', 'server_ext',
++      '-extfile', files('gencerts.cnf'),
++      '-in', '@INPUT0@', '-CA', '@INPUT1@',
++      '-CAkey', '@INPUT2@',
++      '-CAserial', 'cert-ca.srl',
++      '-CAcreateserial', '-sha256', '-days', '10000', '-out', '@OUTPUT@' ]
++  )
++
++  cert_client_key_pkcs1_pem_tgt = custom_target('cert-client-key-pkcs1.pem',
++    output: 'cert-client-key-pkcs1.pem',
++    command: [ openssl, 'genrsa', '-out', '@OUTPUT@' ]
++  )
++
++  cert_client_key_pkcs8_pem_tgt = custom_target('cert-client-key-pkcs8.pem',
++    input: cert_client_key_pkcs1_pem_tgt,
++    output: 'cert-client-key-pkcs8.pem',
++    command: [ openssl, 'pkcs8', '-topk8', '-nocrypt', '-in', '@INPUT@', '-out', '@OUTPUT@' ]
++  )
++
++  cert_client_key_pkcs8_md5_des_pem_tgt = custom_target('cert-client-key-pkcs8-md5-des.pem',
++    input: cert_client_key_pkcs8_pem_tgt,
++    output: 'cert-client-key-pkcs8-md5-des.pem',
++    command: [ openssl, 'pkcs8', '-in', '@INPUT@', '-out', '@OUTPUT@',
++      '-topk8', '-v1', 'PBE-MD5-DES', '-passout', 'pass:abc', openssl_legacy ]
++  )
++
++  cert_client_key_pkcs8_v2_des_pem_tgt = custom_target('cert-client-key-pkcs8-v2-des.pem',
++    input: cert_client_key_pkcs8_pem_tgt,
++    output: 'cert-client-key-pkcs8-v2-des.pem',
++    command: [ openssl, 'pkcs8', '-in', '@INPUT@', '-out', '@OUTPUT@',
++      '-topk8', '-v2', 'des-cbc', '-v2prf', 'hmacWithSHA1', '-passout', 'pass:abc',
++      openssl_legacy ]
++  )
++
++  cert_client_key_pkcs8_v2_des_ede3_pem_tgt = custom_target('cert-client-key-pkcs8-v2-des-ede3.pem',
++    input: cert_client_key_pkcs8_pem_tgt,
++    output: 'cert-client-key-pkcs8-v2-des-ede3.pem',
++    command: [ openssl, 'pkcs8', '-in', '@INPUT@', '-out', '@OUTPUT@',
++        '-topk8', '-v2', 'des-ede3-cbc', '-v2prf', 'hmacWithSHA224', '-passout', 'pass:abc' ]
++  )
++
++  cert_client_key_pkcs8_v2_aes128_pem_tgt = custom_target('cert-client-key-pkcs8-v2-aes128.pem',
++    input: cert_client_key_pkcs8_pem_tgt,
++    output: 'cert-client-key-pkcs8-v2-aes128.pem',
++    command: [ openssl, 'pkcs8', '-in', '@INPUT@', '-out', '@OUTPUT@',
++      '-topk8', '-v2', 'aes128', '-v2prf', 'hmacWithSHA256', '-passout', 'pass:abc' ]
++  )
++
++  cert_client_key_pkcs8_sha1_des_pem_tgt = custom_target('cert-client-key-pkcs8-sha1-des.pem',
++    input: cert_client_key_pkcs8_pem_tgt,
++    output: 'cert-client-key-pkcs8-sha1-des.pem',
++    command: [ openssl, 'pkcs8', '-in', '@INPUT@', '-out', '@OUTPUT@',
++      '-topk8', '-v1', 'PBE-SHA1-DES', '-passout', 'pass:abc', openssl_legacy ]
++  )
++
++  cert_client_key_pkcs8_v2_aes256_pem_tgt = custom_target('cert-client-key-pkcs8-v2-aes256.pem',
++    input: cert_client_key_pkcs8_pem_tgt,
++    output: 'cert-client-key-pkcs8-v2-aes256.pem',
++    command: [ openssl, 'pkcs8', '-in', '@INPUT@', '-out', '@OUTPUT@',
++      '-topk8', '-v2', 'aes256', '-v2prf', 'hmacWithSHA512', '-passout', 'pass:abc' ]
++  )
++
++  cert_client_csr_tgt = custom_target('cert-client.csr',
++    input: cert_client_key_pkcs1_pem_tgt,
++    output: 'cert-client.csr',
++    command: [ openssl, 'req', '-new', '-extensions', 'cert_ext',
++      '-config', files('gencerts.cnf'),
++      '-subj', '/O=Bar Example Organization/CN=Bar Example Organization/emailAddress=bar@mail.example',
++      '-key', '@INPUT@', '-out', '@OUTPUT@'
++    ]
++  )
++
++  cert_client_pem_tgt = custom_target('cert-client.pem',
++    input: [ cert_client_csr_tgt, cert_ca_pem_tgt, cert_ca_key_pem_tgt ],
++    output: 'cert-client.pem',
++    command: [ openssl, 'x509', '-req', '-extensions', 'cert_ext',
++      '-extfile', files('gencerts.cnf'),
++      '-in', '@INPUT0@', '-CA', '@INPUT1@',
++      '-CAkey', '@INPUT2@',
++      '-CAserial', 'cert-ca.srl',
++      '-CAcreateserial', '-sha256', '-days', '10000', '-out', '@OUTPUT@' ]
++  )
++
++  cert_client_crt_tgt = custom_target('cert-client.crt',
++    input: cert_client_pem_tgt,
++    output: 'cert-client.crt',
++    command: [ openssl, 'x509', '-in', '@INPUT@', '-out', '@OUTPUT@', '-outform', 'der' ]
++  )
++
++  cert_intca_key_pem_tgt = custom_target('cert-intca-key.pem',
++    output: 'cert-intca-key.pem',
++    command: [ openssl, 'genrsa', '-out', '@OUTPUT@' ]
++  )
++
++  cert_intca_csr_tgt = custom_target('cert-intca.csr',
++    input: cert_intca_key_pem_tgt,
++    output: 'cert-intca.csr',
++    command: [ openssl, 'req', '-new', '-extensions', 'int_ext',
++      '-config', files('gencerts.cnf'),
++      '-subj', '/O=International Union of Example Organizations/CN=Certificate issuer guy/emailAddress=ca@mail.example',
++      '-key', '@INPUT@', '-out', '@OUTPUT@' ]
++  )
++
++  cert_intca_pem_tgt = custom_target('cert-intca.pem',
++    input: [ cert_intca_csr_tgt, cert_ca_pem_tgt, cert_ca_key_pem_tgt ],
++    output: 'cert-intca.pem',
++    command: [ openssl, 'x509', '-req', '-extensions', 'int_ext',
++      '-extfile', files('gencerts.cnf'),
++      '-in', '@INPUT0@', '-CA', '@INPUT1@',
++      '-CAkey', '@INPUT2@',
++      '-CAserial', 'cert-ca.srl',
++      '-CAcreateserial', '-sha256', '-days', '10000', '-out', '@OUTPUT@' ]
++  )
++
++  cat = find_program('cat')
++
++  cert_chain_pem_tgt = custom_target('cert-chain.pem',
++    input: [ cert_intca_pem_tgt, cert_ca_pem_tgt ],
++    output: 'cert-chain.pem',
++    capture: true,
++    command: [ cat, '@INPUT@' ]
++  )
++
++  cert_entity_int_key_pem_tgt = custom_target('cert-entity-int-key.pem',
++    output: 'cert-entity-int-key.pem',
++    command: [ openssl, 'genrsa', '-out', '@OUTPUT@' ]
++  )
++
++  cert_entity_int_csr_tgt = custom_target('cert-entity-int.csr',
++    input: cert_entity_int_key_pem_tgt,
++    output: 'cert-entity-int.csr',
++    command: [ openssl, 'req', '-new', '-extensions', 'cert_ext',
++      '-config', files('gencerts.cnf'),
++      '-subj', '/O=Baz Example Organization/CN=Baz Example Organization/emailAddress=baz@mail.example',
++      '-key', '@INPUT@', '-out', '@OUTPUT@' ]
++  )
++
++  cert_entity_int_pem_tgt = custom_target('cert-entity-int.pem',
++    input: [ cert_entity_int_csr_tgt, cert_intca_pem_tgt, cert_intca_key_pem_tgt ],
++    output: 'cert-entity-int.pem',
++    command: [ openssl, 'x509', '-req', '-extensions', 'cert_ext',
++      '-extfile', files('gencerts.cnf'),
++      '-in', '@INPUT0@', '-CA', '@INPUT1@',
++      '-CAkey', '@INPUT2@',
++      '-CAserial', 'cert-intca.srl',
++      '-CAcreateserial', '-sha256', '-days', '10000', '-out', '@OUTPUT@' ]
++  )
++
++  cert_ca2_pem_tgt = custom_target('cert-ca2.pem',
++    input: cert_ca_key_pem_tgt,
++    output: 'cert-ca2.pem',
++    command: [ openssl, 'req', '-x509', '-new', '-nodes', '-extensions', 'ca_no_akid_ext',
++      '-config', files('gencerts.cnf'),
++      '-subj', '/O=International Union of Example Organizations/CN=Certificate issuer guy/emailAddress=ca-no-akid@mail.example',
++      '-key', '@INPUT@', '-sha256', '-days', '10000', '-out', '@OUTPUT@' ]
++  )
++
++  cert_client_key_pkcs1_des_pem_tgt = custom_target('cert-client-key-pkcs1-des.pem',
++    input: cert_client_key_pkcs1_pem_tgt,
++    output: 'cert-client-key-pkcs1-des.pem',
++    command: [ openssl, 'rsa', '-in', '@INPUT@', '-out', '@OUTPUT@', '-des', '-passout', 'pass:abc', openssl_legacy ],
++  )
++
++  cert_no_keyid_csr_tgt = custom_target('cert-no-keyid.csr',
++    input: cert_client_key_pkcs1_pem_tgt,
++    output: 'cert-no-keyid.csr',
++    command: [ openssl, 'req', '-new',
++      '-config', files('gencerts.cnf'),
++      '-subj', '/O=Baz Example Organization/CN=Baz Example Organization/emailAddress=baz@mail.example',
++      '-key', '@INPUT@', '-out', '@OUTPUT@' ]
++  )
++
++  cert_no_keyid_pem_tgt = custom_target('cert-no-keyid.pem',
++    input: [ cert_no_keyid_csr_tgt, cert_ca2_pem_tgt, cert_ca_key_pem_tgt ],
++    output: 'cert-no-keyid.pem',
++    command: [ openssl, 'x509', '-req', '-extensions', 'no_keyid_ext',
++      '-extfile', files('gencerts.cnf'),
++      '-in', '@INPUT0@', '-CA', '@INPUT1@',
++      '-CAkey', '@INPUT2@',
++      '-CAserial', 'cert-ca2.srl',
++      '-CAcreateserial', '-sha256', '-days', '10000', '-out', '@OUTPUT@' ]
++  )
++
++  cert_expired_csr_tgt = custom_target('cert-expired.csr',
++    input: cert_client_key_pkcs1_pem_tgt,
++    output: 'cert-expired.csr',
++    command: [ openssl, 'req', '-new', '-extensions', 'cert_ext',
++      '-config', files('gencerts.cnf'),
++      '-subj', '/O=Bar Example Organization/CN=Bar Example Organization/emailAddress=bar@mail.example',
++      '-key', '@INPUT@', '-out', '@OUTPUT@' ]
++  )
++
++  echo = find_program('echo')
++
++  cert_ca_cnf_tgt = custom_target('cert-ca.cnf',
++    output: 'cert-ca.cnf',
++    capture: true,
++    command: [ echo, '-e',
++      '[example]\ndatabase=cert-ca-index.txt\nserial=cert-ca.srl\npolicy=dummy\n[dummy]' ]
++  )
++
++  cert_entity_pkcs12_rc2_sha1_p12_tgt = custom_target('cert-entity-pkcs12-rc2-sha1.p12',
++    input: [ cert_entity_int_key_pem_tgt, cert_entity_int_pem_tgt, cert_chain_pem_tgt ],
++    output: 'cert-entity-pkcs12-rc2-sha1.p12',
++    command: [ openssl, 'pkcs12', '-inkey', '@INPUT0@', '-in', '@INPUT1@', '-certfile', '@INPUT2@', '-out', '@OUTPUT@', '-export',
++      '-passout', 'pass:abc', '-certpbe', 'PBE-SHA1-RC2-40', '-keypbe', 'PBE-SHA1-RC2-128', '-macalg', 'sha1', openssl_legacy ]
++  )
++
++  cert_entity_combined_pem_tgt = custom_target('cert-entity-combined.pem',
++    input: cert_entity_pkcs12_rc2_sha1_p12_tgt,
++    output: 'cert-entity-combined.pem',
++    command: [ openssl, 'pkcs12', '-in', '@INPUT@', '-out', '@OUTPUT@', '-passin', 'pass:abc', '-passout', 'pass:abc', openssl_legacy ]
++  )
++
++  gen_cert_expired_pem_sh = find_program('gen-cert-expired-pem.sh')
++  cert_expired_pem_tgt = custom_target('cert-expired.pem',
++    input: [ cert_expired_csr_tgt, cert_ca_pem_tgt, cert_ca_key_pem_tgt, cert_ca_cnf_tgt, files('gencerts.cnf') ],
++    output: 'cert-expired.pem',
++    command: [ gen_cert_expired_pem_sh, '@INPUT0@', '@INPUT1@', '@INPUT2@', '@INPUT3@', '@INPUT4@', '@OUTPUT@' ]
++  )
++
++  cert_entity_pkcs12_nomac_p12_tgt = custom_target('cert-entity-pkcs12-nomac.p12',
++    input: [ cert_entity_int_key_pem_tgt, cert_entity_int_pem_tgt ],
++    output: 'cert-entity-pkcs12-nomac.p12',
++    command: [ openssl, 'pkcs12', '-inkey', '@INPUT0@', '-in', '@INPUT1@', '-out', '@OUTPUT@', '-export', '-passout', 'pass:abc', '-nomac' ]
++  )
++
++  cert_entity_pkcs12_des_sha256_p12_tgt = custom_target('cert-entity-pkcs12-des-sha256.p12',
++    input: [ cert_entity_int_key_pem_tgt, cert_entity_int_pem_tgt, cert_chain_pem_tgt ],
++    output: 'cert-entity-pkcs12-des-sha256.p12',
++    command: [ openssl, 'pkcs12', '-inkey', '@INPUT0@', '-in', '@INPUT1@', '-certfile', '@INPUT2@', '-out', '@OUTPUT@', '-export',
++      '-passout', 'pass:abc', '-certpbe', 'PBE-SHA1-3DES', '-keypbe', 'PBE-SHA1-2DES', '-macalg', 'sha256' ]
++  )
++
++  cert_entity_pkcs12_rc4_sha384_p12_tgt = custom_target('cert-entity-pkcs12-rc4-sha384.p12',
++    input: [ cert_entity_int_key_pem_tgt, cert_entity_int_pem_tgt, cert_chain_pem_tgt ],
++    output: 'cert-entity-pkcs12-rc4-sha384.p12',
++    command: [ openssl, 'pkcs12', '-inkey', '@INPUT0@', '-in', '@INPUT1@', '-certfile', '@INPUT2@', '-out', '@OUTPUT@', '-export',
++      '-passout', 'pass:abc', '-certpbe', 'PBE-SHA1-RC4-128', '-keypbe', 'PBE-SHA1-RC2-40', '-macalg', 'sha384', openssl_legacy ]
++  )
++
++  cert_entity_pkcs12_pkcs5_sha512_p12_tgt = custom_target('cert-entity-pkcs12-pkcs5-sha512.p12',
++    input: [ cert_entity_int_key_pem_tgt, cert_entity_int_pem_tgt, cert_chain_pem_tgt ],
++    output: 'cert-entity-pkcs12-pkcs5-sha512.p12',
++    command: [ openssl, 'pkcs12', '-inkey', '@INPUT0@', '-in', '@INPUT1@', '-certfile', '@INPUT2@', '-out', '@OUTPUT@', '-export',
++      '-passout', 'pass:abc', '-certpbe', 'des-cbc', '-keypbe', 'des-cbc', '-macalg', 'sha512', openssl_legacy ]
++  )
++
++  key_ciphertext_dat_tgt = custom_target('key-ciphertext.dat',
++    input: [ 'plaintext.txt', cert_client_pem_tgt ],
++    output: 'key-ciphertext.dat',
++    command: [ openssl, 'rsautl', '-encrypt', '-pkcs', '-in', '@INPUT0@', '-certin',
++      '-inkey', '@INPUT1@', '-out', '@OUTPUT@' ]
++  )
++
++  key_signature_dat_tgt = custom_target('key-signature.dat',
++    input: 'plaintext.txt',
++    output: 'key-signature.dat',
++    command: [ openssl, 'rsautl', '-sign', '-pkcs', '-in', '@INPUT@',
++      '-inkey', cert_client_key_pkcs1_pem_tgt, '-out', '@OUTPUT@' ]
++  )
++
++  pem_rsa_files = [
++    [ 'cert-client-key-pkcs1-des3.pem', '-des3' ],
++    [ 'cert-client-key-pkcs1-aes128.pem', '-aes128' ],
++    [ 'cert-client-key-pkcs1-aes192.pem', '-aes192' ],
++    [ 'cert-client-key-pkcs1-aes256.pem', '-aes256' ],
++  ]
++
++  foreach file: pem_rsa_files
++    test_pem_cert_deps += custom_target(file[0],
++      input: cert_client_key_pkcs1_pem_tgt,
++      output: file[0],
++      command: [ openssl, 'rsa', '-in', '@INPUT@', '-out', '@OUTPUT@', file[1], '-passout', 'pass:abc' ]
++    )
++  endforeach
++
++  built_headers = [
++    [ 'plaintext.txt', 'key-plaintext.h' ],
++    [ key_ciphertext_dat_tgt, 'key-ciphertext.h' ],
++    [ key_signature_dat_tgt, 'key-signature.h' ]
++  ]
++
++  xxd_sh = find_program('xxd.sh')
++
++  foreach header: built_headers
++    gen_headers += custom_target(header[1],
++      input: header[0],
++      output: header[1],
++      command: [ xxd_sh,'@INPUT@', '@OUTPUT@' ]
++    )
++  endforeach
++
++  cert_verifs = [
++    [ cert_server_pem_tgt, cert_ca_pem_tgt ],
++    [ ec_cert_server_pem_tgt, ec_cert_ca_pem_tgt ],
++    [ cert_client_pem_tgt, cert_ca_pem_tgt ],
++    [ cert_intca_pem_tgt, cert_ca_pem_tgt ],
++    [ cert_entity_int_pem_tgt, cert_chain_pem_tgt ],
++    [ cert_no_keyid_pem_tgt, cert_ca2_pem_tgt ]
++  ]
++  foreach cert_verif: cert_verifs
++    test(cert_verif[0].full_path() + '-verify',
++      openssl,
++      args: [ 'verify', '-CAfile', cert_verif[1].full_path(), cert_verif[0].full_path() ]
++    )
++  endforeach
++
++  test_pem_cert_deps += [
++    # test_pem
++    cert_client_key_pkcs8_md5_des_pem_tgt,
++    cert_client_key_pkcs8_sha1_des_pem_tgt,
++    cert_client_key_pkcs8_v2_des_pem_tgt,
++    cert_client_key_pkcs8_v2_des_ede3_pem_tgt,
++    cert_client_key_pkcs8_v2_aes128_pem_tgt,
++    cert_client_key_pkcs8_v2_aes256_pem_tgt,
++    cert_client_key_pkcs1_des_pem_tgt,
++    cert_client_key_pkcs1_pem_tgt,
++    cert_client_key_pkcs1_des_pem_tgt,
++    cert_client_key_pkcs8_pem_tgt,
++    cert_client_key_pkcs8_sha1_des_pem_tgt,
++    cert_client_pem_tgt,
++    cert_client_crt_tgt,
++    cert_entity_combined_pem_tgt,
++    cert_entity_pkcs12_nomac_p12_tgt,
++    cert_entity_pkcs12_rc2_sha1_p12_tgt,
++    cert_entity_pkcs12_des_sha256_p12_tgt,
++    cert_entity_pkcs12_rc4_sha384_p12_tgt,
++    cert_entity_pkcs12_pkcs5_sha512_p12_tgt,
++    # test_key
++    cert_ca_pem_tgt,
++    cert_server_pem_tgt,
++    cert_intca_pem_tgt,
++    cert_entity_int_pem_tgt,
++    cert_client_pem_tgt,
++    cert_client_key_pkcs8_pem_tgt,
++    # test_tls
++    cert_chain_pem_tgt,
++    cert_expired_pem_tgt,
++    cert_ca2_pem_tgt,
++    cert_no_keyid_pem_tgt,
++    ec_cert_ca_pem_tgt,
++    ec_cert_server_pem_tgt,
++    cert_server_key_pkcs8_pem_tgt
++  ]
++endif
++
++# Mocking l_getrandom() to get a stable random seed
++libell_private_ecdh_dep = declare_dependency(
++  link_with: libell_private,
++  link_args: '-Wl,-wrap,l_getrandom'
++)
++
++if get_option('tests') or get_option('cert-tests')
++  foreach test_name: tests
++    dep = test_name == 'test-ecdh' ? libell_private_ecdh_dep : libell_private_dep
++    exe = executable(test_name,
++      [ '@0@.c'.format(test_name), gen_headers, test_pem_cert_deps ],
++      include_directories: include_directories('..'),
++      c_args: [
++        '-DUNITDIR="@0@/unit/"'.format(meson.project_source_root()),
++        '-DCERTDIR="@0@/unit/"'.format(meson.project_build_root())
++      ],
++      dependencies: dep,
++      install: false
++    )
++
++    test(test_name, exe,
++      protocol: 'tap')
++  endforeach
++endif
+diff --git a/unit/xxd.sh b/unit/xxd.sh
+new file mode 100755
+index 000000000000..3fd26d2bce90
+--- /dev/null
++++ b/unit/xxd.sh
+@@ -0,0 +1,3 @@
++#!/bin/sh
++
++xxd -i < "$1" > "$2"
+-- 
+2.52.0
+
-- 
2.54.0


^ permalink raw reply related

* [BlueZ v10 03/16] build: Add support for building with libical 4.x
From: Bastien Nocera @ 2026-05-05  8:45 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <20260505085741.2497401-1-hadess@hadess.net>

Some functions were moved to libicalvcal, use that library if we're
building against libical 4.0 or newer.

See https://github.com/bluez/bluez/issues/2090
---
 meson.build       | 6 ++++++
 obexd/meson.build | 1 +
 2 files changed, 7 insertions(+)

diff --git a/meson.build b/meson.build
index d3c43d79141f..15508a868636 100644
--- a/meson.build
+++ b/meson.build
@@ -134,6 +134,12 @@ cups_dep = dependency('cups', required: get_option('cups'))
 jsonc_dep = dependency('json-c', version: '>= 0.13', required: get_option('mesh'))
 alsa_dep = dependency('alsa', required: get_option('midi'))
 ical_dep = dependency('libical', required: get_option('obex'))
+ical4_dep = dependency('libical', version: '>= 4.0', required: false)
+if ical_dep.found() and ical4_dep.found()
+  icalvcal_dep = dependency('libicalvcal', required: get_option('obex'))
+else
+  icalvcal_dep = dummy_dep
+endif
 readline_dep = dependency('readline',
   required: get_option('client').enabled() or
     get_option('mesh').enabled())
diff --git a/obexd/meson.build b/obexd/meson.build
index baddafcd8873..2270a10cb423 100644
--- a/obexd/meson.build
+++ b/obexd/meson.build
@@ -100,6 +100,7 @@ executable('obexd',
     libgdbus_internal_dep,
     libshared_glib_dep,
     ical_dep,
+    icalvcal_dep,
     dbus_dep,
     ebook_dep,
     edataserver_dep,
-- 
2.54.0


^ permalink raw reply related

* [BlueZ v10 00/16] Add meson build system and HTML docs
From: Bastien Nocera @ 2026-05-05  8:45 UTC (permalink / raw)
  To: linux-bluetooth

Changes since v9:
- Removed docs reference to hcidump
- Fix build with libical 4.x
- Fix build problems caused by RAP-related changes

Bastien Nocera (15):
  build: Add meson wrap for libell
  build: Add meson build system
  build: Add support for building with libical 4.x
  build: Separate systemd and libsystemd dependencies
  tools: Install gatttool if deprecated tools are enabled
  tools: Install avinfo tool by default
  emulator: Install the emulator if built
  build: Add option to allow disabling bluetoothd
  unit: Run test-bap tests concurrently
  unit: Make gobex-transfer tests run concurrently
  build: Only build profiles if the daemon is built
  build: Only build gdbus library if there is a user
  unit: Add integration tests
  doc: Add HTML documentation
  github: Add docs deployment

Paul Otto (1):
  doc: Add introduction to GATT

 .github/workflows/docs.yml                    |  54 +
 attrib/meson.build                            |  17 +
 btio/meson.build                              |   1 +
 client/btpclient/meson.build                  |  20 +
 client/meson.build                            |  33 +
 completion/meson.build                        |   3 +
 doc/_static/bluez.css                         | 452 +++++++++
 doc/_static/bluez.png                         | Bin 0 -> 18354 bytes
 doc/_static/bullet.svg                        |   1 +
 doc/_static/card.png                          | Bin 0 -> 35387 bytes
 doc/_static/figtree.woff2                     | Bin 0 -> 14364 bytes
 doc/_static/toc_bullet.svg                    |  39 +
 doc/bluetoothctl-cmd.rst                      |  34 +
 doc/conf.py                                   |  39 +
 doc/copy-subdir.py                            |  14 +
 doc/daemons.rst                               |  12 +
 doc/dbus-gatt.rst                             |  20 +
 doc/dbus-obex.rst                             |  33 +
 doc/dbus.rst                                  |  76 ++
 doc/deprecated-tools.rst                      |  21 +
 doc/dev-maint.rst                             |  17 +
 doc/favicon.ico                               | Bin 0 -> 29152 bytes
 doc/gatt-intro.rst                            | 141 +++
 doc/index.rst                                 |  47 +
 doc/meson.build                               | 293 ++++++
 doc/protocols.rst                             |  22 +
 doc/qualifications.rst                        |  76 ++
 doc/tools.rst                                 |  24 +
 emulator/meson.build                          |  36 +
 gdbus/meson.build                             |  19 +
 gobex/meson.build                             |   8 +
 lib/meson.build                               |  53 +
 mesh/meson.build                              |  60 ++
 meson.build                                   | 329 +++++++
 meson_options.txt                             |  55 ++
 monitor/meson.build                           |  37 +
 obexd/meson.build                             | 122 +++
 peripheral/meson.build                        |  13 +
 plugins/meson.build                           |  29 +
 profiles/meson.build                          | 168 ++++
 src/meson.build                               |  90 ++
 src/shared/meson.build                        |  85 ++
 subprojects/ell.wrap                          |  11 +
 .../0001-build-Add-meson-build-system.patch   | 922 ++++++++++++++++++
 test/meson.build                              |  37 +
 tools/mesh/meson.build                        |  16 +
 tools/meson.build                             | 262 +++++
 tools/mpris-proxy.service.in                  |   2 +-
 unit/integration-test-skipped.sh              |   3 +
 unit/integration-test.py                      | 271 +++++
 unit/meson.build                              | 194 ++++
 unit/output_checker.py                        | 214 ++++
 unit/unittest_inspector.py                    |  46 +
 unit/unittest_list.sh                         |  15 +
 54 files changed, 4585 insertions(+), 1 deletion(-)
 create mode 100644 .github/workflows/docs.yml
 create mode 100644 attrib/meson.build
 create mode 100644 btio/meson.build
 create mode 100644 client/btpclient/meson.build
 create mode 100644 client/meson.build
 create mode 100644 completion/meson.build
 create mode 100644 doc/_static/bluez.css
 create mode 100644 doc/_static/bluez.png
 create mode 100644 doc/_static/bullet.svg
 create mode 100644 doc/_static/card.png
 create mode 100644 doc/_static/figtree.woff2
 create mode 100644 doc/_static/toc_bullet.svg
 create mode 100644 doc/bluetoothctl-cmd.rst
 create mode 100644 doc/conf.py
 create mode 100644 doc/copy-subdir.py
 create mode 100644 doc/daemons.rst
 create mode 100644 doc/dbus-gatt.rst
 create mode 100644 doc/dbus-obex.rst
 create mode 100644 doc/dbus.rst
 create mode 100644 doc/deprecated-tools.rst
 create mode 100644 doc/dev-maint.rst
 create mode 100644 doc/favicon.ico
 create mode 100644 doc/gatt-intro.rst
 create mode 100644 doc/index.rst
 create mode 100644 doc/meson.build
 create mode 100644 doc/protocols.rst
 create mode 100644 doc/qualifications.rst
 create mode 100644 doc/tools.rst
 create mode 100644 emulator/meson.build
 create mode 100644 gdbus/meson.build
 create mode 100644 gobex/meson.build
 create mode 100644 lib/meson.build
 create mode 100644 mesh/meson.build
 create mode 100644 meson.build
 create mode 100644 meson_options.txt
 create mode 100644 monitor/meson.build
 create mode 100644 obexd/meson.build
 create mode 100644 peripheral/meson.build
 create mode 100644 plugins/meson.build
 create mode 100644 profiles/meson.build
 create mode 100644 src/meson.build
 create mode 100644 src/shared/meson.build
 create mode 100644 subprojects/ell.wrap
 create mode 100644 subprojects/packagefiles/0001-build-Add-meson-build-system.patch
 create mode 100644 test/meson.build
 create mode 100644 tools/mesh/meson.build
 create mode 100644 tools/meson.build
 create mode 100755 unit/integration-test-skipped.sh
 create mode 100755 unit/integration-test.py
 create mode 100644 unit/meson.build
 create mode 100644 unit/output_checker.py
 create mode 100755 unit/unittest_inspector.py
 create mode 100644 unit/unittest_list.sh

-- 
2.54.0


^ permalink raw reply

* [bluez/bluez] 897689: mpris-proxy: Fix possible crash
From: hadess @ 2026-05-05  8:33 UTC (permalink / raw)
  To: linux-bluetooth

  Branch: refs/heads/1089698
  Home:   https://github.com/bluez/bluez
  Commit: 897689ffe9c0ac36fbd508b9d754a557d1ee84be
      https://github.com/bluez/bluez/commit/897689ffe9c0ac36fbd508b9d754a557d1ee84be
  Author: Bastien Nocera <hadess@hadess.net>
  Date:   2026-05-05 (Tue, 05 May 2026)

  Changed paths:
    M tools/mpris-proxy.c

  Log Message:
  -----------
  mpris-proxy: Fix possible crash

find_player_by_obex() doesn't check whether session->obex is a valid
pointer before dereferecing it, but all code paths that assign it use
create_obex_session() to assign it, a function that can fail.

Check whether session->obex is null before dereferencing it.

 #0 find_player_by_obex at tools/mpris-proxy.c:2819
 #1 obex_property_changed at tools/mpris-proxy.c:2929
 #2 add_property at gdbus/client.c:373
 #3 update_properties at gdbus/client.c:399
 #5 properties_changed at gdbus/client.c:537
 #6 signal_filter at gdbus/watch.c:416
 #7 message_filter at gdbus/watch.c:566
 #10 message_dispatch at gdbus/mainloop.c:59
 #13 g_main_context_dispatch_unlocked at ../glib/gmain.c:4451
 #14 g_main_context_iterate_unlocked at ../glib/gmain.c:4516

Closes: https://bugzilla.redhat.com/show_bug.cgi?id=2466640


  Commit: 79975d8d2f524ad50eb840c5137eb80a45aa6ea8
      https://github.com/bluez/bluez/commit/79975d8d2f524ad50eb840c5137eb80a45aa6ea8
  Author: Bastien Nocera <hadess@hadess.net>
  Date:   2026-05-05 (Tue, 05 May 2026)

  Changed paths:
    M tools/mpris-proxy.c

  Log Message:
  -----------
  mpris-proxy: Avoid session->obex dereference

Protect against trying to access session->obex variable that might be
null after failure to create the session object.


Compare: https://github.com/bluez/bluez/compare/897689ffe9c0%5E...79975d8d2f52

To unsubscribe from these emails, change your notification settings at https://github.com/bluez/bluez/settings/notifications

^ permalink raw reply

* [BlueZ 1/2] mpris-proxy: Fix possible crash
From: Bastien Nocera @ 2026-05-05  7:29 UTC (permalink / raw)
  To: linux-bluetooth

find_player_by_obex() doesn't check whether session->obex is a valid
pointer before dereferecing it, but all code paths that assign it use
create_obex_session() to assign it, a function that can fail.

Check whether session->obex is null before dereferencing it.

 #0 find_player_by_obex at tools/mpris-proxy.c:2819
 #1 obex_property_changed at tools/mpris-proxy.c:2929
 #2 add_property at gdbus/client.c:373
 #3 update_properties at gdbus/client.c:399
 #5 properties_changed at gdbus/client.c:537
 #6 signal_filter at gdbus/watch.c:416
 #7 message_filter at gdbus/watch.c:566
 #10 message_dispatch at gdbus/mainloop.c:59
 #13 g_main_context_dispatch_unlocked at ../glib/gmain.c:4451
 #14 g_main_context_iterate_unlocked at ../glib/gmain.c:4516

Closes: https://bugzilla.redhat.com/show_bug.cgi?id=2466640
---
 tools/mpris-proxy.c | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/tools/mpris-proxy.c b/tools/mpris-proxy.c
index 1d7a421e9278..360b8ab34469 100644
--- a/tools/mpris-proxy.c
+++ b/tools/mpris-proxy.c
@@ -2816,8 +2816,12 @@ static struct player *find_player_by_obex(const char *path)
 	for (l = players; l; l = l->next) {
 		struct player *player = l->data;
 		struct obex_session *session = player->obex;
-		const char *obex_path = g_dbus_proxy_get_path(session->obex);
+		const char *obex_path = NULL;
 
+		if (session == NULL)
+			continue;
+
+		obex_path= g_dbus_proxy_get_path(session->obex);
 		if (g_str_has_prefix(path, obex_path))
 			return player;
 	}
-- 
2.54.0


^ permalink raw reply related

* [BlueZ 2/2] mpris-proxy: Avoid session->obex dereference
From: Bastien Nocera @ 2026-05-05  7:29 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <20260505072958.2424004-1-hadess@hadess.net>

Protect against trying to access session->obex variable that might be
null after failure to create the session object.
---
 tools/mpris-proxy.c | 10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/tools/mpris-proxy.c b/tools/mpris-proxy.c
index 360b8ab34469..8c9b01044fe2 100644
--- a/tools/mpris-proxy.c
+++ b/tools/mpris-proxy.c
@@ -1306,7 +1306,7 @@ static int parse_track_entry(DBusMessageIter *entry, const char *key,
 		const char *handle, *path;
 		char *filename, *uri;
 
-		if (!player || !player->obex)
+		if (!player || !player->obex || !player->obex->obex)
 			return -EINVAL;
 
 		path = g_dbus_proxy_get_path(player->obex->obex);
@@ -2614,9 +2614,13 @@ static void obex_get_image(struct player *player, const char *handle)
 	DBusMessage *msg;
 	DBusMessageIter iter, array;
 	struct obex_session *obex_session = player->obex;
-	const char *path = g_dbus_proxy_get_path(obex_session->obex);
+	const char *path;
 	char *filename;
 
+	if (!player->obex)
+		return;
+
+	path = g_dbus_proxy_get_path(obex_session->obex);
 	player->filename = g_strconcat(g_get_tmp_dir(), "/",
 				path + strlen(BLUEZ_OBEX_CLIENT_PATH "/"),
 				"-", handle, NULL);
@@ -2674,7 +2678,7 @@ static void device_property_changed(GDBusProxy *proxy, const char *name,
 			player->obex = NULL;
 	}
 
-	g_dbus_proxy_unref(session->obex);
+	g_clear_pointer(&session->obex, g_dbus_proxy_unref);
 	g_dbus_proxy_unref(session->device);
 	obex_sessions = g_slist_remove(obex_sessions, session);
 	g_free(session);
-- 
2.54.0


^ permalink raw reply related

* RE: bluetooth hci0: Direct firmware load for rtl_bt/rtl8761a_config.bin failed with error -2
From: Zenm Chen @ 2026-05-05  7:25 UTC (permalink / raw)
  To: max.chou; +Cc: hildawu, linux-bluetooth, pkshih, zenmchen
In-Reply-To: <d6274785e3644bfbb0bf6a3c6a6bbff3@realtek.com>

Max Chou <max.chou@realtek.com> 於 2026年4月30日週四 上午10:22寫道:
>
> Hi!
> The config file rtl8761a_config is not mandatory. In ic_id_table[],
> .config_needed is indeed set to false. Please rest assured regarding
> this matter.
> If you would like to fix the warning message, it would be good to
> send a patch to add rtl8761a_config.bin containing only the header
> to the linux-firmware repository.
>
> BRs,
> Max
>

Hi Max,

Thank you for the clarification! After adding an empty config file,
Bluetooth is working as usual and the error message doesn't appear anymore.

$ od -t x1 /lib/firmware/rtl_bt/rtl8761bu_config.bin 
0000000 55 ab 23 87 00 00
0000006

$ ls /lib/firmware/rtl_bt/rtl8761{a,bu}_config.bin 
lrwxrwxrwx 1 root root 20 Apr 30 22:24 /lib/firmware/rtl_bt/rtl8761a_config.bin -> rtl8761bu_config.bin
-rw-r--r-- 1 root root  6 Mar  5 01:40 /lib/firmware/rtl_bt/rtl8761bu_config.bin

$ dmesg
[  550.038863] Bluetooth: Core ver 2.22
[  550.038897] NET: Registered PF_BLUETOOTH protocol family
[  550.038899] Bluetooth: HCI device and connection manager initialized
[  550.038904] Bluetooth: HCI socket layer initialized
[  550.038906] Bluetooth: L2CAP socket layer initialized
[  550.038910] Bluetooth: SCO socket layer initialized
[  550.070541] usbcore: registered new interface driver btusb
[  550.077485] Bluetooth: hci0: RTL: examining hci_ver=06 hci_rev=000a lmp_ver=06 lmp_subver=8761
[  550.079510] Bluetooth: hci0: RTL: rom_version status=0 version=3
[  550.081469] Bluetooth: hci0: RTL: btrtl_initialize: key id 0
[  550.081475] Bluetooth: hci0: RTL: loading rtl_bt/rtl8761a_fw.bin
[  550.083538] Bluetooth: hci0: RTL: loading rtl_bt/rtl8761a_config.bin
[  550.083853] Bluetooth: hci0: RTL: cfg_sz 6, total sz 22646
[  550.167668] Bluetooth: BNEP (Ethernet Emulation) ver 1.3
[  550.167674] Bluetooth: BNEP filters: protocol multicast
[  550.167679] Bluetooth: BNEP socket layer initialized
[  550.659710] Bluetooth: hci0: RTL: fw version 0x0e3e4380
[  550.800287] Bluetooth: MGMT ver 1.22
[  550.819174] NET: Registered PF_ALG protocol family
[  550.857408] Bluetooth: RFCOMM TTY layer initialized
[  550.857422] Bluetooth: RFCOMM socket layer initialized
[  550.857433] Bluetooth: RFCOMM ver 1.11

^ permalink raw reply

* [Bug 221449] Wireless gamepad stopped working through Bluetooth
From: bugzilla-daemon @ 2026-05-05  5:09 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <bug-221449-62941@https.bugzilla.kernel.org/>

https://bugzilla.kernel.org/show_bug.cgi?id=221449

The Linux kernel's regression tracker (Thorsten Leemhuis) (regressions@leemhuis.info) changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |regressions@leemhuis.info

--- Comment #2 from The Linux kernel's regression tracker (Thorsten Leemhuis) (regressions@leemhuis.info) ---
6.19.y is EOL. Does 7.0 work? Testing 7.1-rc2 would be good, too. And can you
please verify is it's really the kernel that broke things?

-- 
You may reply to this email to add a comment.

You are receiving this mail because:
You are the assignee for the bug.

^ permalink raw reply

* RE: [BlueZ,v1,1/2] monitor: Add features bits defined in 6.2
From: bluez.test.bot @ 2026-05-04 22:42 UTC (permalink / raw)
  To: linux-bluetooth, luiz.dentz
In-Reply-To: <20260504211303.1081876-1-luiz.dentz@gmail.com>

[-- Attachment #1: Type: text/plain, Size: 4726 bytes --]

This is automated email and please do not reply to this email!

Dear submitter,

Thank you for submitting the patches to the linux bluetooth mailing list.
This is a CI test results with your patch series:
PW Link:https://patchwork.kernel.org/project/bluetooth/list/?series=1089499

---Test result---

Test Summary:
CheckPatch                    FAIL      1.13 seconds
GitLint                       FAIL      0.70 seconds
BuildEll                      PASS      20.49 seconds
BluezMake                     PASS      656.66 seconds
MakeCheck                     PASS      0.95 seconds
MakeDistcheck                 PASS      245.58 seconds
CheckValgrind                 PASS      221.87 seconds
CheckSmatch                   WARNING   349.65 seconds
bluezmakeextell               PASS      182.14 seconds
IncrementalBuild              PASS      700.74 seconds
ScanBuild                     PASS      1031.74 seconds

Details
##############################
Test: CheckPatch - FAIL
Desc: Run checkpatch.pl script
Output:
[BlueZ,v1,1/2] monitor: Add features bits defined in 6.2
WARNING:COMMIT_LOG_LONG_LINE: Possible unwrapped commit description (prefer a maximum 75 chars per line)
#98: 
https://www.bluetooth.com/wp-content/uploads/Files/Specification/HTML/Core-62/out/en/low-energy-controller/link-layer-specification.html#UUID-56ada5ed-4ae3-acee-198f-27ead57d86f1

/github/workspace/src/patch/14553784.patch total: 0 errors, 1 warnings, 13 lines checked

NOTE: For some of the reported defects, checkpatch may be able to
      mechanically convert to the typical style using --fix or --fix-inplace.

/github/workspace/src/patch/14553784.patch has style problems, please review.

NOTE: Ignored message types: COMMIT_MESSAGE COMPLEX_MACRO CONST_STRUCT FILE_PATH_CHANGES MISSING_SIGN_OFF PREFER_PACKED SPDX_LICENSE_TAG SPLIT_STRING SSCANF_TO_KSTRTO

NOTE: If any of the errors are false positives, please report
      them to the maintainer, see CHECKPATCH in MAINTAINERS.


[BlueZ,v1,2/2] monitor: Add decoding for Short Connection Interval feature
WARNING:PREFER_DEFINED_ATTRIBUTE_MACRO: Prefer __packed over __attribute__((packed))
#140: FILE: monitor/bt.h:3212:
+} __attribute__ ((packed));

WARNING:PREFER_DEFINED_ATTRIBUTE_MACRO: Prefer __packed over __attribute__((packed))
#154: FILE: monitor/bt.h:3226:
+} __attribute__ ((packed));

WARNING:PREFER_DEFINED_ATTRIBUTE_MACRO: Prefer __packed over __attribute__((packed))
#162: FILE: monitor/bt.h:3234:
+} __attribute__ ((packed));

WARNING:PREFER_DEFINED_ATTRIBUTE_MACRO: Prefer __packed over __attribute__((packed))
#168: FILE: monitor/bt.h:3240:
+} __attribute__ ((packed));

WARNING:PREFER_DEFINED_ATTRIBUTE_MACRO: Prefer __packed over __attribute__((packed))
#186: FILE: monitor/bt.h:4209:
+} __attribute__ ((packed));

/github/workspace/src/patch/14553785.patch total: 0 errors, 5 warnings, 232 lines checked

NOTE: For some of the reported defects, checkpatch may be able to
      mechanically convert to the typical style using --fix or --fix-inplace.

/github/workspace/src/patch/14553785.patch has style problems, please review.

NOTE: Ignored message types: COMMIT_MESSAGE COMPLEX_MACRO CONST_STRUCT FILE_PATH_CHANGES MISSING_SIGN_OFF PREFER_PACKED SPDX_LICENSE_TAG SPLIT_STRING SSCANF_TO_KSTRTO

NOTE: If any of the errors are false positives, please report
      them to the maintainer, see CHECKPATCH in MAINTAINERS.


##############################
Test: GitLint - FAIL
Desc: Run gitlint
Output:
[BlueZ,v1,1/2] monitor: Add features bits defined in 6.2

WARNING: I3 - ignore-body-lines: gitlint will be switching from using Python regex 'match' (match beginning) to 'search' (match anywhere) semantics. Please review your ignore-body-lines.regex option accordingly. To remove this warning, set general.regex-style-search=True. More details: https://jorisroovers.github.io/gitlint/configuration/#regex-style-search
6: B1 Line exceeds max length (178>80): "https://www.bluetooth.com/wp-content/uploads/Files/Specification/HTML/Core-62/out/en/low-energy-controller/link-layer-specification.html#UUID-56ada5ed-4ae3-acee-198f-27ead57d86f1"
##############################
Test: CheckSmatch - WARNING
Desc: Run smatch tool with source
Output:
monitor/packet.c:2000:26: warning: Variable length array is used.monitor/packet.c: note: in included file:monitor/bt.h:3909:52: warning: array of flexible structuresmonitor/bt.h:3897:40: warning: array of flexible structuresmonitor/packet.c:2000:26: warning: Variable length array is used.monitor/packet.c: note: in included file:monitor/bt.h:3909:52: warning: array of flexible structuresmonitor/bt.h:3897:40: warning: array of flexible structures


https://github.com/bluez/bluez/pull/2095

---
Regards,
Linux Bluetooth


^ permalink raw reply

* [bluez/bluez] a253b2: monitor: Add features bits defined in 6.2
From: Luiz Augusto von Dentz @ 2026-05-04 21:44 UTC (permalink / raw)
  To: linux-bluetooth

  Branch: refs/heads/1089499
  Home:   https://github.com/bluez/bluez
  Commit: a253b232bc1d99cef96a5e4209cdc00495232829
      https://github.com/bluez/bluez/commit/a253b232bc1d99cef96a5e4209cdc00495232829
  Author: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
  Date:   2026-05-04 (Mon, 04 May 2026)

  Changed paths:
    M monitor/packet.c

  Log Message:
  -----------
  monitor: Add features bits defined in 6.2

This adds features bits defined as per core spec 6.2:
https://www.bluetooth.com/wp-content/uploads/Files/Specification/HTML/Core-62/out/en/low-energy-controller/link-layer-specification.html#UUID-56ada5ed-4ae3-acee-198f-27ead57d86f1


  Commit: 369b30708d77e0a20b68f99527d989fa0d79b80c
      https://github.com/bluez/bluez/commit/369b30708d77e0a20b68f99527d989fa0d79b80c
  Author: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
  Date:   2026-05-04 (Mon, 04 May 2026)

  Changed paths:
    M monitor/bt.h
    M monitor/packet.c

  Log Message:
  -----------
  monitor: Add decoding for Short Connection Interval feature

This adds deconding support for SCI related commands, command bits, event
event mask bit and feature bits:

Events:

HCI_LE_Connection_Rate_Change(0x37)

Commands:

HCI_LE_Connection_Rate_Request(0x20a1)
HCI_LE_Set_Default_Rate_Parameters(0x20a2)
HCI_LE_Read_Minimum_Supported_Connection_Interval(0x20a3)


Compare: https://github.com/bluez/bluez/compare/a253b232bc1d%5E...369b30708d77

To unsubscribe from these emails, change your notification settings at https://github.com/bluez/bluez/settings/notifications

^ permalink raw reply

* [PATCH BlueZ v1 2/2] monitor: Add decoding for Short Connection Interval feature
From: Luiz Augusto von Dentz @ 2026-05-04 21:13 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <20260504211303.1081876-1-luiz.dentz@gmail.com>

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

This adds deconding support for SCI related commands, command bits, event
event mask bit and feature bits:

Events:

HCI_LE_Connection_Rate_Change(0x37)

Commands:

HCI_LE_Connection_Rate_Request(0x20a1)
HCI_LE_Set_Default_Rate_Parameters(0x20a2)
HCI_LE_Read_Minimum_Supported_Connection_Interval(0x20a3)
---
 monitor/bt.h     |  54 ++++++++++++++++++++
 monitor/packet.c | 130 +++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 184 insertions(+)

diff --git a/monitor/bt.h b/monitor/bt.h
index 147b76537e97..60fe2efbf143 100644
--- a/monitor/bt.h
+++ b/monitor/bt.h
@@ -3196,6 +3196,49 @@ struct bt_hci_cmd_le_fsu {
 	uint8_t  types;
 } __attribute__ ((packed));
 
+#define BT_HCI_CMD_LE_CONN_RATE		0x20a1
+#define BT_HCI_BIT_LE_CONN_RATE		BT_HCI_CMD_BIT(48, 5)
+struct bt_hci_cmd_le_conn_rate {
+	uint16_t handle;
+	uint16_t interval_min;
+	uint16_t interval_max;
+	uint16_t subrate_min;
+	uint16_t subrate_max;
+	uint16_t max_latency;
+	uint16_t cont_num;
+	uint16_t supv_timeout;
+	uint16_t min_ce_len;
+	uint16_t max_ce_len;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_LE_SET_DEF_RATE		0x20a2
+#define BT_HCI_BIT_LE_SET_DEF_RATE		BT_HCI_CMD_BIT(48, 6)
+struct bt_hci_cmd_le_set_def_rate {
+	uint16_t interval_min;
+	uint16_t interval_max;
+	uint16_t subrate_min;
+	uint16_t subrate_max;
+	uint16_t max_latency;
+	uint16_t cont_num;
+	uint16_t supv_timeout;
+	uint16_t min_ce_len;
+	uint16_t max_ce_len;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_LE_READ_CONN_INTERVAL	0x20a3
+#define BT_HCI_BIT_LE_READ_CONN_INTERVAL	BT_HCI_CMD_BIT(48, 7)
+struct bt_hci_le_conn_interval_group {
+	uint16_t min;
+	uint16_t max;
+	uint16_t stride;
+} __attribute__ ((packed));
+
+struct bt_hci_rsp_le_read_conn_interval {
+	uint8_t  status;
+	uint8_t  num_grps;
+	struct bt_hci_le_conn_interval_group grps[0];
+} __attribute__ ((packed));
+
 #define BT_HCI_EVT_INQUIRY_COMPLETE		0x01
 struct bt_hci_evt_inquiry_complete {
 	uint8_t  status;
@@ -4154,6 +4197,17 @@ struct bt_hci_evt_le_fsu_complete {
 	uint8_t  types;
 } __attribute__ ((packed));
 
+#define BT_HCI_EVT_LE_CONN_RATE_CHANGE		0x37
+struct bt_hci_evt_le_conn_rate_change {
+	uint8_t  status;
+	uint16_t handle;
+	uint16_t interval;
+	uint16_t subrate;
+	uint16_t latency;
+	uint16_t cont_number;
+	uint16_t supv_timeout;
+} __attribute__ ((packed));
+
 #define BT_HCI_ERR_SUCCESS			0x00
 #define BT_HCI_ERR_UNKNOWN_COMMAND		0x01
 #define BT_HCI_ERR_UNKNOWN_CONN_ID		0x02
diff --git a/monitor/packet.c b/monitor/packet.c
index 4697eea099a9..a0bf7a70987e 100644
--- a/monitor/packet.c
+++ b/monitor/packet.c
@@ -2415,6 +2415,12 @@ static void print_rssi(int8_t rssi)
 	packet_print_rssi("RSSI", rssi);
 }
 
+static void print_slot_125u(const char *label, uint16_t value)
+{
+	 print_field("%s: %.3f msec (0x%4.4x)", label,
+				le16_to_cpu(value) * 0.125, le16_to_cpu(value));
+}
+
 static void print_slot_625(const char *label, uint16_t value)
 {
 	 print_field("%s: %.3f msec (0x%4.4x)", label,
@@ -3341,6 +3347,8 @@ static const struct bitfield_data events_le_table[] = {
 	{ 50, "LE CS Test End Complete"			},
 	{ 51, "LE Monitored Advertisers Report"		},
 	{ 52, "LE Frame Space Update Complete"		},
+	{ 53, "LE UTP Received"				},
+	{ 54, "LE Connection Rate Change"		},
 	{ }
 };
 
@@ -9836,6 +9844,89 @@ static void le_fsu_cmd(uint16_t index, const void *data, uint8_t size)
 	print_fsu_types(cmd->types);
 }
 
+static void le_conn_rate_cmd(uint16_t index, const void *data, uint8_t size)
+{
+	const struct bt_hci_cmd_le_conn_rate *cmd = data;
+
+	print_handle(cmd->handle);
+	print_slot_125u("Connection Interval Min", cmd->interval_min);
+	print_slot_125u("Connection Interval Max", cmd->interval_max);
+	print_field("Subrate Min: %u (0x%4.4x)",
+				le16_to_cpu(cmd->subrate_min),
+				le16_to_cpu(cmd->subrate_min));
+	print_field("Subrate Max: %u (0x%4.4x)",
+				le16_to_cpu(cmd->subrate_max),
+				le16_to_cpu(cmd->subrate_max));
+	print_field("Max Latency: %u (0x%4.4x)",
+				le16_to_cpu(cmd->max_latency),
+				le16_to_cpu(cmd->max_latency));
+	print_field("Continuation Number: %u (0x%4.4x)",
+				le16_to_cpu(cmd->cont_num),
+				le16_to_cpu(cmd->cont_num));
+	print_field("Supervision Timeout: %d ms (0x%4.4x)",
+				le16_to_cpu(cmd->supv_timeout) * 10,
+				le16_to_cpu(cmd->supv_timeout));
+	print_slot_125u("Minimum CE Length", cmd->min_ce_len);
+	print_slot_125u("Maximum CE Length", cmd->max_ce_len);
+}
+
+static void le_set_def_rate_cmd(uint16_t index, const void *data, uint8_t size)
+{
+	const struct bt_hci_cmd_le_set_def_rate *cmd = data;
+
+	print_slot_125u("Connection Interval Min", cmd->interval_min);
+	print_slot_125u("Connection Interval Max", cmd->interval_max);
+	print_field("Subrate Min: %u (0x%4.4x)",
+				le16_to_cpu(cmd->subrate_min),
+				le16_to_cpu(cmd->subrate_min));
+	print_field("Subrate Max: %u (0x%4.4x)",
+				le16_to_cpu(cmd->subrate_max),
+				le16_to_cpu(cmd->subrate_max));
+	print_field("Max Latency: %u (0x%4.4x)",
+				le16_to_cpu(cmd->max_latency),
+				le16_to_cpu(cmd->max_latency));
+	print_field("Continuation Number: %u (0x%4.4x)",
+				le16_to_cpu(cmd->cont_num),
+				le16_to_cpu(cmd->cont_num));
+	print_field("Supervision Timeout: %d ms (0x%4.4x)",
+				le16_to_cpu(cmd->supv_timeout) * 10,
+				le16_to_cpu(cmd->supv_timeout));
+	print_slot_125u("Minimum CE Length", cmd->min_ce_len);
+	print_slot_125u("Maximum CE Length", cmd->max_ce_len);
+}
+
+static void le_read_conn_interval_rsp(uint16_t index, const void *data,
+					uint8_t size)
+{
+	const struct bt_hci_rsp_le_read_conn_interval *rsp = data;
+	struct iovec iov;
+	uint8_t i;
+
+	print_status(rsp->status);
+	print_field("Number of Groups: %u", rsp->num_grps);
+
+	if (!rsp->num_grps)
+		return;
+
+	iov.iov_base = (void *)rsp->grps;
+	iov.iov_len = size - sizeof(*rsp);
+
+	for (i = 0; i < rsp->num_grps; i++) {
+		const struct bt_hci_le_conn_interval_group *grp;
+
+		grp = util_iov_pull(&iov, sizeof(*grp));
+		if (!grp) {
+			print_text(COLOR_ERROR, "  invalid group");
+			break;
+		}
+
+		print_field("Group %u:", i);
+		print_slot_125u("  Interval Min", grp->min);
+		print_slot_125u("  Interval Max", grp->max);
+		print_slot_125u("  Interval Stride", grp->stride);
+	}
+}
+
 struct opcode_data {
 	uint16_t opcode;
 	int bit;
@@ -10907,6 +10998,21 @@ static const struct opcode_data opcode_table[] = {
 				"LE Frame Space Update", le_fsu_cmd,
 				sizeof(struct bt_hci_cmd_le_fsu),
 				true, status_rsp, 1, true },
+	{ BT_HCI_CMD_LE_CONN_RATE, BT_HCI_BIT_LE_CONN_RATE,
+				"LE Connection Rate Request", le_conn_rate_cmd,
+				sizeof(struct bt_hci_cmd_le_conn_rate),
+				true, status_rsp, 1, true },
+	{ BT_HCI_CMD_LE_SET_DEF_RATE, BT_HCI_BIT_LE_SET_DEF_RATE,
+				"LE Set Default Rate Parameteres",
+				le_set_def_rate_cmd,
+				sizeof(struct bt_hci_cmd_le_set_def_rate),
+				true, status_rsp, 1, true },
+	{ BT_HCI_CMD_LE_READ_CONN_INTERVAL,
+				BT_HCI_BIT_LE_READ_CONN_INTERVAL,
+				"LE Read Minimum Supported Connection Interval",
+				null_cmd, 0, true, le_read_conn_interval_rsp,
+				sizeof(struct bt_hci_rsp_le_read_conn_interval),
+				true },
 	{ }
 };
 
@@ -13400,6 +13506,26 @@ static void le_fsu_evt(struct timeval *tv, uint16_t index,
 	print_fsu_types(evt->types);
 }
 
+static void le_conn_rate_change_evt(struct timeval *tv, uint16_t index,
+					const void *data, uint8_t size)
+{
+	const struct bt_hci_evt_le_conn_rate_change *evt = data;
+
+	print_handle(evt->handle);
+	print_slot_125u("Connection Interval", le16_to_cpu(evt->interval));
+	print_field("Subrate Factor: %u (0x%4.4x)", le16_to_cpu(evt->subrate),
+					le16_to_cpu(evt->subrate));
+	print_field("Peripheral Latency: %u (0x%4.4x)",
+					le16_to_cpu(evt->latency),
+					le16_to_cpu(evt->latency));
+	print_field("Continuation Number: %u (0x%4.4x)",
+					le16_to_cpu(evt->cont_number),
+					le16_to_cpu(evt->cont_number));
+	print_field("Supervision Timeout: %u ms (0x%4.4X)",
+					le16_to_cpu(evt->supv_timeout),
+					le16_to_cpu(evt->supv_timeout));
+}
+
 struct subevent_data {
 	uint8_t subevent;
 	const char *str;
@@ -13566,6 +13692,10 @@ static const struct subevent_data le_meta_event_table[] = {
 	{ BT_HCI_EVT_LE_FSU_COMPLETE,
 		"LE Frame Space Update Complete",
 		le_fsu_evt, sizeof(struct bt_hci_evt_le_fsu_complete) },
+	{ BT_HCI_EVT_LE_CONN_RATE_CHANGE,
+		"LE Connection Rate Change",
+		le_conn_rate_change_evt,
+		sizeof(struct bt_hci_evt_le_conn_rate_change) },
 	{ }
 };
 
-- 
2.53.0


^ permalink raw reply related

* [PATCH BlueZ v1 1/2] monitor: Add features bits defined in 6.2
From: Luiz Augusto von Dentz @ 2026-05-04 21:13 UTC (permalink / raw)
  To: linux-bluetooth

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

This adds features bits defined as per core spec 6.2:
https://www.bluetooth.com/wp-content/uploads/Files/Specification/HTML/Core-62/out/en/low-energy-controller/link-layer-specification.html#UUID-56ada5ed-4ae3-acee-198f-27ead57d86f1
---
 monitor/packet.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/monitor/packet.c b/monitor/packet.c
index 177ec80a8975..4697eea099a9 100644
--- a/monitor/packet.c
+++ b/monitor/packet.c
@@ -2894,6 +2894,13 @@ static const struct bitfield_data features_le_0[] = {
 static const struct bitfield_data features_le_1[] = {
 	{ 0, "Monitoring Advertisers"				},
 	{ 1, "Frame Space Update"				},
+	{ 2, "UTP OTA Mode"					},
+	{ 3, "UTP HCI Pairing"					},
+	{ 4, "LL_OTA_UTP_IND maximum length"			},
+	{ 5, "LL_OTA_UTP_IND maximum length"			},
+	{ 8, "Shorter Connection Intervals"			},
+	{ 9, "Shorter Connection Intervals (Host Support)"	},
+	{ 10, "LE Flushable ACL Data"				},
 };
 
 static const struct bitfield_data features_msft[] = {
-- 
2.53.0


^ permalink raw reply related

* Re: [PATCH v2] sysfs: return -ENOENT from move/rename when kobj->sd is NULL
From: Danilo Krummrich @ 2026-05-04 20:55 UTC (permalink / raw)
  To: Conor Kotwasinski
  Cc: Greg Kroah-Hartman, Rafael J . Wysocki, driver-core, linux-kernel,
	linux-bluetooth, syzbot+d1db96f72a452dc9cbd2,
	syzbot+faeac5b54ba997a96278
In-Reply-To: <20260504050736.17672-1-conorkotwasinski2024@u.northwestern.edu>

On Mon May 4, 2026 at 7:07 AM CEST, Conor Kotwasinski wrote:
> sysfs_move_dir_ns() and sysfs_rename_dir_ns() pass kobj->sd to
> kernfs_rename_ns() unconditionally. If sysfs_remove_dir() has already
> cleared kobj->sd, the NULL flows through and kernfs_rename_ns()
> dereferences it via rcu_access_pointer(kn->__parent), which KASAN
> surfaces as a stack-segment fault on the shadow lookup:
>
>   Oops: stack segment: 0000 [#1] SMP KASAN PTI
>   RIP: 0010:kernfs_rename_ns+0x3a/0x7a0 fs/kernfs/dir.c:1752
>   Call Trace:
>    kobject_move+0x525/0x6e0 lib/kobject.c:569
>    device_move+0xe0/0x730 drivers/base/core.c:4606
>    hci_conn_del_sysfs+0xb8/0x1a0 net/bluetooth/hci_sysfs.c:75
>    hci_conn_cleanup net/bluetooth/hci_conn.c:173 [inline]
>    hci_conn_del+0xc36/0x1240 net/bluetooth/hci_conn.c:1234
>    hci_conn_hash_flush+0x191/0x260 net/bluetooth/hci_conn.c:2638
>    hci_dev_close_sync+0x821/0x1100 net/bluetooth/hci_sync.c:5327
>    hci_dev_do_close net/bluetooth/hci_core.c:501 [inline]
>    hci_unregister_dev+0x21a/0x5b0 net/bluetooth/hci_core.c:2715
>
> syzbot has reported 35 hits with this signature across net, net-next
> and linux-next between July 2025 and January 2026, via both vhci
> release and HCIDEVRESET ioctl.
>
> Return -ENOENT in that case, consistent with sysfs_create_dir_ns().
> The underlying ordering problem in bluetooth -- device_move() called
> after the target's sysfs has been torn down -- is a separate issue.
>
> Reported-by: syzbot+d1db96f72a452dc9cbd2@syzkaller.appspotmail.com
> Closes: https://lore.kernel.org/all/687c6966.a70a0220.693ce.00a5.GAE@google.com/
> Reported-by: syzbot+faeac5b54ba997a96278@syzkaller.appspotmail.com
> Closes: https://syzkaller.appspot.com/bug?extid=faeac5b54ba997a96278
> Fixes: 324a56e16e44 ("kernfs: s/sysfs_dirent/kernfs_node/ and rename its friends accordingly")

This is just a rename commit with no functional change, so I think we should
pick the following commit instead:

Fixes: 608e266a2d4e ("sysfs: make kobj point to sysfs_dirent instead of dentry")

However, that commit is quite old, so it raises a bit the question, why does
this pop up now?

Technically, the API contract only talks about callers have to serialize calls,
i.e. your if (!kobj->sd) check should not have any TOCTOU issues, but it does
not talk about ordering.

That said, why does the bluetooth API run into this now?

> Cc: stable@vger.kernel.org
> Signed-off-by: Conor Kotwasinski <conorkotwasinski2024@u.northwestern.edu>

Regardless of the above, the patch seems still fine even if it turns out to be
hardening only.

Reviewed-by: Danilo Krummrich <dakr@kernel.org>

^ permalink raw reply

* [bluez/bluez]
From: BluezTestBot @ 2026-05-04 20:42 UTC (permalink / raw)
  To: linux-bluetooth

  Branch: refs/heads/1089431
  Home:   https://github.com/bluez/bluez

To unsubscribe from these emails, change your notification settings at https://github.com/bluez/bluez/settings/notifications

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox