Skip to content

Commit 23424c0

Browse files
holtmannGustavo Padovan
authored and
Gustavo Padovan
committed
Bluetooth: Add support creating virtual AMP controllers
So far the only option to create a virtual AMP controller was by setting a module parameter for the hci_vhci driver. This patch adds the functionality to define inline to create either a BR/EDR or an AMP controller. In addition the client will be informed which HCI controller index it got assigned. That is especially useful for automated end-to-end testing. To keep backwards compatibility with existing userspace, the command for creating a controller type needs to be send right after opening the device node. If the command is not send, it defaults back to automatically creating a BR/EDR controller. Signed-off-by: Marcel Holtmann <[email protected]> Signed-off-by: Gustavo Padovan <[email protected]>
1 parent bfacbb9 commit 23424c0

File tree

1 file changed

+123
-46
lines changed

1 file changed

+123
-46
lines changed

drivers/bluetooth/hci_vhci.c

Lines changed: 123 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
*/
2525

2626
#include <linux/module.h>
27+
#include <asm/unaligned.h>
2728

2829
#include <linux/kernel.h>
2930
#include <linux/init.h>
@@ -39,17 +40,17 @@
3940
#include <net/bluetooth/bluetooth.h>
4041
#include <net/bluetooth/hci_core.h>
4142

42-
#define VERSION "1.3"
43+
#define VERSION "1.4"
4344

4445
static bool amp;
4546

4647
struct vhci_data {
4748
struct hci_dev *hdev;
4849

49-
unsigned long flags;
50-
5150
wait_queue_head_t read_wait;
5251
struct sk_buff_head readq;
52+
53+
struct delayed_work open_timeout;
5354
};
5455

5556
static int vhci_open_dev(struct hci_dev *hdev)
@@ -99,16 +100,62 @@ static int vhci_send_frame(struct sk_buff *skb)
99100
skb_queue_tail(&data->readq, skb);
100101

101102
wake_up_interruptible(&data->read_wait);
103+
return 0;
104+
}
105+
106+
static int vhci_create_device(struct vhci_data *data, __u8 dev_type)
107+
{
108+
struct hci_dev *hdev;
109+
struct sk_buff *skb;
110+
111+
skb = bt_skb_alloc(4, GFP_KERNEL);
112+
if (!skb)
113+
return -ENOMEM;
114+
115+
hdev = hci_alloc_dev();
116+
if (!hdev) {
117+
kfree_skb(skb);
118+
return -ENOMEM;
119+
}
120+
121+
data->hdev = hdev;
122+
123+
hdev->bus = HCI_VIRTUAL;
124+
hdev->dev_type = dev_type;
125+
hci_set_drvdata(hdev, data);
126+
127+
hdev->open = vhci_open_dev;
128+
hdev->close = vhci_close_dev;
129+
hdev->flush = vhci_flush;
130+
hdev->send = vhci_send_frame;
102131

132+
if (hci_register_dev(hdev) < 0) {
133+
BT_ERR("Can't register HCI device");
134+
hci_free_dev(hdev);
135+
data->hdev = NULL;
136+
kfree_skb(skb);
137+
return -EBUSY;
138+
}
139+
140+
bt_cb(skb)->pkt_type = HCI_VENDOR_PKT;
141+
142+
*skb_put(skb, 1) = 0xff;
143+
*skb_put(skb, 1) = dev_type;
144+
put_unaligned_le16(hdev->id, skb_put(skb, 2));
145+
skb_queue_tail(&data->readq, skb);
146+
147+
wake_up_interruptible(&data->read_wait);
103148
return 0;
104149
}
105150

106151
static inline ssize_t vhci_get_user(struct vhci_data *data,
107-
const char __user *buf, size_t count)
152+
const char __user *buf, size_t count)
108153
{
109154
struct sk_buff *skb;
155+
__u8 pkt_type, dev_type;
156+
int ret;
110157

111-
if (count > HCI_MAX_FRAME_SIZE)
158+
if (count < 2 || count > HCI_MAX_FRAME_SIZE)
112159
return -EINVAL;
113160

114161
skb = bt_skb_alloc(count, GFP_KERNEL);
@@ -120,49 +167,90 @@ static inline ssize_t vhci_get_user(struct vhci_data *data,
120167
return -EFAULT;
121168
}
122169

123-
skb->dev = (void *) data->hdev;
124-
bt_cb(skb)->pkt_type = *((__u8 *) skb->data);
170+
pkt_type = *((__u8 *) skb->data);
125171
skb_pull(skb, 1);
126172

127-
hci_recv_frame(skb);
173+
switch (pkt_type) {
174+
case HCI_EVENT_PKT:
175+
case HCI_ACLDATA_PKT:
176+
case HCI_SCODATA_PKT:
177+
if (!data->hdev) {
178+
kfree_skb(skb);
179+
return -ENODEV;
180+
}
181+
182+
skb->dev = (void *) data->hdev;
183+
bt_cb(skb)->pkt_type = pkt_type;
184+
185+
ret = hci_recv_frame(skb);
186+
break;
187+
188+
case HCI_VENDOR_PKT:
189+
if (data->hdev) {
190+
kfree_skb(skb);
191+
return -EBADFD;
192+
}
128193

129-
return count;
194+
cancel_delayed_work_sync(&data->open_timeout);
195+
196+
dev_type = *((__u8 *) skb->data);
197+
skb_pull(skb, 1);
198+
199+
if (skb->len > 0) {
200+
kfree_skb(skb);
201+
return -EINVAL;
202+
}
203+
204+
kfree_skb(skb);
205+
206+
if (dev_type != HCI_BREDR && dev_type != HCI_AMP)
207+
return -EINVAL;
208+
209+
ret = vhci_create_device(data, dev_type);
210+
break;
211+
212+
default:
213+
kfree_skb(skb);
214+
return -EINVAL;
215+
}
216+
217+
return (ret < 0) ? ret : count;
130218
}
131219

132220
static inline ssize_t vhci_put_user(struct vhci_data *data,
133-
struct sk_buff *skb, char __user *buf, int count)
221+
struct sk_buff *skb,
222+
char __user *buf, int count)
134223
{
135224
char __user *ptr = buf;
136-
int len, total = 0;
225+
int len;
137226

138227
len = min_t(unsigned int, skb->len, count);
139228

140229
if (copy_to_user(ptr, skb->data, len))
141230
return -EFAULT;
142231

143-
total += len;
232+
if (!data->hdev)
233+
return len;
144234

145235
data->hdev->stat.byte_tx += len;
146236

147237
switch (bt_cb(skb)->pkt_type) {
148238
case HCI_COMMAND_PKT:
149239
data->hdev->stat.cmd_tx++;
150240
break;
151-
152241
case HCI_ACLDATA_PKT:
153242
data->hdev->stat.acl_tx++;
154243
break;
155-
156244
case HCI_SCODATA_PKT:
157245
data->hdev->stat.sco_tx++;
158246
break;
159247
}
160248

161-
return total;
249+
return len;
162250
}
163251

164252
static ssize_t vhci_read(struct file *file,
165-
char __user *buf, size_t count, loff_t *pos)
253+
char __user *buf, size_t count, loff_t *pos)
166254
{
167255
struct vhci_data *data = file->private_data;
168256
struct sk_buff *skb;
@@ -185,7 +273,7 @@ static ssize_t vhci_read(struct file *file,
185273
}
186274

187275
ret = wait_event_interruptible(data->read_wait,
188-
!skb_queue_empty(&data->readq));
276+
!skb_queue_empty(&data->readq));
189277
if (ret < 0)
190278
break;
191279
}
@@ -194,7 +282,7 @@ static ssize_t vhci_read(struct file *file,
194282
}
195283

196284
static ssize_t vhci_write(struct file *file,
197-
const char __user *buf, size_t count, loff_t *pos)
285+
const char __user *buf, size_t count, loff_t *pos)
198286
{
199287
struct vhci_data *data = file->private_data;
200288

@@ -213,10 +301,17 @@ static unsigned int vhci_poll(struct file *file, poll_table *wait)
213301
return POLLOUT | POLLWRNORM;
214302
}
215303

304+
static void vhci_open_timeout(struct work_struct *work)
305+
{
306+
struct vhci_data *data = container_of(work, struct vhci_data,
307+
open_timeout.work);
308+
309+
vhci_create_device(data, amp ? HCI_AMP : HCI_BREDR);
310+
}
311+
216312
static int vhci_open(struct inode *inode, struct file *file)
217313
{
218314
struct vhci_data *data;
219-
struct hci_dev *hdev;
220315

221316
data = kzalloc(sizeof(struct vhci_data), GFP_KERNEL);
222317
if (!data)
@@ -225,35 +320,13 @@ static int vhci_open(struct inode *inode, struct file *file)
225320
skb_queue_head_init(&data->readq);
226321
init_waitqueue_head(&data->read_wait);
227322

228-
hdev = hci_alloc_dev();
229-
if (!hdev) {
230-
kfree(data);
231-
return -ENOMEM;
232-
}
233-
234-
data->hdev = hdev;
235-
236-
hdev->bus = HCI_VIRTUAL;
237-
hci_set_drvdata(hdev, data);
238-
239-
if (amp)
240-
hdev->dev_type = HCI_AMP;
241-
242-
hdev->open = vhci_open_dev;
243-
hdev->close = vhci_close_dev;
244-
hdev->flush = vhci_flush;
245-
hdev->send = vhci_send_frame;
246-
247-
if (hci_register_dev(hdev) < 0) {
248-
BT_ERR("Can't register HCI device");
249-
kfree(data);
250-
hci_free_dev(hdev);
251-
return -EBUSY;
252-
}
323+
INIT_DELAYED_WORK(&data->open_timeout, vhci_open_timeout);
253324

254325
file->private_data = data;
255326
nonseekable_open(inode, file);
256327

328+
schedule_delayed_work(&data->open_timeout, msecs_to_jiffies(1000));
329+
257330
return 0;
258331
}
259332

@@ -262,8 +335,12 @@ static int vhci_release(struct inode *inode, struct file *file)
262335
struct vhci_data *data = file->private_data;
263336
struct hci_dev *hdev = data->hdev;
264337

265-
hci_unregister_dev(hdev);
266-
hci_free_dev(hdev);
338+
cancel_delayed_work_sync(&data->open_timeout);
339+
340+
if (hdev) {
341+
hci_unregister_dev(hdev);
342+
hci_free_dev(hdev);
343+
}
267344

268345
file->private_data = NULL;
269346
kfree(data);

0 commit comments

Comments
 (0)