diff mbox series

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

Message ID 20211105011331.288326-1-hj.tedd.an@gmail.com (mailing list archive)
State Superseded
Headers show
Series [RFC,V3] Bluetooth: vhci: Add support creating extended device mode | expand

Checks

Context Check Description
tedd_an/checkpatch fail [RFC,V3] Bluetooth: vhci: Add support creating extended device mode\WARNING:TYPO_SPELLING: 'lenght' may be misspelled - perhaps 'length'? #109: FILE: drivers/bluetooth/hci_vhci.c:37: + * flag_len is the lenght or flag array ^^^^^^ WARNING:TYPO_SPELLING: 'vaild' may be misspelled - perhaps 'valid'? #142: FILE: drivers/bluetooth/hci_vhci.c:408: + /* Make sure the skb has a minimum vaild length */ ^^^^^ ERROR:SPACING: space required before the open parenthesis '(' #181: FILE: drivers/bluetooth/hci_vhci.c:447: + switch(flag) { WARNING:LEADING_SPACE: please, no spaces at the start of a line #239: FILE: drivers/bluetooth/hci_vhci.c:505: + int err;$ WARNING:LEADING_SPACE: please, no spaces at the start of a line #241: FILE: drivers/bluetooth/hci_vhci.c:507: + mutex_lock(&data->open_mutex);$ WARNING:LEADING_SPACE: please, no spaces at the start of a line #242: FILE: drivers/bluetooth/hci_vhci.c:508: + err = __vhci_create_extended_device(data, skb);$ WARNING:LEADING_SPACE: please, no spaces at the start of a line #243: FILE: drivers/bluetooth/hci_vhci.c:509: + mutex_unlock(&data->open_mutex);$ WARNING:LEADING_SPACE: please, no spaces at the start of a line #245: FILE: drivers/bluetooth/hci_vhci.c:511: + return err;$ WARNING:BLOCK_COMMENT_STYLE: Block comments should align the * on each line #259: FILE: drivers/bluetooth/hci_vhci.c:559: + /* 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 total: 1 errors, 8 warnings, 176 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/12603907.patch has style problems, please review. NOTE: Ignored message types: UNKNOWN_COMMIT_ID NOTE: If any of the errors are false positives, please report them to the maintainer, see CHECKPATCH in MAINTAINERS.
tedd_an/gitlint success Gitlint PASS
tedd_an/buildkernel success Build Kernel PASS
tedd_an/testrunnersetup success Test Runner Setup PASS
tedd_an/testrunnerl2cap-tester success Total: 40, Passed: 40 (100.0%), Failed: 0, Not Run: 0
tedd_an/testrunnerbnep-tester success Total: 1, Passed: 1 (100.0%), Failed: 0, Not Run: 0
tedd_an/testrunnermgmt-tester success Total: 492, Passed: 492 (100.0%), Failed: 0, Not Run: 0
tedd_an/testrunnerrfcomm-tester success Total: 9, Passed: 9 (100.0%), Failed: 0, Not Run: 0
tedd_an/testrunnersco-tester success Total: 12, Passed: 12 (100.0%), Failed: 0, Not Run: 0
tedd_an/testrunnersmp-tester success Total: 8, Passed: 8 (100.0%), Failed: 0, Not Run: 0
tedd_an/testrunneruserchan-tester success Total: 4, Passed: 4 (100.0%), Failed: 0, Not Run: 0

Commit Message

Tedd Ho-Jeong An Nov. 5, 2021, 1:13 a.m. UTC
From: Tedd Ho-Jeong An <tedd.an@intel.com>

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@intel.com>
---
 drivers/bluetooth/hci_vhci.c | 156 +++++++++++++++++++++++++++++++++--
 1 file changed, 150 insertions(+), 6 deletions(-)

Comments

Luiz Augusto von Dentz Nov. 5, 2021, 9:30 p.m. UTC | #1
Hi Tedd,

On Thu, Nov 4, 2021 at 6:34 PM Tedd Ho-Jeong An <hj.tedd.an@gmail.com> wrote:
>
> From: Tedd Ho-Jeong An <tedd.an@intel.com>
>
> 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@intel.com>
> ---
>  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
>
diff mbox series

Patch

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;
+		}
+	}
+
+	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: