* [PATCH BlueZ] plugins: Add new plugin to fix airpods pairing
@ 2024-04-03 11:08 Frédéric Danis
2024-04-03 13:01 ` [BlueZ] " bluez.test.bot
2024-04-03 13:50 ` [PATCH BlueZ] " Szymon Janc
0 siblings, 2 replies; 4+ messages in thread
From: Frédéric Danis @ 2024-04-03 11:08 UTC (permalink / raw)
To: linux-bluetooth
Apple Airpods are discoverable and pairable in BREDR mode, but also
advertise in unconnectable mode in LE with the same Public address, at the
same time. As the pairing process uses the latest seen address, sometimes
it uses the LE Public address to pair, which fails.
This commit adds a new adapter driver plugin which force the BREDR last
seen time on LE Public address device found event related to an Apple
device, allowing pairing process to always use the BREDR.
This commit is based on proposal
https://lore.kernel.org/all/20240103101328.1812899-1-clancy_shang@163.com/
---
Makefile.plugins | 3 ++
plugins/airpods.c | 132 ++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 135 insertions(+)
create mode 100644 plugins/airpods.c
diff --git a/Makefile.plugins b/Makefile.plugins
index 4aa2c9c92..2ebd8aaf6 100644
--- a/Makefile.plugins
+++ b/Makefile.plugins
@@ -11,6 +11,9 @@ builtin_sources += plugins/autopair.c
builtin_modules += policy
builtin_sources += plugins/policy.c
+builtin_modules += airpods
+builtin_sources += plugins/airpods.c
+
if ADMIN
builtin_modules += admin
builtin_sources += plugins/admin.c
diff --git a/plugins/airpods.c b/plugins/airpods.c
new file mode 100644
index 000000000..5043f0cca
--- /dev/null
+++ b/plugins/airpods.c
@@ -0,0 +1,132 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2024 Frédéric Danis <frederic.danis@collabora.com>
+ *
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdbool.h>
+
+#include <glib.h>
+
+#include "bluetooth/bluetooth.h"
+
+#include "lib/mgmt.h"
+#include "src/plugin.h"
+#include "src/adapter.h"
+#include "src/device.h"
+#include "src/eir.h"
+#include "src/log.h"
+#include "src/shared/mgmt.h"
+#include "src/shared/util.h"
+
+#define APPLE_INC_VENDOR_ID 0x004c
+
+static struct mgmt *mgmt;
+
+static bool eir_msd_is_apple_inc(GSList *msd_list)
+{
+ GSList *msd_l, *msd_next;
+
+ for (msd_l = msd_list; msd_l != NULL; msd_l = msd_next) {
+ const struct eir_msd *msd = msd_l->data;
+
+ msd_next = g_slist_next(msd_l);
+
+ if (msd->company == APPLE_INC_VENDOR_ID)
+ return true;
+ }
+
+ return false;
+}
+
+static void airpods_device_found_callback(uint16_t index, uint16_t length,
+ const void *param, void *user_data)
+{
+ struct btd_device *dev;
+ const struct mgmt_ev_device_found *ev = param;
+ struct btd_adapter *adapter = user_data;
+ uint16_t eir_len;
+ uint32_t flags = le32_to_cpu(ev->flags);
+ struct eir_data eir_data;
+
+ dev = btd_adapter_find_device(adapter, &ev->addr.bdaddr,
+ ev->addr.type);
+ if (!dev)
+ return;
+
+ if (length < sizeof(*ev)) {
+ warn("Too short device found event (%u bytes)", length);
+ return;
+ }
+
+ eir_len = btohs(ev->eir_len);
+ if (length != sizeof(*ev) + eir_len) {
+ warn("Device found event size mismatch (%u != %zu)",
+ length, sizeof(*ev) + eir_len);
+ return;
+ }
+
+ if (eir_len == 0)
+ return;
+
+ memset(&eir_data, 0, sizeof(eir_data));
+ eir_parse(&eir_data, ev->eir, eir_len);
+
+ if (eir_msd_is_apple_inc(eir_data.msd_list) &&
+ (flags & MGMT_DEV_FOUND_NOT_CONNECTABLE) &&
+ (ev->addr.type == BDADDR_LE_PUBLIC)) {
+ DBG("Force BREDR last seen");
+ device_set_bredr_support(dev);
+ device_update_last_seen(dev, BDADDR_BREDR, true);
+ }
+}
+
+static int airpods_probe(struct btd_adapter *adapter)
+{
+ if (!mgmt)
+ mgmt = mgmt_new_default();
+
+ if (!mgmt) {
+ fprintf(stderr, "Failed to open management socket\n");
+ return 0;
+ }
+
+ mgmt_register(mgmt, MGMT_EV_DEVICE_FOUND,
+ btd_adapter_get_index(adapter),
+ airpods_device_found_callback,
+ adapter, NULL);
+
+ return 0;
+}
+
+static void airpods_remove(struct btd_adapter *adapter)
+{
+ mgmt_unregister_index(mgmt, btd_adapter_get_index(adapter));
+}
+
+static struct btd_adapter_driver airpods_driver = {
+ .name = "airpods",
+ .probe = airpods_probe,
+ .remove = airpods_remove,
+};
+
+static int airpods_init(void)
+{
+ return btd_register_adapter_driver(&airpods_driver);
+}
+
+static void airpods_exit(void)
+{
+ btd_unregister_adapter_driver(&airpods_driver);
+}
+
+BLUETOOTH_PLUGIN_DEFINE(airpods, VERSION,
+ BLUETOOTH_PLUGIN_PRIORITY_LOW, airpods_init, airpods_exit)
--
2.34.1
^ permalink raw reply related [flat|nested] 4+ messages in thread
* RE: [BlueZ] plugins: Add new plugin to fix airpods pairing
2024-04-03 11:08 [PATCH BlueZ] plugins: Add new plugin to fix airpods pairing Frédéric Danis
@ 2024-04-03 13:01 ` bluez.test.bot
2024-04-03 13:50 ` [PATCH BlueZ] " Szymon Janc
1 sibling, 0 replies; 4+ messages in thread
From: bluez.test.bot @ 2024-04-03 13:01 UTC (permalink / raw)
To: linux-bluetooth, frederic.danis
[-- Attachment #1: Type: text/plain, Size: 949 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=841054
---Test result---
Test Summary:
CheckPatch PASS 0.55 seconds
GitLint PASS 0.34 seconds
BuildEll PASS 24.87 seconds
BluezMake PASS 1668.80 seconds
MakeCheck PASS 13.49 seconds
MakeDistcheck PASS 178.87 seconds
CheckValgrind PASS 248.59 seconds
CheckSmatch PASS 351.49 seconds
bluezmakeextell PASS 120.29 seconds
IncrementalBuild PASS 1467.46 seconds
ScanBuild PASS 1018.85 seconds
---
Regards,
Linux Bluetooth
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH BlueZ] plugins: Add new plugin to fix airpods pairing
2024-04-03 11:08 [PATCH BlueZ] plugins: Add new plugin to fix airpods pairing Frédéric Danis
2024-04-03 13:01 ` [BlueZ] " bluez.test.bot
@ 2024-04-03 13:50 ` Szymon Janc
2024-04-03 16:35 ` Frédéric Danis
1 sibling, 1 reply; 4+ messages in thread
From: Szymon Janc @ 2024-04-03 13:50 UTC (permalink / raw)
To: Frédéric Danis; +Cc: linux-bluetooth
Hi,
On Wed, 3 Apr 2024 at 13:08, Frédéric Danis
<frederic.danis@collabora.com> wrote:
>
> Apple Airpods are discoverable and pairable in BREDR mode, but also
> advertise in unconnectable mode in LE with the same Public address, at the
> same time. As the pairing process uses the latest seen address, sometimes
> it uses the LE Public address to pair, which fails.
>
> This commit adds a new adapter driver plugin which force the BREDR last
> seen time on LE Public address device found event related to an Apple
> device, allowing pairing process to always use the BREDR.
>
While I'm fine with having plugin for this specific case, I wonder if
select_conn_bearer() shouldn't take
bearer's connectable state into account when selecting bearer for connection
> This commit is based on proposal
> https://lore.kernel.org/all/20240103101328.1812899-1-clancy_shang@163.com/
> ---
> Makefile.plugins | 3 ++
> plugins/airpods.c | 132 ++++++++++++++++++++++++++++++++++++++++++++++
> 2 files changed, 135 insertions(+)
> create mode 100644 plugins/airpods.c
>
> diff --git a/Makefile.plugins b/Makefile.plugins
> index 4aa2c9c92..2ebd8aaf6 100644
> --- a/Makefile.plugins
> +++ b/Makefile.plugins
> @@ -11,6 +11,9 @@ builtin_sources += plugins/autopair.c
> builtin_modules += policy
> builtin_sources += plugins/policy.c
>
> +builtin_modules += airpods
> +builtin_sources += plugins/airpods.c
> +
> if ADMIN
> builtin_modules += admin
> builtin_sources += plugins/admin.c
> diff --git a/plugins/airpods.c b/plugins/airpods.c
> new file mode 100644
> index 000000000..5043f0cca
> --- /dev/null
> +++ b/plugins/airpods.c
> @@ -0,0 +1,132 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + *
> + * BlueZ - Bluetooth protocol stack for Linux
> + *
> + * Copyright (C) 2024 Frédéric Danis <frederic.danis@collabora.com>
> + *
> + *
> + */
> +
> +#ifdef HAVE_CONFIG_H
> +#include <config.h>
> +#endif
> +
> +#include <stdbool.h>
> +
> +#include <glib.h>
> +
> +#include "bluetooth/bluetooth.h"
> +
> +#include "lib/mgmt.h"
> +#include "src/plugin.h"
> +#include "src/adapter.h"
> +#include "src/device.h"
> +#include "src/eir.h"
> +#include "src/log.h"
> +#include "src/shared/mgmt.h"
> +#include "src/shared/util.h"
> +
> +#define APPLE_INC_VENDOR_ID 0x004c
> +
> +static struct mgmt *mgmt;
> +
> +static bool eir_msd_is_apple_inc(GSList *msd_list)
> +{
> + GSList *msd_l, *msd_next;
> +
> + for (msd_l = msd_list; msd_l != NULL; msd_l = msd_next) {
> + const struct eir_msd *msd = msd_l->data;
> +
> + msd_next = g_slist_next(msd_l);
> +
> + if (msd->company == APPLE_INC_VENDOR_ID)
> + return true;
> + }
> +
> + return false;
> +}
> +
> +static void airpods_device_found_callback(uint16_t index, uint16_t length,
> + const void *param, void *user_data)
> +{
> + struct btd_device *dev;
> + const struct mgmt_ev_device_found *ev = param;
> + struct btd_adapter *adapter = user_data;
> + uint16_t eir_len;
> + uint32_t flags = le32_to_cpu(ev->flags);
> + struct eir_data eir_data;
> +
> + dev = btd_adapter_find_device(adapter, &ev->addr.bdaddr,
> + ev->addr.type);
> + if (!dev)
> + return;
> +
> + if (length < sizeof(*ev)) {
> + warn("Too short device found event (%u bytes)", length);
> + return;
> + }
> +
> + eir_len = btohs(ev->eir_len);
> + if (length != sizeof(*ev) + eir_len) {
> + warn("Device found event size mismatch (%u != %zu)",
> + length, sizeof(*ev) + eir_len);
> + return;
> + }
> +
> + if (eir_len == 0)
> + return;
> +
> + memset(&eir_data, 0, sizeof(eir_data));
> + eir_parse(&eir_data, ev->eir, eir_len);
> +
> + if (eir_msd_is_apple_inc(eir_data.msd_list) &&
> + (flags & MGMT_DEV_FOUND_NOT_CONNECTABLE) &&
> + (ev->addr.type == BDADDR_LE_PUBLIC)) {
> + DBG("Force BREDR last seen");
> + device_set_bredr_support(dev);
> + device_update_last_seen(dev, BDADDR_BREDR, true);
> + }
> +}
> +
> +static int airpods_probe(struct btd_adapter *adapter)
> +{
> + if (!mgmt)
> + mgmt = mgmt_new_default();
> +
> + if (!mgmt) {
> + fprintf(stderr, "Failed to open management socket\n");
> + return 0;
> + }
> +
> + mgmt_register(mgmt, MGMT_EV_DEVICE_FOUND,
> + btd_adapter_get_index(adapter),
> + airpods_device_found_callback,
> + adapter, NULL);
> +
> + return 0;
> +}
> +
> +static void airpods_remove(struct btd_adapter *adapter)
> +{
> + mgmt_unregister_index(mgmt, btd_adapter_get_index(adapter));
> +}
> +
> +static struct btd_adapter_driver airpods_driver = {
> + .name = "airpods",
> + .probe = airpods_probe,
> + .remove = airpods_remove,
> +};
> +
> +static int airpods_init(void)
> +{
> + return btd_register_adapter_driver(&airpods_driver);
> +}
> +
> +static void airpods_exit(void)
> +{
> + btd_unregister_adapter_driver(&airpods_driver);
> +}
> +
> +BLUETOOTH_PLUGIN_DEFINE(airpods, VERSION,
> + BLUETOOTH_PLUGIN_PRIORITY_LOW, airpods_init, airpods_exit)
> --
> 2.34.1
>
>
--
pozdrawiam
Szymon K. Janc
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH BlueZ] plugins: Add new plugin to fix airpods pairing
2024-04-03 13:50 ` [PATCH BlueZ] " Szymon Janc
@ 2024-04-03 16:35 ` Frédéric Danis
0 siblings, 0 replies; 4+ messages in thread
From: Frédéric Danis @ 2024-04-03 16:35 UTC (permalink / raw)
To: Szymon Janc, Luiz Augusto von Dentz; +Cc: linux-bluetooth
Hi,
On 03/04/2024 15:50, Szymon Janc wrote:
> Hi,
>
> On Wed, 3 Apr 2024 at 13:08, Frédéric Danis
> <frederic.danis@collabora.com> wrote:
>> Apple Airpods are discoverable and pairable in BREDR mode, but also
>> advertise in unconnectable mode in LE with the same Public address, at the
>> same time. As the pairing process uses the latest seen address, sometimes
>> it uses the LE Public address to pair, which fails.
>>
>> This commit adds a new adapter driver plugin which force the BREDR last
>> seen time on LE Public address device found event related to an Apple
>> device, allowing pairing process to always use the BREDR.
>>
> While I'm fine with having plugin for this specific case, I wonder if
> select_conn_bearer() shouldn't take
> bearer's connectable state into account when selecting bearer for connection
Yes, this could be a lot simpler, but couldn't it break some other
pairing case?
>> This commit is based on proposal
>> https://lore.kernel.org/all/20240103101328.1812899-1-clancy_shang@163.com/
>> ---
>> Makefile.plugins | 3 ++
>> plugins/airpods.c | 132 ++++++++++++++++++++++++++++++++++++++++++++++
>> 2 files changed, 135 insertions(+)
>> create mode 100644 plugins/airpods.c
>>
>> diff --git a/Makefile.plugins b/Makefile.plugins
>> index 4aa2c9c92..2ebd8aaf6 100644
>> --- a/Makefile.plugins
>> +++ b/Makefile.plugins
>> @@ -11,6 +11,9 @@ builtin_sources += plugins/autopair.c
>> builtin_modules += policy
>> builtin_sources += plugins/policy.c
>>
>> +builtin_modules += airpods
>> +builtin_sources += plugins/airpods.c
>> +
>> if ADMIN
>> builtin_modules += admin
>> builtin_sources += plugins/admin.c
>> diff --git a/plugins/airpods.c b/plugins/airpods.c
>> new file mode 100644
>> index 000000000..5043f0cca
>> --- /dev/null
>> +++ b/plugins/airpods.c
>> @@ -0,0 +1,132 @@
>> +// SPDX-License-Identifier: GPL-2.0-or-later
>> +/*
>> + *
>> + * BlueZ - Bluetooth protocol stack for Linux
>> + *
>> + * Copyright (C) 2024 Frédéric Danis <frederic.danis@collabora.com>
>> + *
>> + *
>> + */
>> +
>> +#ifdef HAVE_CONFIG_H
>> +#include <config.h>
>> +#endif
>> +
>> +#include <stdbool.h>
>> +
>> +#include <glib.h>
>> +
>> +#include "bluetooth/bluetooth.h"
>> +
>> +#include "lib/mgmt.h"
>> +#include "src/plugin.h"
>> +#include "src/adapter.h"
>> +#include "src/device.h"
>> +#include "src/eir.h"
>> +#include "src/log.h"
>> +#include "src/shared/mgmt.h"
>> +#include "src/shared/util.h"
>> +
>> +#define APPLE_INC_VENDOR_ID 0x004c
>> +
>> +static struct mgmt *mgmt;
>> +
>> +static bool eir_msd_is_apple_inc(GSList *msd_list)
>> +{
>> + GSList *msd_l, *msd_next;
>> +
>> + for (msd_l = msd_list; msd_l != NULL; msd_l = msd_next) {
>> + const struct eir_msd *msd = msd_l->data;
>> +
>> + msd_next = g_slist_next(msd_l);
>> +
>> + if (msd->company == APPLE_INC_VENDOR_ID)
>> + return true;
>> + }
>> +
>> + return false;
>> +}
>> +
>> +static void airpods_device_found_callback(uint16_t index, uint16_t length,
>> + const void *param, void *user_data)
>> +{
>> + struct btd_device *dev;
>> + const struct mgmt_ev_device_found *ev = param;
>> + struct btd_adapter *adapter = user_data;
>> + uint16_t eir_len;
>> + uint32_t flags = le32_to_cpu(ev->flags);
>> + struct eir_data eir_data;
>> +
>> + dev = btd_adapter_find_device(adapter, &ev->addr.bdaddr,
>> + ev->addr.type);
>> + if (!dev)
>> + return;
>> +
>> + if (length < sizeof(*ev)) {
>> + warn("Too short device found event (%u bytes)", length);
>> + return;
>> + }
>> +
>> + eir_len = btohs(ev->eir_len);
>> + if (length != sizeof(*ev) + eir_len) {
>> + warn("Device found event size mismatch (%u != %zu)",
>> + length, sizeof(*ev) + eir_len);
>> + return;
>> + }
>> +
>> + if (eir_len == 0)
>> + return;
>> +
>> + memset(&eir_data, 0, sizeof(eir_data));
>> + eir_parse(&eir_data, ev->eir, eir_len);
>> +
>> + if (eir_msd_is_apple_inc(eir_data.msd_list) &&
>> + (flags & MGMT_DEV_FOUND_NOT_CONNECTABLE) &&
>> + (ev->addr.type == BDADDR_LE_PUBLIC)) {
>> + DBG("Force BREDR last seen");
>> + device_set_bredr_support(dev);
>> + device_update_last_seen(dev, BDADDR_BREDR, true);
>> + }
>> +}
>> +
>> +static int airpods_probe(struct btd_adapter *adapter)
>> +{
>> + if (!mgmt)
>> + mgmt = mgmt_new_default();
>> +
>> + if (!mgmt) {
>> + fprintf(stderr, "Failed to open management socket\n");
>> + return 0;
>> + }
>> +
>> + mgmt_register(mgmt, MGMT_EV_DEVICE_FOUND,
>> + btd_adapter_get_index(adapter),
>> + airpods_device_found_callback,
>> + adapter, NULL);
>> +
>> + return 0;
>> +}
>> +
>> +static void airpods_remove(struct btd_adapter *adapter)
>> +{
>> + mgmt_unregister_index(mgmt, btd_adapter_get_index(adapter));
>> +}
>> +
>> +static struct btd_adapter_driver airpods_driver = {
>> + .name = "airpods",
>> + .probe = airpods_probe,
>> + .remove = airpods_remove,
>> +};
>> +
>> +static int airpods_init(void)
>> +{
>> + return btd_register_adapter_driver(&airpods_driver);
>> +}
>> +
>> +static void airpods_exit(void)
>> +{
>> + btd_unregister_adapter_driver(&airpods_driver);
>> +}
>> +
>> +BLUETOOTH_PLUGIN_DEFINE(airpods, VERSION,
>> + BLUETOOTH_PLUGIN_PRIORITY_LOW, airpods_init, airpods_exit)
>> --
>> 2.34.1
>>
>>
>
--
Frédéric Danis
Senior Software Engineer
Collabora Ltd.
Platinum Building, St John's Innovation Park, Cambridge CB4 0DS, United Kingdom
Registered in England & Wales, no. 5513718
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2024-04-03 16:35 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-04-03 11:08 [PATCH BlueZ] plugins: Add new plugin to fix airpods pairing Frédéric Danis
2024-04-03 13:01 ` [BlueZ] " bluez.test.bot
2024-04-03 13:50 ` [PATCH BlueZ] " Szymon Janc
2024-04-03 16:35 ` Frédéric Danis
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).