Re: [RFC PATCH V3] Bluetooth: vhci: Add support creating extended device mode

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

 



Hi Tedd,

On Thu, Nov 4, 2021 at 6:34 PM Tedd Ho-Jeong An <hj.tedd.an@xxxxxxxxx> wrote:
>
> From: Tedd Ho-Jeong An <tedd.an@xxxxxxxxx>
>
> This patch adds new opcode(0x03) for HCI Vendor packet to support
> creating extended device mode. In order to avoid the conflict with the
> legacy opcode, it has to be 0x03 only and all other bits must be set to
> zero.
>
> Then, it is followed by the extended configuration data that contains
> the device type and the flags to be used.
>
> Signed-off-by: Tedd Ho-Jeong An <tedd.an@xxxxxxxxx>
> ---
>  drivers/bluetooth/hci_vhci.c | 156 +++++++++++++++++++++++++++++++++--
>  1 file changed, 150 insertions(+), 6 deletions(-)
>
> diff --git a/drivers/bluetooth/hci_vhci.c b/drivers/bluetooth/hci_vhci.c
> index 49ac884d996e..d1177a079f98 100644
> --- a/drivers/bluetooth/hci_vhci.c
> +++ b/drivers/bluetooth/hci_vhci.c
> @@ -30,6 +30,24 @@
>
>  static bool amp;
>
> +/* This is the struct for extended device configuration.
> + * The opcode 0x03 is used for creating an extended device and followed by
> + * the configuration data below.
> + * dev_type is Primay or AMP.
> + * flag_len is the lenght or flag array
> + * flag array contains the flag to use/set while creating the device.
> + */
> +struct vhci_ext_config {
> +       __u8    dev_type;
> +       __u8    flag_len;
> +       __u8    flag[0];
> +};
> +
> +#define VHCI_EXT_FLAG_ENABLE_AOSP              0x01
> +#define VHCI_EXT_FLAG_QUIRK_RAW_DEVICE         0x02
> +#define VHCI_EXT_FLAG_QUIARK_EXTERNAL_CONFIG   0x03
> +#define VHCI_EXT_FLAG_QUIRK_INVALID_BDADDR     0x04
> +
>  struct vhci_data {
>         struct hci_dev *hdev;
>
> @@ -375,6 +393,124 @@ static int vhci_create_device(struct vhci_data *data, __u8 opcode)
>         return err;
>  }
>
> +static int __vhci_create_extended_device(struct vhci_data *data,
> +                                                       struct sk_buff *skb)
> +{
> +       struct hci_dev *hdev;
> +       struct sk_buff *resp;
> +       struct vhci_ext_config *config;
> +       int i;
> +       __u8 flag;
> +
> +       if (data->hdev)
> +               return -EBADFD;
> +
> +       /* Make sure the skb has a minimum vaild length */
> +       if (skb->len < sizeof(*config))
> +               return -EINVAL;
> +
> +       config = (void *)(skb->data);
> +       if (skb->len < sizeof(*config) + config->flag_len)
> +               return -EINVAL;
> +
> +       if (config->dev_type != HCI_PRIMARY && config->dev_type != HCI_AMP)
> +               return -EINVAL;
> +
> +       resp = bt_skb_alloc(4, GFP_KERNEL);
> +       if (!resp)
> +               return -ENOMEM;
> +
> +       hdev = hci_alloc_dev();
> +       if (!hdev) {
> +               kfree_skb(resp);
> +               return -ENOMEM;
> +       }
> +
> +       data->hdev = hdev;
> +
> +       hdev->bus = HCI_VIRTUAL;
> +       hdev->dev_type = config->dev_type;
> +       hci_set_drvdata(hdev, data);
> +
> +       hdev->open  = vhci_open_dev;
> +       hdev->close = vhci_close_dev;
> +       hdev->flush = vhci_flush;
> +       hdev->send  = vhci_send_frame;
> +       hdev->get_data_path_id = vhci_get_data_path_id;
> +       hdev->get_codec_config_data = vhci_get_codec_config_data;
> +       hdev->wakeup = vhci_wakeup;
> +       hdev->setup = vhci_setup;
> +       set_bit(HCI_QUIRK_NON_PERSISTENT_SETUP, &hdev->quirks);
> +
> +       for (i = 0; i < config->flag_len; i++) {
> +               flag = config->flag[i];
> +               switch(flag) {
> +               case VHCI_EXT_FLAG_ENABLE_AOSP:
> +                       data->aosp_capable = 1;
> +                       break;
> +               case VHCI_EXT_FLAG_QUIRK_RAW_DEVICE:
> +                       set_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks);
> +                       break;
> +               case VHCI_EXT_FLAG_QUIARK_EXTERNAL_CONFIG:
> +                       set_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks);
> +                       break;
> +               case VHCI_EXT_FLAG_QUIRK_INVALID_BDADDR:
> +                       set_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks);
> +                       break;
> +               default:
> +                       BT_ERR("Invalid flag");
> +                       hci_free_dev(hdev);
> +                       data->hdev = NULL;
> +                       kfree_skb(resp);
> +                       return -EINVAL;
> +               }
> +       }

We can probably move the code below to a common function e.g.
vhci_register_dev since it should be the same for both old and new
commands, so that would take care of calling hci_register_dev and
registering the debugfs entries.

> +       if (hci_register_dev(hdev) < 0) {
> +               BT_ERR("Can't register HCI device");
> +               hci_free_dev(hdev);
> +               data->hdev = NULL;
> +               kfree_skb(resp);
> +               return -EBUSY;
> +       }
> +
> +       debugfs_create_file("force_suspend", 0644, hdev->debugfs, data,
> +                           &force_suspend_fops);
> +
> +       debugfs_create_file("force_wakeup", 0644, hdev->debugfs, data,
> +                           &force_wakeup_fops);
> +
> +       if (IS_ENABLED(CONFIG_BT_MSFTEXT))
> +               debugfs_create_file("msft_opcode", 0644, hdev->debugfs, data,
> +                                   &msft_opcode_fops);
> +
> +       if (IS_ENABLED(CONFIG_BT_AOSPEXT))
> +               debugfs_create_file("aosp_capable", 0644, hdev->debugfs, data,
> +                                   &aosp_capable_fops);
> +
> +       hci_skb_pkt_type(resp) = HCI_VENDOR_PKT;
> +
> +       skb_put_u8(resp, 0xff);
> +       skb_put_u8(resp, 0x03);
> +       put_unaligned_le16(hdev->id, skb_put(resp, 2));
> +       skb_queue_tail(&data->readq, resp);
> +
> +       wake_up_interruptible(&data->read_wait);
> +       return 0;
> +}
> +
> +static int vhci_create_extended_device(struct vhci_data *data,
> +                                                       struct sk_buff *skb)
> +{
> +       int err;
> +
> +       mutex_lock(&data->open_mutex);
> +       err = __vhci_create_extended_device(data, skb);
> +       mutex_unlock(&data->open_mutex);
> +
> +       return err;
> +}
> +
>  static inline ssize_t vhci_get_user(struct vhci_data *data,
>                                     struct iov_iter *from)
>  {
> @@ -419,14 +555,22 @@ static inline ssize_t vhci_get_user(struct vhci_data *data,
>                 opcode = *((__u8 *) skb->data);
>                 skb_pull(skb, 1);
>
> -               if (skb->len > 0) {
> -                       kfree_skb(skb);
> -                       return -EINVAL;
> +               /* The dev_type 3 is used as an escape opcode for extension
> +               * handling. If dev_type is set to 3 all other bits must be
> +               * set to zero.
> +               */
> +               if (opcode == 0x03) {
> +                       if (skb->len < 1)
> +                               ret = -EINVAL;
> +                       else
> +                               ret = vhci_create_extended_device(data, skb);
> +               } else {
> +                       if (skb->len > 0)
> +                               ret = -EINVAL;
> +                       else
> +                               ret = vhci_create_device(data, opcode);
>                 }
> -
>                 kfree_skb(skb);
> -
> -               ret = vhci_create_device(data, opcode);
>                 break;
>
>         default:
> --
> 2.25.1
>


-- 
Luiz Augusto von Dentz



[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