Commit 82a30cfc authored by Marcel Holtmann's avatar Marcel Holtmann

Bluetooth: Support HCI_QUIRK_RAW_DEVICE for hci_vhci driver

This adds support for configuring the hci_vhci virtual controllers
as a raw-only device using HCI_QUIRK_RAW_DEVICE. This is useful for
testing the kernel internal infrastructure.
Signed-off-by: default avatarMarcel Holtmann <marcel@holtmann.org>
Signed-off-by: default avatarJohan Hedberg <johan.hedberg@intel.com>
parent 73d1df2a
...@@ -40,7 +40,7 @@ ...@@ -40,7 +40,7 @@
#include <net/bluetooth/bluetooth.h> #include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h> #include <net/bluetooth/hci_core.h>
#define VERSION "1.4" #define VERSION "1.5"
static bool amp; static bool amp;
...@@ -95,10 +95,21 @@ static int vhci_send_frame(struct hci_dev *hdev, struct sk_buff *skb) ...@@ -95,10 +95,21 @@ static int vhci_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
return 0; return 0;
} }
static int vhci_create_device(struct vhci_data *data, __u8 dev_type) static int vhci_create_device(struct vhci_data *data, __u8 opcode)
{ {
struct hci_dev *hdev; struct hci_dev *hdev;
struct sk_buff *skb; struct sk_buff *skb;
__u8 dev_type;
/* bits 0-1 are dev_type (BR/EDR or AMP) */
dev_type = opcode & 0x03;
if (dev_type != HCI_BREDR && dev_type != HCI_AMP)
return -EINVAL;
/* bits 2-6 are reserved (must be zero) */
if (opcode & 0x7c)
return -EINVAL;
skb = bt_skb_alloc(4, GFP_KERNEL); skb = bt_skb_alloc(4, GFP_KERNEL);
if (!skb) if (!skb)
...@@ -121,6 +132,10 @@ static int vhci_create_device(struct vhci_data *data, __u8 dev_type) ...@@ -121,6 +132,10 @@ static int vhci_create_device(struct vhci_data *data, __u8 dev_type)
hdev->flush = vhci_flush; hdev->flush = vhci_flush;
hdev->send = vhci_send_frame; hdev->send = vhci_send_frame;
/* bit 7 is for raw device */
if (opcode & 0x80)
set_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks);
if (hci_register_dev(hdev) < 0) { if (hci_register_dev(hdev) < 0) {
BT_ERR("Can't register HCI device"); BT_ERR("Can't register HCI device");
hci_free_dev(hdev); hci_free_dev(hdev);
...@@ -132,7 +147,7 @@ static int vhci_create_device(struct vhci_data *data, __u8 dev_type) ...@@ -132,7 +147,7 @@ static int vhci_create_device(struct vhci_data *data, __u8 dev_type)
bt_cb(skb)->pkt_type = HCI_VENDOR_PKT; bt_cb(skb)->pkt_type = HCI_VENDOR_PKT;
*skb_put(skb, 1) = 0xff; *skb_put(skb, 1) = 0xff;
*skb_put(skb, 1) = dev_type; *skb_put(skb, 1) = opcode;
put_unaligned_le16(hdev->id, skb_put(skb, 2)); put_unaligned_le16(hdev->id, skb_put(skb, 2));
skb_queue_tail(&data->readq, skb); skb_queue_tail(&data->readq, skb);
...@@ -146,7 +161,7 @@ static inline ssize_t vhci_get_user(struct vhci_data *data, ...@@ -146,7 +161,7 @@ static inline ssize_t vhci_get_user(struct vhci_data *data,
{ {
size_t len = iov_length(iov, count); size_t len = iov_length(iov, count);
struct sk_buff *skb; struct sk_buff *skb;
__u8 pkt_type, dev_type; __u8 pkt_type, opcode;
unsigned long i; unsigned long i;
int ret; int ret;
...@@ -190,7 +205,7 @@ static inline ssize_t vhci_get_user(struct vhci_data *data, ...@@ -190,7 +205,7 @@ static inline ssize_t vhci_get_user(struct vhci_data *data,
cancel_delayed_work_sync(&data->open_timeout); cancel_delayed_work_sync(&data->open_timeout);
dev_type = *((__u8 *) skb->data); opcode = *((__u8 *) skb->data);
skb_pull(skb, 1); skb_pull(skb, 1);
if (skb->len > 0) { if (skb->len > 0) {
...@@ -200,10 +215,7 @@ static inline ssize_t vhci_get_user(struct vhci_data *data, ...@@ -200,10 +215,7 @@ static inline ssize_t vhci_get_user(struct vhci_data *data,
kfree_skb(skb); kfree_skb(skb);
if (dev_type != HCI_BREDR && dev_type != HCI_AMP) ret = vhci_create_device(data, opcode);
return -EINVAL;
ret = vhci_create_device(data, dev_type);
break; break;
default: default:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment