lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Message-ID: <CABBYNZ+FkEcRBeVTr+dk0dn6MTd6X7g5G5F5-zn0U8GpemO_=w@mail.gmail.com>
Date: Tue, 15 Apr 2025 15:46:10 -0400
From: Luiz Augusto von Dentz <luiz.dentz@...il.com>
To: Hsin-chen Chuang <chharry@...gle.com>
Cc: Hsin-chen Chuang <chharry@...omium.org>, chromeos-bluetooth-upstreaming@...omium.org, 
	"David S. Miller" <davem@...emloft.net>, Eric Dumazet <edumazet@...gle.com>, 
	Jakub Kicinski <kuba@...nel.org>, Johan Hedberg <johan.hedberg@...il.com>, 
	Marcel Holtmann <marcel@...tmann.org>, Paolo Abeni <pabeni@...hat.com>, Simon Horman <horms@...nel.org>, 
	Ying Hsu <yinghsu@...omium.org>, linux-bluetooth@...r.kernel.org, 
	linux-kernel@...r.kernel.org, netdev@...r.kernel.org
Subject: Re: [PATCH 1/4] Bluetooth: Introduce HCI Driver protocol

Hi Hsin-chen,

On Fri, Apr 11, 2025 at 9:33 AM Hsin-chen Chuang <chharry@...gle.com> wrote:
>
> From: Hsin-chen Chuang <chharry@...omium.org>
>
> Although commit 75ddcd5ad40e ("Bluetooth: btusb: Configure altsetting
> for HCI_USER_CHANNEL") has enabled the HCI_USER_CHANNEL user to send out
> SCO data through USB Bluetooth chips, it's observed that with the patch
> HFP is flaky on most of the existing USB Bluetooth controllers: Intel
> chips sometimes send out no packet for Transparent codec; MTK chips may
> generate SCO data with a wrong handle for CVSD codec; RTK could split
> the data with a wrong packet size for Transparent codec; ... etc.
>
> To address the issue above one needs to reset the altsetting back to
> zero when there is no active SCO connection, which is the same as the
> BlueZ behavior, and another benefit is the bus doesn't need to reserve
> bandwidth when no SCO connection.
>
> This patch adds the infrastructure that allow the user space program to
> talk to Bluetooth drivers directly:
> - Define the new packet type HCI_DRV_PKT which is specifically used for
>   communication between the user space program and the Bluetooth drviers
> - hci_send_frame intercepts the packets and invokes drivers' HCI Drv
>   callbacks (so far only defined for btusb)
> - 2 kinds of events to user space: Command Status and Command Complete,
>   the former simply returns the status while the later may contain
>   additional response data.
>
> Cc: chromeos-bluetooth-upstreaming@...omium.org
> Fixes: b16b327edb4d ("Bluetooth: btusb: add sysfs attribute to control USB alt setting")
> Signed-off-by: Hsin-chen Chuang <chharry@...omium.org>
> ---
>
>  drivers/bluetooth/btusb.c        |  65 ++++++++++++++++++--
>  include/net/bluetooth/hci.h      |   1 +
>  include/net/bluetooth/hci_core.h |   3 +
>  include/net/bluetooth/hci_drv.h  |  74 ++++++++++++++++++++++
>  include/net/bluetooth/hci_mon.h  |   2 +
>  net/bluetooth/Makefile           |   3 +-
>  net/bluetooth/hci_core.c         |  10 +++
>  net/bluetooth/hci_drv.c          | 102 +++++++++++++++++++++++++++++++
>  net/bluetooth/hci_sock.c         |  12 +++-
>  9 files changed, 263 insertions(+), 9 deletions(-)
>  create mode 100644 include/net/bluetooth/hci_drv.h
>  create mode 100644 net/bluetooth/hci_drv.c
>
> diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
> index 7a9b89bcea22..a33c6b9f8433 100644
> --- a/drivers/bluetooth/btusb.c
> +++ b/drivers/bluetooth/btusb.c
> @@ -21,6 +21,7 @@
>
>  #include <net/bluetooth/bluetooth.h>
>  #include <net/bluetooth/hci_core.h>
> +#include <net/bluetooth/hci_drv.h>
>
>  #include "btintel.h"
>  #include "btbcm.h"
> @@ -3754,6 +3755,57 @@ static ssize_t isoc_alt_store(struct device *dev,
>
>  static DEVICE_ATTR_RW(isoc_alt);
>
> +static const struct {
> +       u16 opcode;
> +       const char *desc;
> +} btusb_hci_drv_supported_commands[] = {
> +       /* Common commands */
> +       { HCI_DRV_OP_READ_INFO, "Read Info" },
> +};
> +static int btusb_hci_drv_read_info(struct hci_dev *hdev, void *data,
> +                                  u16 data_len)
> +{
> +       struct hci_drv_rp_read_info *rp;
> +       size_t rp_size;
> +       int err, i;
> +       u16 num_supported_commands = ARRAY_SIZE(btusb_hci_drv_supported_commands);
> +
> +       rp_size = sizeof(*rp) + num_supported_commands * 2;
> +
> +       rp = kmalloc(rp_size, GFP_KERNEL);
> +       if (!rp)
> +               return -ENOMEM;
> +
> +       strscpy_pad(rp->driver_name, btusb_driver.name);
> +
> +       rp->num_supported_commands = cpu_to_le16(num_supported_commands);
> +       for (i = 0; i < num_supported_commands; i++) {
> +               bt_dev_info(hdev, "Supported HCI Driver command: %s",
> +                           btusb_hci_drv_supported_commands[i].desc);
> +               rp->supported_commands[i] =
> +                       cpu_to_le16(btusb_hci_drv_supported_commands[i].opcode);
> +       }
> +
> +       err = hci_drv_cmd_complete(hdev, HCI_DRV_OP_READ_INFO,
> +                                  HCI_DRV_STATUS_SUCCESS, rp, rp_size);
> +
> +       kfree(rp);
> +       return err;
> +}
> +
> +static const struct hci_drv_handler btusb_hci_drv_common_handlers[] = {
> +       { btusb_hci_drv_read_info,      HCI_DRV_READ_INFO_SIZE },
> +};
> +
> +static const struct hci_drv_handler btusb_hci_drv_specific_handlers[] = {};
> +
> +static struct hci_drv btusb_hci_drv = {
> +       .common_handler_count   = ARRAY_SIZE(btusb_hci_drv_common_handlers),
> +       .common_handlers        = btusb_hci_drv_common_handlers,
> +       .specific_handler_count = ARRAY_SIZE(btusb_hci_drv_specific_handlers),
> +       .specific_handlers      = btusb_hci_drv_specific_handlers,
> +};
> +
>  static int btusb_probe(struct usb_interface *intf,
>                        const struct usb_device_id *id)
>  {
> @@ -3893,12 +3945,13 @@ static int btusb_probe(struct usb_interface *intf,
>                 data->reset_gpio = reset_gpio;
>         }
>
> -       hdev->open   = btusb_open;
> -       hdev->close  = btusb_close;
> -       hdev->flush  = btusb_flush;
> -       hdev->send   = btusb_send_frame;
> -       hdev->notify = btusb_notify;
> -       hdev->wakeup = btusb_wakeup;
> +       hdev->open    = btusb_open;
> +       hdev->close   = btusb_close;
> +       hdev->flush   = btusb_flush;
> +       hdev->send    = btusb_send_frame;
> +       hdev->notify  = btusb_notify;
> +       hdev->wakeup  = btusb_wakeup;
> +       hdev->hci_drv = &btusb_hci_drv;
>
>  #ifdef CONFIG_PM
>         err = btusb_config_oob_wake(hdev);
> diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
> index a8586c3058c7..e297b312d2b7 100644
> --- a/include/net/bluetooth/hci.h
> +++ b/include/net/bluetooth/hci.h
> @@ -494,6 +494,7 @@ enum {
>  #define HCI_EVENT_PKT          0x04
>  #define HCI_ISODATA_PKT                0x05
>  #define HCI_DIAG_PKT           0xf0
> +#define HCI_DRV_PKT            0xf1
>  #define HCI_VENDOR_PKT         0xff
>
>  /* HCI packet types */
> diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
> index 5115da34f881..dd80f1a398be 100644
> --- a/include/net/bluetooth/hci_core.h
> +++ b/include/net/bluetooth/hci_core.h
> @@ -31,6 +31,7 @@
>  #include <linux/rculist.h>
>
>  #include <net/bluetooth/hci.h>
> +#include <net/bluetooth/hci_drv.h>
>  #include <net/bluetooth/hci_sync.h>
>  #include <net/bluetooth/hci_sock.h>
>  #include <net/bluetooth/coredump.h>
> @@ -613,6 +614,8 @@ struct hci_dev {
>         struct list_head        monitored_devices;
>         bool                    advmon_pend_notify;
>
> +       struct hci_drv          *hci_drv;
> +
>  #if IS_ENABLED(CONFIG_BT_LEDS)
>         struct led_trigger      *power_led;
>  #endif
> diff --git a/include/net/bluetooth/hci_drv.h b/include/net/bluetooth/hci_drv.h
> new file mode 100644
> index 000000000000..a05227b6e2df
> --- /dev/null
> +++ b/include/net/bluetooth/hci_drv.h
> @@ -0,0 +1,74 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +/*
> + * Copyright (C) 2025 Google Corporation
> + */
> +
> +#ifndef __HCI_DRV_H
> +#define __HCI_DRV_H
> +
> +#include <linux/types.h>
> +
> +#include <net/bluetooth/bluetooth.h>
> +#include <net/bluetooth/hci.h>
> +
> +struct hci_drv_cmd_hdr {
> +       __le16  opcode;
> +       __le16  len;
> +} __packed;
> +
> +struct hci_drv_ev_hdr {
> +       __le16  opcode;
> +       __le16  len;
> +} __packed;
> +
> +#define HCI_DRV_EV_CMD_STATUS  0x0000
> +struct hci_drv_ev_cmd_status {
> +       __le16  opcode;
> +       __u8    status;
> +} __packed;
> +
> +#define HCI_DRV_EV_CMD_COMPLETE        0x0001
> +struct hci_drv_ev_cmd_complete {
> +       __le16  opcode;
> +       __u8    status;
> +       __u8    data[];
> +} __packed;
> +
> +#define HCI_DRV_STATUS_SUCCESS                 0x00
> +#define HCI_DRV_STATUS_UNSPECIFIED_ERROR       0x01
> +#define HCI_DRV_STATUS_UNKNOWN_COMMAND         0x02
> +#define HCI_DRV_STATUS_INVALID_PARAMETERS      0x03
> +
> +#define HCI_DRV_MAX_DRIVER_NAME_LENGTH 32
> +
> +/* Common commands that make sense on all drivers start from 0x0000 */
> +#define HCI_DRV_OP_READ_INFO   0x0000
> +#define HCI_DRV_READ_INFO_SIZE 0
> +struct hci_drv_rp_read_info {
> +       __u8    driver_name[HCI_DRV_MAX_DRIVER_NAME_LENGTH];
> +       __le16  num_supported_commands;
> +       __le16  supported_commands[];
> +} __packed;
> +
> +/* Driver specific commands start from 0x1135 */
> +#define HCI_DRV_OP_DRIVER_SPECIFIC_BASE        0x1135

Or perhaps we just use the hci_opcode_ogf/hci_opcode_ocf so we have 10
bits for driver specific commands, since we are reusing the command
status/complete logic this should be really straightforward.

> +int hci_drv_cmd_status(struct hci_dev *hdev, u16 cmd, u8 status);
> +int hci_drv_cmd_complete(struct hci_dev *hdev, u16 cmd, u8 status, void *rp,
> +                        size_t rp_len);
> +int hci_drv_process_cmd(struct hci_dev *hdev, struct sk_buff *cmd_skb);
> +
> +struct hci_drv_handler {
> +       int (*func)(struct hci_dev *hdev, void *data, u16 data_len);
> +       size_t data_len;
> +};
> +
> +struct hci_drv {
> +       size_t common_handler_count;
> +       const struct hci_drv_handler *common_handlers;
> +
> +       size_t specific_handler_count;
> +       const struct hci_drv_handler *specific_handlers;
> +};
> +
> +#endif /* __HCI_DRV_H */
> diff --git a/include/net/bluetooth/hci_mon.h b/include/net/bluetooth/hci_mon.h
> index 082f89531b88..bbd752494ef9 100644
> --- a/include/net/bluetooth/hci_mon.h
> +++ b/include/net/bluetooth/hci_mon.h
> @@ -51,6 +51,8 @@ struct hci_mon_hdr {
>  #define HCI_MON_CTRL_EVENT     17
>  #define HCI_MON_ISO_TX_PKT     18
>  #define HCI_MON_ISO_RX_PKT     19
> +#define HCI_MON_DRV_TX_PKT     20
> +#define HCI_MON_DRV_RX_PKT     21
>
>  struct hci_mon_new_index {
>         __u8            type;
> diff --git a/net/bluetooth/Makefile b/net/bluetooth/Makefile
> index 5a3835b7dfcd..a7eede7616d8 100644
> --- a/net/bluetooth/Makefile
> +++ b/net/bluetooth/Makefile
> @@ -14,7 +14,8 @@ bluetooth_6lowpan-y := 6lowpan.o
>
>  bluetooth-y := af_bluetooth.o hci_core.o hci_conn.o hci_event.o mgmt.o \
>         hci_sock.o hci_sysfs.o l2cap_core.o l2cap_sock.o smp.o lib.o \
> -       ecdh_helper.o mgmt_util.o mgmt_config.o hci_codec.o eir.o hci_sync.o
> +       ecdh_helper.o mgmt_util.o mgmt_config.o hci_codec.o eir.o hci_sync.o \
> +       hci_drv.o
>
>  bluetooth-$(CONFIG_DEV_COREDUMP) += coredump.o
>
> diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
> index 5eb0600bbd03..2815b2d7d28d 100644
> --- a/net/bluetooth/hci_core.c
> +++ b/net/bluetooth/hci_core.c
> @@ -2911,6 +2911,8 @@ int hci_recv_frame(struct hci_dev *hdev, struct sk_buff *skb)
>                 break;
>         case HCI_ISODATA_PKT:
>                 break;
> +       case HCI_DRV_PKT:
> +               break;
>         default:
>                 kfree_skb(skb);
>                 return -EINVAL;
> @@ -3019,6 +3021,14 @@ static int hci_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
>                 return -EINVAL;
>         }
>
> +       if (hci_skb_pkt_type(skb) == HCI_DRV_PKT) {
> +               // Intercept HCI Drv packet here and don't go with hdev->send
> +               // callabck.
> +               err = hci_drv_process_cmd(hdev, skb);
> +               kfree_skb(skb);
> +               return err;
> +       }
> +
>         err = hdev->send(hdev, skb);
>         if (err < 0) {
>                 bt_dev_err(hdev, "sending frame failed (%d)", err);
> diff --git a/net/bluetooth/hci_drv.c b/net/bluetooth/hci_drv.c
> new file mode 100644
> index 000000000000..7b7a5b05740c
> --- /dev/null
> +++ b/net/bluetooth/hci_drv.c
> @@ -0,0 +1,102 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (C) 2025 Google Corporation
> + */
> +
> +#include <linux/skbuff.h>
> +#include <linux/types.h>
> +
> +#include <net/bluetooth/bluetooth.h>
> +#include <net/bluetooth/hci_core.h>
> +#include <net/bluetooth/hci_drv.h>
> +
> +int hci_drv_cmd_status(struct hci_dev *hdev, u16 cmd, u8 status)
> +{
> +       struct hci_drv_ev_hdr *hdr;
> +       struct hci_drv_ev_cmd_status *ev;
> +       struct sk_buff *skb;
> +
> +       skb = bt_skb_alloc(sizeof(*hdr) + sizeof(*ev), GFP_KERNEL);
> +       if (!skb)
> +               return -ENOMEM;
> +
> +       hdr = skb_put(skb, sizeof(*hdr));
> +       hdr->opcode = __cpu_to_le16(HCI_DRV_EV_CMD_STATUS);
> +       hdr->len = __cpu_to_le16(sizeof(*ev));
> +
> +       ev = skb_put(skb, sizeof(*ev));
> +       ev->opcode = __cpu_to_le16(cmd);
> +       ev->status = status;
> +
> +       hci_skb_pkt_type(skb) = HCI_DRV_PKT;
> +
> +       return hci_recv_frame(hdev, skb);
> +}
> +EXPORT_SYMBOL(hci_drv_cmd_status);
> +
> +int hci_drv_cmd_complete(struct hci_dev *hdev, u16 cmd, u8 status, void *rp,
> +                        size_t rp_len)
> +{
> +       struct hci_drv_ev_hdr *hdr;
> +       struct hci_drv_ev_cmd_complete *ev;
> +       struct sk_buff *skb;
> +
> +       skb = bt_skb_alloc(sizeof(*hdr) + sizeof(*ev) + rp_len, GFP_KERNEL);
> +       if (!skb)
> +               return -ENOMEM;
> +
> +       hdr = skb_put(skb, sizeof(*hdr));
> +       hdr->opcode = __cpu_to_le16(HCI_DRV_EV_CMD_COMPLETE);
> +       hdr->len = __cpu_to_le16(sizeof(*ev) + rp_len);
> +
> +       ev = skb_put(skb, sizeof(*ev));
> +       ev->opcode = __cpu_to_le16(cmd);
> +       ev->status = status;
> +
> +       skb_put_data(skb, rp, rp_len);
> +
> +       hci_skb_pkt_type(skb) = HCI_DRV_PKT;
> +
> +       return hci_recv_frame(hdev, skb);
> +}
> +EXPORT_SYMBOL(hci_drv_cmd_complete);
> +
> +int hci_drv_process_cmd(struct hci_dev *hdev, struct sk_buff *skb)
> +{
> +       struct hci_drv_cmd_hdr *hdr;
> +       const struct hci_drv_handler *handler = NULL;
> +       u16 opcode, len, offset;
> +
> +       hdr = skb_pull_data(skb, sizeof(*hdr));
> +       if (!hdr)
> +               return -EILSEQ;
> +
> +       opcode = __le16_to_cpu(hdr->opcode);
> +       len = __le16_to_cpu(hdr->len);
> +       if (len != skb->len)
> +               return -EILSEQ;
> +
> +       if (!hdev->hci_drv)
> +               return hci_drv_cmd_status(hdev, opcode,
> +                                         HCI_DRV_STATUS_UNKNOWN_COMMAND);
> +
> +       if (opcode < HCI_DRV_OP_DRIVER_SPECIFIC_BASE) {
> +               if (opcode < hdev->hci_drv->common_handler_count)
> +                       handler = &hdev->hci_drv->common_handlers[opcode];
> +       } else {
> +               offset = opcode - HCI_DRV_OP_DRIVER_SPECIFIC_BASE;
> +               if (offset < hdev->hci_drv->specific_handler_count)
> +                       handler = &hdev->hci_drv->specific_handlers[offset];
> +       }
> +
> +       if (!handler || !handler->func)
> +               return hci_drv_cmd_status(hdev, opcode,
> +                                         HCI_DRV_STATUS_UNKNOWN_COMMAND);
> +
> +       if (len != handler->data_len)
> +               return hci_drv_cmd_status(hdev, opcode,
> +                                         HCI_DRV_STATUS_INVALID_PARAMETERS);
> +
> +       return handler->func(hdev, skb->data, len);
> +}
> +EXPORT_SYMBOL(hci_drv_process_cmd);
> diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c
> index 022b86797acd..428ee5c7de7e 100644
> --- a/net/bluetooth/hci_sock.c
> +++ b/net/bluetooth/hci_sock.c
> @@ -234,7 +234,8 @@ void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb)
>                         if (hci_skb_pkt_type(skb) != HCI_EVENT_PKT &&
>                             hci_skb_pkt_type(skb) != HCI_ACLDATA_PKT &&
>                             hci_skb_pkt_type(skb) != HCI_SCODATA_PKT &&
> -                           hci_skb_pkt_type(skb) != HCI_ISODATA_PKT)
> +                           hci_skb_pkt_type(skb) != HCI_ISODATA_PKT &&
> +                           hci_skb_pkt_type(skb) != HCI_DRV_PKT)
>                                 continue;
>                 } else {
>                         /* Don't send frame to other channel types */
> @@ -391,6 +392,12 @@ void hci_send_to_monitor(struct hci_dev *hdev, struct sk_buff *skb)
>                 else
>                         opcode = cpu_to_le16(HCI_MON_ISO_TX_PKT);
>                 break;
> +       case HCI_DRV_PKT:
> +               if (bt_cb(skb)->incoming)
> +                       opcode = cpu_to_le16(HCI_MON_DRV_RX_PKT);
> +               else
> +                       opcode = cpu_to_le16(HCI_MON_DRV_TX_PKT);
> +               break;
>         case HCI_DIAG_PKT:
>                 opcode = cpu_to_le16(HCI_MON_VENDOR_DIAG);
>                 break;
> @@ -1860,7 +1867,8 @@ static int hci_sock_sendmsg(struct socket *sock, struct msghdr *msg,
>                 if (hci_skb_pkt_type(skb) != HCI_COMMAND_PKT &&
>                     hci_skb_pkt_type(skb) != HCI_ACLDATA_PKT &&
>                     hci_skb_pkt_type(skb) != HCI_SCODATA_PKT &&
> -                   hci_skb_pkt_type(skb) != HCI_ISODATA_PKT) {
> +                   hci_skb_pkt_type(skb) != HCI_ISODATA_PKT &&
> +                   hci_skb_pkt_type(skb) != HCI_DRV_PKT) {
>                         err = -EINVAL;
>                         goto drop;
>                 }
> --
> 2.49.0.604.gff1f9ca942-goog
>


-- 
Luiz Augusto von Dentz

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ