Re: [PATCH BlueZ] plugins: Add new plugin to fix airpods pairing

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi,

On Wed, 3 Apr 2024 at 13:08, Frédéric Danis
<frederic.danis@xxxxxxxxxxxxx> 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@xxxxxxx/
> ---
>  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@xxxxxxxxxxxxx>
> + *
> + *
> + */
> +
> +#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





[Index of Archives]     [Bluez Devel]     [Linux Wireless Networking]     [Linux Wireless Personal Area Networking]     [Linux ATH6KL]     [Linux USB Devel]     [Linux Media Drivers]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Big List of Linux Books]

  Powered by Linux