Commit bb400801 authored by David S. Miller's avatar David S. Miller
parents 130aa61a 611b30f7
...@@ -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.2" #define VERSION "1.3"
static int minor = MISC_DYNAMIC_MINOR; static int minor = MISC_DYNAMIC_MINOR;
...@@ -51,14 +51,8 @@ struct vhci_data { ...@@ -51,14 +51,8 @@ struct vhci_data {
wait_queue_head_t read_wait; wait_queue_head_t read_wait;
struct sk_buff_head readq; struct sk_buff_head readq;
struct fasync_struct *fasync;
}; };
#define VHCI_FASYNC 0x0010
static struct miscdevice vhci_miscdev;
static int vhci_open_dev(struct hci_dev *hdev) static int vhci_open_dev(struct hci_dev *hdev)
{ {
set_bit(HCI_RUNNING, &hdev->flags); set_bit(HCI_RUNNING, &hdev->flags);
...@@ -105,9 +99,6 @@ static int vhci_send_frame(struct sk_buff *skb) ...@@ -105,9 +99,6 @@ static int vhci_send_frame(struct sk_buff *skb)
memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1); memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1);
skb_queue_tail(&data->readq, skb); skb_queue_tail(&data->readq, skb);
if (data->flags & VHCI_FASYNC)
kill_fasync(&data->fasync, SIGIO, POLL_IN);
wake_up_interruptible(&data->read_wait); wake_up_interruptible(&data->read_wait);
return 0; return 0;
...@@ -179,41 +170,31 @@ static inline ssize_t vhci_put_user(struct vhci_data *data, ...@@ -179,41 +170,31 @@ static inline ssize_t vhci_put_user(struct vhci_data *data,
static ssize_t vhci_read(struct file *file, static ssize_t vhci_read(struct file *file,
char __user *buf, size_t count, loff_t *pos) char __user *buf, size_t count, loff_t *pos)
{ {
DECLARE_WAITQUEUE(wait, current);
struct vhci_data *data = file->private_data; struct vhci_data *data = file->private_data;
struct sk_buff *skb; struct sk_buff *skb;
ssize_t ret = 0; ssize_t ret = 0;
add_wait_queue(&data->read_wait, &wait);
while (count) { while (count) {
set_current_state(TASK_INTERRUPTIBLE);
skb = skb_dequeue(&data->readq); skb = skb_dequeue(&data->readq);
if (!skb) { if (skb) {
if (file->f_flags & O_NONBLOCK) { ret = vhci_put_user(data, skb, buf, count);
ret = -EAGAIN; if (ret < 0)
break; skb_queue_head(&data->readq, skb);
} else
kfree_skb(skb);
if (signal_pending(current)) { break;
ret = -ERESTARTSYS;
break;
}
schedule();
continue;
} }
if (access_ok(VERIFY_WRITE, buf, count)) if (file->f_flags & O_NONBLOCK) {
ret = vhci_put_user(data, skb, buf, count); ret = -EAGAIN;
else break;
ret = -EFAULT; }
kfree_skb(skb); ret = wait_event_interruptible(data->read_wait,
break; !skb_queue_empty(&data->readq));
if (ret < 0)
break;
} }
set_current_state(TASK_RUNNING);
remove_wait_queue(&data->read_wait, &wait);
return ret; return ret;
} }
...@@ -223,9 +204,6 @@ static ssize_t vhci_write(struct file *file, ...@@ -223,9 +204,6 @@ static ssize_t vhci_write(struct file *file,
{ {
struct vhci_data *data = file->private_data; struct vhci_data *data = file->private_data;
if (!access_ok(VERIFY_READ, buf, count))
return -EFAULT;
return vhci_get_user(data, buf, count); return vhci_get_user(data, buf, count);
} }
...@@ -259,11 +237,9 @@ static int vhci_open(struct inode *inode, struct file *file) ...@@ -259,11 +237,9 @@ static int vhci_open(struct inode *inode, struct file *file)
skb_queue_head_init(&data->readq); skb_queue_head_init(&data->readq);
init_waitqueue_head(&data->read_wait); init_waitqueue_head(&data->read_wait);
lock_kernel();
hdev = hci_alloc_dev(); hdev = hci_alloc_dev();
if (!hdev) { if (!hdev) {
kfree(data); kfree(data);
unlock_kernel();
return -ENOMEM; return -ENOMEM;
} }
...@@ -284,12 +260,10 @@ static int vhci_open(struct inode *inode, struct file *file) ...@@ -284,12 +260,10 @@ static int vhci_open(struct inode *inode, struct file *file)
BT_ERR("Can't register HCI device"); BT_ERR("Can't register HCI device");
kfree(data); kfree(data);
hci_free_dev(hdev); hci_free_dev(hdev);
unlock_kernel();
return -EBUSY; return -EBUSY;
} }
file->private_data = data; file->private_data = data;
unlock_kernel();
return nonseekable_open(inode, file); return nonseekable_open(inode, file);
} }
...@@ -310,48 +284,25 @@ static int vhci_release(struct inode *inode, struct file *file) ...@@ -310,48 +284,25 @@ static int vhci_release(struct inode *inode, struct file *file)
return 0; return 0;
} }
static int vhci_fasync(int fd, struct file *file, int on)
{
struct vhci_data *data = file->private_data;
int err = 0;
lock_kernel();
err = fasync_helper(fd, file, on, &data->fasync);
if (err < 0)
goto out;
if (on)
data->flags |= VHCI_FASYNC;
else
data->flags &= ~VHCI_FASYNC;
out:
unlock_kernel();
return err;
}
static const struct file_operations vhci_fops = { static const struct file_operations vhci_fops = {
.owner = THIS_MODULE,
.read = vhci_read, .read = vhci_read,
.write = vhci_write, .write = vhci_write,
.poll = vhci_poll, .poll = vhci_poll,
.ioctl = vhci_ioctl, .ioctl = vhci_ioctl,
.open = vhci_open, .open = vhci_open,
.release = vhci_release, .release = vhci_release,
.fasync = vhci_fasync,
}; };
static struct miscdevice vhci_miscdev= { static struct miscdevice vhci_miscdev= {
.name = "vhci", .name = "vhci",
.fops = &vhci_fops, .fops = &vhci_fops,
.minor = MISC_DYNAMIC_MINOR,
}; };
static int __init vhci_init(void) static int __init vhci_init(void)
{ {
BT_INFO("Virtual HCI driver ver %s", VERSION); BT_INFO("Virtual HCI driver ver %s", VERSION);
vhci_miscdev.minor = minor;
if (misc_register(&vhci_miscdev) < 0) { if (misc_register(&vhci_miscdev) < 0) {
BT_ERR("Can't register misc device with minor %d", minor); BT_ERR("Can't register misc device with minor %d", minor);
return -EIO; return -EIO;
...@@ -369,9 +320,6 @@ static void __exit vhci_exit(void) ...@@ -369,9 +320,6 @@ static void __exit vhci_exit(void)
module_init(vhci_init); module_init(vhci_init);
module_exit(vhci_exit); module_exit(vhci_exit);
module_param(minor, int, 0444);
MODULE_PARM_DESC(minor, "Miscellaneous minor device number");
MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>"); MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
MODULE_DESCRIPTION("Bluetooth virtual HCI driver ver " VERSION); MODULE_DESCRIPTION("Bluetooth virtual HCI driver ver " VERSION);
MODULE_VERSION(VERSION); MODULE_VERSION(VERSION);
......
...@@ -81,12 +81,6 @@ enum { ...@@ -81,12 +81,6 @@ enum {
BT_CLOSED BT_CLOSED
}; };
/* Endianness conversions */
#define htobs(a) __cpu_to_le16(a)
#define htobl(a) __cpu_to_le32(a)
#define btohs(a) __le16_to_cpu(a)
#define btohl(a) __le32_to_cpu(a)
/* BD Address */ /* BD Address */
typedef struct { typedef struct {
__u8 b[6]; __u8 b[6];
......
...@@ -137,6 +137,8 @@ struct hci_dev { ...@@ -137,6 +137,8 @@ struct hci_dev {
struct device *parent; struct device *parent;
struct device dev; struct device dev;
struct rfkill *rfkill;
struct module *owner; struct module *owner;
int (*open)(struct hci_dev *hdev); int (*open)(struct hci_dev *hdev);
......
...@@ -26,8 +26,13 @@ ...@@ -26,8 +26,13 @@
#define __L2CAP_H #define __L2CAP_H
/* L2CAP defaults */ /* L2CAP defaults */
#define L2CAP_DEFAULT_MTU 672 #define L2CAP_DEFAULT_MTU 672
#define L2CAP_DEFAULT_FLUSH_TO 0xFFFF #define L2CAP_DEFAULT_FLUSH_TO 0xffff
#define L2CAP_DEFAULT_RX_WINDOW 1
#define L2CAP_DEFAULT_MAX_RECEIVE 1
#define L2CAP_DEFAULT_RETRANS_TO 300 /* 300 milliseconds */
#define L2CAP_DEFAULT_MONITOR_TO 1000 /* 1 second */
#define L2CAP_DEFAULT_MAX_RX_APDU 0xfff7
#define L2CAP_CONN_TIMEOUT (40000) /* 40 seconds */ #define L2CAP_CONN_TIMEOUT (40000) /* 40 seconds */
#define L2CAP_INFO_TIMEOUT (4000) /* 4 seconds */ #define L2CAP_INFO_TIMEOUT (4000) /* 4 seconds */
...@@ -64,17 +69,29 @@ struct l2cap_conninfo { ...@@ -64,17 +69,29 @@ struct l2cap_conninfo {
#define L2CAP_LM_SECURE 0x0020 #define L2CAP_LM_SECURE 0x0020
/* L2CAP command codes */ /* L2CAP command codes */
#define L2CAP_COMMAND_REJ 0x01 #define L2CAP_COMMAND_REJ 0x01
#define L2CAP_CONN_REQ 0x02 #define L2CAP_CONN_REQ 0x02
#define L2CAP_CONN_RSP 0x03 #define L2CAP_CONN_RSP 0x03
#define L2CAP_CONF_REQ 0x04 #define L2CAP_CONF_REQ 0x04
#define L2CAP_CONF_RSP 0x05 #define L2CAP_CONF_RSP 0x05
#define L2CAP_DISCONN_REQ 0x06 #define L2CAP_DISCONN_REQ 0x06
#define L2CAP_DISCONN_RSP 0x07 #define L2CAP_DISCONN_RSP 0x07
#define L2CAP_ECHO_REQ 0x08 #define L2CAP_ECHO_REQ 0x08
#define L2CAP_ECHO_RSP 0x09 #define L2CAP_ECHO_RSP 0x09
#define L2CAP_INFO_REQ 0x0a #define L2CAP_INFO_REQ 0x0a
#define L2CAP_INFO_RSP 0x0b #define L2CAP_INFO_RSP 0x0b
/* L2CAP feature mask */
#define L2CAP_FEAT_FLOWCTL 0x00000001
#define L2CAP_FEAT_RETRANS 0x00000002
#define L2CAP_FEAT_ERTM 0x00000008
#define L2CAP_FEAT_STREAMING 0x00000010
#define L2CAP_FEAT_FCS 0x00000020
#define L2CAP_FEAT_FIXED_CHAN 0x00000080
/* L2CAP checksum option */
#define L2CAP_FCS_NONE 0x00
#define L2CAP_FCS_CRC16 0x01
/* L2CAP structures */ /* L2CAP structures */
struct l2cap_hdr { struct l2cap_hdr {
...@@ -106,17 +123,23 @@ struct l2cap_conn_rsp { ...@@ -106,17 +123,23 @@ struct l2cap_conn_rsp {
__le16 status; __le16 status;
} __attribute__ ((packed)); } __attribute__ ((packed));
/* channel indentifier */
#define L2CAP_CID_SIGNALING 0x0001
#define L2CAP_CID_CONN_LESS 0x0002
#define L2CAP_CID_DYN_START 0x0040
#define L2CAP_CID_DYN_END 0xffff
/* connect result */ /* connect result */
#define L2CAP_CR_SUCCESS 0x0000 #define L2CAP_CR_SUCCESS 0x0000
#define L2CAP_CR_PEND 0x0001 #define L2CAP_CR_PEND 0x0001
#define L2CAP_CR_BAD_PSM 0x0002 #define L2CAP_CR_BAD_PSM 0x0002
#define L2CAP_CR_SEC_BLOCK 0x0003 #define L2CAP_CR_SEC_BLOCK 0x0003
#define L2CAP_CR_NO_MEM 0x0004 #define L2CAP_CR_NO_MEM 0x0004
/* connect status */ /* connect status */
#define L2CAP_CS_NO_INFO 0x0000 #define L2CAP_CS_NO_INFO 0x0000
#define L2CAP_CS_AUTHEN_PEND 0x0001 #define L2CAP_CS_AUTHEN_PEND 0x0001
#define L2CAP_CS_AUTHOR_PEND 0x0002 #define L2CAP_CS_AUTHOR_PEND 0x0002
struct l2cap_conf_req { struct l2cap_conf_req {
__le16 dcid; __le16 dcid;
...@@ -143,10 +166,14 @@ struct l2cap_conf_opt { ...@@ -143,10 +166,14 @@ struct l2cap_conf_opt {
} __attribute__ ((packed)); } __attribute__ ((packed));
#define L2CAP_CONF_OPT_SIZE 2 #define L2CAP_CONF_OPT_SIZE 2
#define L2CAP_CONF_HINT 0x80
#define L2CAP_CONF_MASK 0x7f
#define L2CAP_CONF_MTU 0x01 #define L2CAP_CONF_MTU 0x01
#define L2CAP_CONF_FLUSH_TO 0x02 #define L2CAP_CONF_FLUSH_TO 0x02
#define L2CAP_CONF_QOS 0x03 #define L2CAP_CONF_QOS 0x03
#define L2CAP_CONF_RFC 0x04 #define L2CAP_CONF_RFC 0x04
#define L2CAP_CONF_FCS 0x05
#define L2CAP_CONF_MAX_SIZE 22 #define L2CAP_CONF_MAX_SIZE 22
...@@ -162,6 +189,8 @@ struct l2cap_conf_rfc { ...@@ -162,6 +189,8 @@ struct l2cap_conf_rfc {
#define L2CAP_MODE_BASIC 0x00 #define L2CAP_MODE_BASIC 0x00
#define L2CAP_MODE_RETRANS 0x01 #define L2CAP_MODE_RETRANS 0x01
#define L2CAP_MODE_FLOWCTL 0x02 #define L2CAP_MODE_FLOWCTL 0x02
#define L2CAP_MODE_ERTM 0x03
#define L2CAP_MODE_STREAM 0x04
struct l2cap_disconn_req { struct l2cap_disconn_req {
__le16 dcid; __le16 dcid;
......
...@@ -39,6 +39,7 @@ ...@@ -39,6 +39,7 @@
#include <linux/skbuff.h> #include <linux/skbuff.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/notifier.h> #include <linux/notifier.h>
#include <linux/rfkill.h>
#include <net/sock.h> #include <net/sock.h>
#include <asm/system.h> #include <asm/system.h>
...@@ -476,6 +477,11 @@ int hci_dev_open(__u16 dev) ...@@ -476,6 +477,11 @@ int hci_dev_open(__u16 dev)
hci_req_lock(hdev); hci_req_lock(hdev);
if (hdev->rfkill && rfkill_blocked(hdev->rfkill)) {
ret = -ERFKILL;
goto done;
}
if (test_bit(HCI_UP, &hdev->flags)) { if (test_bit(HCI_UP, &hdev->flags)) {
ret = -EALREADY; ret = -EALREADY;
goto done; goto done;
...@@ -813,6 +819,24 @@ int hci_get_dev_info(void __user *arg) ...@@ -813,6 +819,24 @@ int hci_get_dev_info(void __user *arg)
/* ---- Interface to HCI drivers ---- */ /* ---- Interface to HCI drivers ---- */
static int hci_rfkill_set_block(void *data, bool blocked)
{
struct hci_dev *hdev = data;
BT_DBG("%p name %s blocked %d", hdev, hdev->name, blocked);
if (!blocked)
return 0;
hci_dev_do_close(hdev);
return 0;
}
static const struct rfkill_ops hci_rfkill_ops = {
.set_block = hci_rfkill_set_block,
};
/* Alloc HCI device */ /* Alloc HCI device */
struct hci_dev *hci_alloc_dev(void) struct hci_dev *hci_alloc_dev(void)
{ {
...@@ -844,7 +868,8 @@ int hci_register_dev(struct hci_dev *hdev) ...@@ -844,7 +868,8 @@ int hci_register_dev(struct hci_dev *hdev)
struct list_head *head = &hci_dev_list, *p; struct list_head *head = &hci_dev_list, *p;
int i, id = 0; int i, id = 0;
BT_DBG("%p name %s type %d owner %p", hdev, hdev->name, hdev->type, hdev->owner); BT_DBG("%p name %s type %d owner %p", hdev, hdev->name,
hdev->type, hdev->owner);
if (!hdev->open || !hdev->close || !hdev->destruct) if (!hdev->open || !hdev->close || !hdev->destruct)
return -EINVAL; return -EINVAL;
...@@ -900,6 +925,15 @@ int hci_register_dev(struct hci_dev *hdev) ...@@ -900,6 +925,15 @@ int hci_register_dev(struct hci_dev *hdev)
hci_register_sysfs(hdev); hci_register_sysfs(hdev);
hdev->rfkill = rfkill_alloc(hdev->name, &hdev->dev,
RFKILL_TYPE_BLUETOOTH, &hci_rfkill_ops, hdev);
if (hdev->rfkill) {
if (rfkill_register(hdev->rfkill) < 0) {
rfkill_destroy(hdev->rfkill);
hdev->rfkill = NULL;
}
}
hci_notify(hdev, HCI_DEV_REG); hci_notify(hdev, HCI_DEV_REG);
return id; return id;
...@@ -924,6 +958,11 @@ int hci_unregister_dev(struct hci_dev *hdev) ...@@ -924,6 +958,11 @@ int hci_unregister_dev(struct hci_dev *hdev)
hci_notify(hdev, HCI_DEV_UNREG); hci_notify(hdev, HCI_DEV_UNREG);
if (hdev->rfkill) {
rfkill_unregister(hdev->rfkill);
rfkill_destroy(hdev->rfkill);
}
hci_unregister_sysfs(hdev); hci_unregister_sysfs(hdev);
__hci_dev_put(hdev); __hci_dev_put(hdev);
......
This diff is collapsed.
...@@ -679,7 +679,7 @@ static struct rfcomm_session *rfcomm_session_create(bdaddr_t *src, bdaddr_t *dst ...@@ -679,7 +679,7 @@ static struct rfcomm_session *rfcomm_session_create(bdaddr_t *src, bdaddr_t *dst
bacpy(&addr.l2_bdaddr, dst); bacpy(&addr.l2_bdaddr, dst);
addr.l2_family = AF_BLUETOOTH; addr.l2_family = AF_BLUETOOTH;
addr.l2_psm = htobs(RFCOMM_PSM); addr.l2_psm = cpu_to_le16(RFCOMM_PSM);
addr.l2_cid = 0; addr.l2_cid = 0;
*err = kernel_connect(sock, (struct sockaddr *) &addr, sizeof(addr), O_NONBLOCK); *err = kernel_connect(sock, (struct sockaddr *) &addr, sizeof(addr), O_NONBLOCK);
if (*err == 0 || *err == -EINPROGRESS) if (*err == 0 || *err == -EINPROGRESS)
...@@ -852,9 +852,9 @@ static int rfcomm_send_pn(struct rfcomm_session *s, int cr, struct rfcomm_dlc *d ...@@ -852,9 +852,9 @@ static int rfcomm_send_pn(struct rfcomm_session *s, int cr, struct rfcomm_dlc *d
} }
if (cr && channel_mtu >= 0) if (cr && channel_mtu >= 0)
pn->mtu = htobs(channel_mtu); pn->mtu = cpu_to_le16(channel_mtu);
else else
pn->mtu = htobs(d->mtu); pn->mtu = cpu_to_le16(d->mtu);
*ptr = __fcs(buf); ptr++; *ptr = __fcs(buf); ptr++;
...@@ -1056,7 +1056,7 @@ static void rfcomm_make_uih(struct sk_buff *skb, u8 addr) ...@@ -1056,7 +1056,7 @@ static void rfcomm_make_uih(struct sk_buff *skb, u8 addr)
if (len > 127) { if (len > 127) {
hdr = (void *) skb_push(skb, 4); hdr = (void *) skb_push(skb, 4);
put_unaligned(htobs(__len16(len)), (__le16 *) &hdr->len); put_unaligned(cpu_to_le16(__len16(len)), (__le16 *) &hdr->len);
} else { } else {
hdr = (void *) skb_push(skb, 3); hdr = (void *) skb_push(skb, 3);
hdr->len = __len8(len); hdr->len = __len8(len);
...@@ -1289,7 +1289,7 @@ static int rfcomm_apply_pn(struct rfcomm_dlc *d, int cr, struct rfcomm_pn *pn) ...@@ -1289,7 +1289,7 @@ static int rfcomm_apply_pn(struct rfcomm_dlc *d, int cr, struct rfcomm_pn *pn)
d->priority = pn->priority; d->priority = pn->priority;
d->mtu = btohs(pn->mtu); d->mtu = __le16_to_cpu(pn->mtu);
if (cr && d->mtu > s->mtu) if (cr && d->mtu > s->mtu)
d->mtu = s->mtu; d->mtu = s->mtu;
...@@ -1922,7 +1922,7 @@ static int rfcomm_add_listener(bdaddr_t *ba) ...@@ -1922,7 +1922,7 @@ static int rfcomm_add_listener(bdaddr_t *ba)
/* Bind socket */ /* Bind socket */
bacpy(&addr.l2_bdaddr, ba); bacpy(&addr.l2_bdaddr, ba);
addr.l2_family = AF_BLUETOOTH; addr.l2_family = AF_BLUETOOTH;
addr.l2_psm = htobs(RFCOMM_PSM); addr.l2_psm = cpu_to_le16(RFCOMM_PSM);
addr.l2_cid = 0; addr.l2_cid = 0;
err = kernel_bind(sock, (struct sockaddr *) &addr, sizeof(addr)); err = kernel_bind(sock, (struct sockaddr *) &addr, sizeof(addr));
if (err < 0) { if (err < 0) {
......
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