mirror of
https://github.com/FEX-Emu/linux.git
synced 2024-12-23 09:56:00 +00:00
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/padovan/bluetooth-next
This commit is contained in:
commit
0111ad823e
@ -65,12 +65,14 @@ static struct usb_device_id ath3k_table[] = {
|
||||
{ USB_DEVICE(0x0CF3, 0x3002) },
|
||||
{ USB_DEVICE(0x13d3, 0x3304) },
|
||||
{ USB_DEVICE(0x0930, 0x0215) },
|
||||
{ USB_DEVICE(0x0489, 0xE03D) },
|
||||
|
||||
/* Atheros AR9285 Malbec with sflash firmware */
|
||||
{ USB_DEVICE(0x03F0, 0x311D) },
|
||||
|
||||
/* Atheros AR3012 with sflash firmware*/
|
||||
{ USB_DEVICE(0x0CF3, 0x3004) },
|
||||
{ USB_DEVICE(0x13d3, 0x3375) },
|
||||
|
||||
/* Atheros AR5BBU12 with sflash firmware */
|
||||
{ USB_DEVICE(0x0489, 0xE02C) },
|
||||
@ -87,6 +89,7 @@ static struct usb_device_id ath3k_blist_tbl[] = {
|
||||
|
||||
/* Atheros AR3012 with sflash firmware*/
|
||||
{ USB_DEVICE(0x0cf3, 0x3004), .driver_info = BTUSB_ATH3012 },
|
||||
{ USB_DEVICE(0x13d3, 0x3375), .driver_info = BTUSB_ATH3012 },
|
||||
|
||||
{ } /* Terminating entry */
|
||||
};
|
||||
|
@ -411,7 +411,7 @@ unlock:
|
||||
|
||||
static int bfusb_open(struct hci_dev *hdev)
|
||||
{
|
||||
struct bfusb_data *data = hdev->driver_data;
|
||||
struct bfusb_data *data = hci_get_drvdata(hdev);
|
||||
unsigned long flags;
|
||||
int i, err;
|
||||
|
||||
@ -437,7 +437,7 @@ static int bfusb_open(struct hci_dev *hdev)
|
||||
|
||||
static int bfusb_flush(struct hci_dev *hdev)
|
||||
{
|
||||
struct bfusb_data *data = hdev->driver_data;
|
||||
struct bfusb_data *data = hci_get_drvdata(hdev);
|
||||
|
||||
BT_DBG("hdev %p bfusb %p", hdev, data);
|
||||
|
||||
@ -448,7 +448,7 @@ static int bfusb_flush(struct hci_dev *hdev)
|
||||
|
||||
static int bfusb_close(struct hci_dev *hdev)
|
||||
{
|
||||
struct bfusb_data *data = hdev->driver_data;
|
||||
struct bfusb_data *data = hci_get_drvdata(hdev);
|
||||
unsigned long flags;
|
||||
|
||||
BT_DBG("hdev %p bfusb %p", hdev, data);
|
||||
@ -483,7 +483,7 @@ static int bfusb_send_frame(struct sk_buff *skb)
|
||||
if (!test_bit(HCI_RUNNING, &hdev->flags))
|
||||
return -EBUSY;
|
||||
|
||||
data = hdev->driver_data;
|
||||
data = hci_get_drvdata(hdev);
|
||||
|
||||
switch (bt_cb(skb)->pkt_type) {
|
||||
case HCI_COMMAND_PKT:
|
||||
@ -544,15 +544,6 @@ static int bfusb_send_frame(struct sk_buff *skb)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void bfusb_destruct(struct hci_dev *hdev)
|
||||
{
|
||||
struct bfusb_data *data = hdev->driver_data;
|
||||
|
||||
BT_DBG("hdev %p bfusb %p", hdev, data);
|
||||
|
||||
kfree(data);
|
||||
}
|
||||
|
||||
static int bfusb_ioctl(struct hci_dev *hdev, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
return -ENOIOCTLCMD;
|
||||
@ -705,18 +696,15 @@ static int bfusb_probe(struct usb_interface *intf, const struct usb_device_id *i
|
||||
data->hdev = hdev;
|
||||
|
||||
hdev->bus = HCI_USB;
|
||||
hdev->driver_data = data;
|
||||
hci_set_drvdata(hdev, data);
|
||||
SET_HCIDEV_DEV(hdev, &intf->dev);
|
||||
|
||||
hdev->open = bfusb_open;
|
||||
hdev->close = bfusb_close;
|
||||
hdev->flush = bfusb_flush;
|
||||
hdev->send = bfusb_send_frame;
|
||||
hdev->destruct = bfusb_destruct;
|
||||
hdev->ioctl = bfusb_ioctl;
|
||||
|
||||
hdev->owner = THIS_MODULE;
|
||||
|
||||
if (hci_register_dev(hdev) < 0) {
|
||||
BT_ERR("Can't register HCI device");
|
||||
hci_free_dev(hdev);
|
||||
@ -753,6 +741,7 @@ static void bfusb_disconnect(struct usb_interface *intf)
|
||||
|
||||
hci_unregister_dev(hdev);
|
||||
hci_free_dev(hdev);
|
||||
kfree(data);
|
||||
}
|
||||
|
||||
static struct usb_driver bfusb_driver = {
|
||||
|
@ -561,7 +561,7 @@ static irqreturn_t bluecard_interrupt(int irq, void *dev_inst)
|
||||
|
||||
static int bluecard_hci_set_baud_rate(struct hci_dev *hdev, int baud)
|
||||
{
|
||||
bluecard_info_t *info = (bluecard_info_t *)(hdev->driver_data);
|
||||
bluecard_info_t *info = hci_get_drvdata(hdev);
|
||||
struct sk_buff *skb;
|
||||
|
||||
/* Ericsson baud rate command */
|
||||
@ -609,7 +609,7 @@ static int bluecard_hci_set_baud_rate(struct hci_dev *hdev, int baud)
|
||||
|
||||
static int bluecard_hci_flush(struct hci_dev *hdev)
|
||||
{
|
||||
bluecard_info_t *info = (bluecard_info_t *)(hdev->driver_data);
|
||||
bluecard_info_t *info = hci_get_drvdata(hdev);
|
||||
|
||||
/* Drop TX queue */
|
||||
skb_queue_purge(&(info->txq));
|
||||
@ -620,7 +620,7 @@ static int bluecard_hci_flush(struct hci_dev *hdev)
|
||||
|
||||
static int bluecard_hci_open(struct hci_dev *hdev)
|
||||
{
|
||||
bluecard_info_t *info = (bluecard_info_t *)(hdev->driver_data);
|
||||
bluecard_info_t *info = hci_get_drvdata(hdev);
|
||||
unsigned int iobase = info->p_dev->resource[0]->start;
|
||||
|
||||
if (test_bit(CARD_HAS_PCCARD_ID, &(info->hw_state)))
|
||||
@ -640,7 +640,7 @@ static int bluecard_hci_open(struct hci_dev *hdev)
|
||||
|
||||
static int bluecard_hci_close(struct hci_dev *hdev)
|
||||
{
|
||||
bluecard_info_t *info = (bluecard_info_t *)(hdev->driver_data);
|
||||
bluecard_info_t *info = hci_get_drvdata(hdev);
|
||||
unsigned int iobase = info->p_dev->resource[0]->start;
|
||||
|
||||
if (!test_and_clear_bit(HCI_RUNNING, &(hdev->flags)))
|
||||
@ -667,7 +667,7 @@ static int bluecard_hci_send_frame(struct sk_buff *skb)
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
info = (bluecard_info_t *)(hdev->driver_data);
|
||||
info = hci_get_drvdata(hdev);
|
||||
|
||||
switch (bt_cb(skb)->pkt_type) {
|
||||
case HCI_COMMAND_PKT:
|
||||
@ -691,11 +691,6 @@ static int bluecard_hci_send_frame(struct sk_buff *skb)
|
||||
}
|
||||
|
||||
|
||||
static void bluecard_hci_destruct(struct hci_dev *hdev)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
static int bluecard_hci_ioctl(struct hci_dev *hdev, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
return -ENOIOCTLCMD;
|
||||
@ -734,18 +729,15 @@ static int bluecard_open(bluecard_info_t *info)
|
||||
info->hdev = hdev;
|
||||
|
||||
hdev->bus = HCI_PCCARD;
|
||||
hdev->driver_data = info;
|
||||
hci_set_drvdata(hdev, info);
|
||||
SET_HCIDEV_DEV(hdev, &info->p_dev->dev);
|
||||
|
||||
hdev->open = bluecard_hci_open;
|
||||
hdev->close = bluecard_hci_close;
|
||||
hdev->flush = bluecard_hci_flush;
|
||||
hdev->send = bluecard_hci_send_frame;
|
||||
hdev->destruct = bluecard_hci_destruct;
|
||||
hdev->ioctl = bluecard_hci_ioctl;
|
||||
|
||||
hdev->owner = THIS_MODULE;
|
||||
|
||||
id = inb(iobase + 0x30);
|
||||
|
||||
if ((id & 0x0f) == 0x02)
|
||||
|
@ -66,7 +66,7 @@ struct hci_vendor_hdr {
|
||||
|
||||
static int bpa10x_recv(struct hci_dev *hdev, int queue, void *buf, int count)
|
||||
{
|
||||
struct bpa10x_data *data = hdev->driver_data;
|
||||
struct bpa10x_data *data = hci_get_drvdata(hdev);
|
||||
|
||||
BT_DBG("%s queue %d buffer %p count %d", hdev->name,
|
||||
queue, buf, count);
|
||||
@ -189,7 +189,7 @@ done:
|
||||
static void bpa10x_rx_complete(struct urb *urb)
|
||||
{
|
||||
struct hci_dev *hdev = urb->context;
|
||||
struct bpa10x_data *data = hdev->driver_data;
|
||||
struct bpa10x_data *data = hci_get_drvdata(hdev);
|
||||
int err;
|
||||
|
||||
BT_DBG("%s urb %p status %d count %d", hdev->name,
|
||||
@ -219,7 +219,7 @@ static void bpa10x_rx_complete(struct urb *urb)
|
||||
|
||||
static inline int bpa10x_submit_intr_urb(struct hci_dev *hdev)
|
||||
{
|
||||
struct bpa10x_data *data = hdev->driver_data;
|
||||
struct bpa10x_data *data = hci_get_drvdata(hdev);
|
||||
struct urb *urb;
|
||||
unsigned char *buf;
|
||||
unsigned int pipe;
|
||||
@ -260,7 +260,7 @@ static inline int bpa10x_submit_intr_urb(struct hci_dev *hdev)
|
||||
|
||||
static inline int bpa10x_submit_bulk_urb(struct hci_dev *hdev)
|
||||
{
|
||||
struct bpa10x_data *data = hdev->driver_data;
|
||||
struct bpa10x_data *data = hci_get_drvdata(hdev);
|
||||
struct urb *urb;
|
||||
unsigned char *buf;
|
||||
unsigned int pipe;
|
||||
@ -301,7 +301,7 @@ static inline int bpa10x_submit_bulk_urb(struct hci_dev *hdev)
|
||||
|
||||
static int bpa10x_open(struct hci_dev *hdev)
|
||||
{
|
||||
struct bpa10x_data *data = hdev->driver_data;
|
||||
struct bpa10x_data *data = hci_get_drvdata(hdev);
|
||||
int err;
|
||||
|
||||
BT_DBG("%s", hdev->name);
|
||||
@ -329,7 +329,7 @@ error:
|
||||
|
||||
static int bpa10x_close(struct hci_dev *hdev)
|
||||
{
|
||||
struct bpa10x_data *data = hdev->driver_data;
|
||||
struct bpa10x_data *data = hci_get_drvdata(hdev);
|
||||
|
||||
BT_DBG("%s", hdev->name);
|
||||
|
||||
@ -343,7 +343,7 @@ static int bpa10x_close(struct hci_dev *hdev)
|
||||
|
||||
static int bpa10x_flush(struct hci_dev *hdev)
|
||||
{
|
||||
struct bpa10x_data *data = hdev->driver_data;
|
||||
struct bpa10x_data *data = hci_get_drvdata(hdev);
|
||||
|
||||
BT_DBG("%s", hdev->name);
|
||||
|
||||
@ -355,7 +355,7 @@ static int bpa10x_flush(struct hci_dev *hdev)
|
||||
static int bpa10x_send_frame(struct sk_buff *skb)
|
||||
{
|
||||
struct hci_dev *hdev = (struct hci_dev *) skb->dev;
|
||||
struct bpa10x_data *data = hdev->driver_data;
|
||||
struct bpa10x_data *data = hci_get_drvdata(hdev);
|
||||
struct usb_ctrlrequest *dr;
|
||||
struct urb *urb;
|
||||
unsigned int pipe;
|
||||
@ -432,17 +432,6 @@ static int bpa10x_send_frame(struct sk_buff *skb)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void bpa10x_destruct(struct hci_dev *hdev)
|
||||
{
|
||||
struct bpa10x_data *data = hdev->driver_data;
|
||||
|
||||
BT_DBG("%s", hdev->name);
|
||||
|
||||
kfree_skb(data->rx_skb[0]);
|
||||
kfree_skb(data->rx_skb[1]);
|
||||
kfree(data);
|
||||
}
|
||||
|
||||
static int bpa10x_probe(struct usb_interface *intf, const struct usb_device_id *id)
|
||||
{
|
||||
struct bpa10x_data *data;
|
||||
@ -470,7 +459,7 @@ static int bpa10x_probe(struct usb_interface *intf, const struct usb_device_id *
|
||||
}
|
||||
|
||||
hdev->bus = HCI_USB;
|
||||
hdev->driver_data = data;
|
||||
hci_set_drvdata(hdev, data);
|
||||
|
||||
data->hdev = hdev;
|
||||
|
||||
@ -480,9 +469,6 @@ static int bpa10x_probe(struct usb_interface *intf, const struct usb_device_id *
|
||||
hdev->close = bpa10x_close;
|
||||
hdev->flush = bpa10x_flush;
|
||||
hdev->send = bpa10x_send_frame;
|
||||
hdev->destruct = bpa10x_destruct;
|
||||
|
||||
hdev->owner = THIS_MODULE;
|
||||
|
||||
set_bit(HCI_QUIRK_NO_RESET, &hdev->quirks);
|
||||
|
||||
@ -512,6 +498,9 @@ static void bpa10x_disconnect(struct usb_interface *intf)
|
||||
hci_unregister_dev(data->hdev);
|
||||
|
||||
hci_free_dev(data->hdev);
|
||||
kfree_skb(data->rx_skb[0]);
|
||||
kfree_skb(data->rx_skb[1]);
|
||||
kfree(data);
|
||||
}
|
||||
|
||||
static struct usb_driver bpa10x_driver = {
|
||||
|
@ -389,7 +389,7 @@ static irqreturn_t bt3c_interrupt(int irq, void *dev_inst)
|
||||
|
||||
static int bt3c_hci_flush(struct hci_dev *hdev)
|
||||
{
|
||||
bt3c_info_t *info = (bt3c_info_t *)(hdev->driver_data);
|
||||
bt3c_info_t *info = hci_get_drvdata(hdev);
|
||||
|
||||
/* Drop TX queue */
|
||||
skb_queue_purge(&(info->txq));
|
||||
@ -428,7 +428,7 @@ static int bt3c_hci_send_frame(struct sk_buff *skb)
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
info = (bt3c_info_t *) (hdev->driver_data);
|
||||
info = hci_get_drvdata(hdev);
|
||||
|
||||
switch (bt_cb(skb)->pkt_type) {
|
||||
case HCI_COMMAND_PKT:
|
||||
@ -456,11 +456,6 @@ static int bt3c_hci_send_frame(struct sk_buff *skb)
|
||||
}
|
||||
|
||||
|
||||
static void bt3c_hci_destruct(struct hci_dev *hdev)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
static int bt3c_hci_ioctl(struct hci_dev *hdev, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
return -ENOIOCTLCMD;
|
||||
@ -580,18 +575,15 @@ static int bt3c_open(bt3c_info_t *info)
|
||||
info->hdev = hdev;
|
||||
|
||||
hdev->bus = HCI_PCCARD;
|
||||
hdev->driver_data = info;
|
||||
hci_set_drvdata(hdev, info);
|
||||
SET_HCIDEV_DEV(hdev, &info->p_dev->dev);
|
||||
|
||||
hdev->open = bt3c_hci_open;
|
||||
hdev->close = bt3c_hci_close;
|
||||
hdev->flush = bt3c_hci_flush;
|
||||
hdev->send = bt3c_hci_send_frame;
|
||||
hdev->destruct = bt3c_hci_destruct;
|
||||
hdev->ioctl = bt3c_hci_ioctl;
|
||||
|
||||
hdev->owner = THIS_MODULE;
|
||||
|
||||
/* Load firmware */
|
||||
err = request_firmware(&firmware, "BT3CPCC.bin", &info->p_dev->dev);
|
||||
if (err < 0) {
|
||||
|
@ -384,7 +384,7 @@ static const struct file_operations btmrvl_txdnldready_fops = {
|
||||
|
||||
void btmrvl_debugfs_init(struct hci_dev *hdev)
|
||||
{
|
||||
struct btmrvl_private *priv = hdev->driver_data;
|
||||
struct btmrvl_private *priv = hci_get_drvdata(hdev);
|
||||
struct btmrvl_debugfs_data *dbg;
|
||||
|
||||
if (!hdev->debugfs)
|
||||
@ -401,36 +401,34 @@ void btmrvl_debugfs_init(struct hci_dev *hdev)
|
||||
dbg->config_dir = debugfs_create_dir("config", hdev->debugfs);
|
||||
|
||||
dbg->psmode = debugfs_create_file("psmode", 0644, dbg->config_dir,
|
||||
hdev->driver_data, &btmrvl_psmode_fops);
|
||||
priv, &btmrvl_psmode_fops);
|
||||
dbg->pscmd = debugfs_create_file("pscmd", 0644, dbg->config_dir,
|
||||
hdev->driver_data, &btmrvl_pscmd_fops);
|
||||
priv, &btmrvl_pscmd_fops);
|
||||
dbg->gpiogap = debugfs_create_file("gpiogap", 0644, dbg->config_dir,
|
||||
hdev->driver_data, &btmrvl_gpiogap_fops);
|
||||
priv, &btmrvl_gpiogap_fops);
|
||||
dbg->hsmode = debugfs_create_file("hsmode", 0644, dbg->config_dir,
|
||||
hdev->driver_data, &btmrvl_hsmode_fops);
|
||||
priv, &btmrvl_hsmode_fops);
|
||||
dbg->hscmd = debugfs_create_file("hscmd", 0644, dbg->config_dir,
|
||||
hdev->driver_data, &btmrvl_hscmd_fops);
|
||||
priv, &btmrvl_hscmd_fops);
|
||||
dbg->hscfgcmd = debugfs_create_file("hscfgcmd", 0644, dbg->config_dir,
|
||||
hdev->driver_data, &btmrvl_hscfgcmd_fops);
|
||||
priv, &btmrvl_hscfgcmd_fops);
|
||||
|
||||
dbg->status_dir = debugfs_create_dir("status", hdev->debugfs);
|
||||
dbg->curpsmode = debugfs_create_file("curpsmode", 0444,
|
||||
dbg->status_dir,
|
||||
hdev->driver_data,
|
||||
&btmrvl_curpsmode_fops);
|
||||
dbg->status_dir, priv,
|
||||
&btmrvl_curpsmode_fops);
|
||||
dbg->psstate = debugfs_create_file("psstate", 0444, dbg->status_dir,
|
||||
hdev->driver_data, &btmrvl_psstate_fops);
|
||||
priv, &btmrvl_psstate_fops);
|
||||
dbg->hsstate = debugfs_create_file("hsstate", 0444, dbg->status_dir,
|
||||
hdev->driver_data, &btmrvl_hsstate_fops);
|
||||
priv, &btmrvl_hsstate_fops);
|
||||
dbg->txdnldready = debugfs_create_file("txdnldready", 0444,
|
||||
dbg->status_dir,
|
||||
hdev->driver_data,
|
||||
&btmrvl_txdnldready_fops);
|
||||
dbg->status_dir, priv,
|
||||
&btmrvl_txdnldready_fops);
|
||||
}
|
||||
|
||||
void btmrvl_debugfs_remove(struct hci_dev *hdev)
|
||||
{
|
||||
struct btmrvl_private *priv = hdev->driver_data;
|
||||
struct btmrvl_private *priv = hci_get_drvdata(hdev);
|
||||
struct btmrvl_debugfs_data *dbg = priv->debugfs_data;
|
||||
|
||||
if (!dbg)
|
||||
|
@ -387,10 +387,6 @@ static int btmrvl_ioctl(struct hci_dev *hdev,
|
||||
return -ENOIOCTLCMD;
|
||||
}
|
||||
|
||||
static void btmrvl_destruct(struct hci_dev *hdev)
|
||||
{
|
||||
}
|
||||
|
||||
static int btmrvl_send_frame(struct sk_buff *skb)
|
||||
{
|
||||
struct hci_dev *hdev = (struct hci_dev *) skb->dev;
|
||||
@ -398,12 +394,13 @@ static int btmrvl_send_frame(struct sk_buff *skb)
|
||||
|
||||
BT_DBG("type=%d, len=%d", skb->pkt_type, skb->len);
|
||||
|
||||
if (!hdev || !hdev->driver_data) {
|
||||
if (!hdev) {
|
||||
BT_ERR("Frame for unknown HCI device");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
priv = (struct btmrvl_private *) hdev->driver_data;
|
||||
priv = hci_get_drvdata(hdev);
|
||||
|
||||
if (!test_bit(HCI_RUNNING, &hdev->flags)) {
|
||||
BT_ERR("Failed testing HCI_RUNING, flags=%lx", hdev->flags);
|
||||
print_hex_dump_bytes("data: ", DUMP_PREFIX_OFFSET,
|
||||
@ -434,7 +431,7 @@ static int btmrvl_send_frame(struct sk_buff *skb)
|
||||
|
||||
static int btmrvl_flush(struct hci_dev *hdev)
|
||||
{
|
||||
struct btmrvl_private *priv = hdev->driver_data;
|
||||
struct btmrvl_private *priv = hci_get_drvdata(hdev);
|
||||
|
||||
skb_queue_purge(&priv->adapter->tx_queue);
|
||||
|
||||
@ -443,7 +440,7 @@ static int btmrvl_flush(struct hci_dev *hdev)
|
||||
|
||||
static int btmrvl_close(struct hci_dev *hdev)
|
||||
{
|
||||
struct btmrvl_private *priv = hdev->driver_data;
|
||||
struct btmrvl_private *priv = hci_get_drvdata(hdev);
|
||||
|
||||
if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
|
||||
return 0;
|
||||
@ -546,16 +543,14 @@ int btmrvl_register_hdev(struct btmrvl_private *priv)
|
||||
}
|
||||
|
||||
priv->btmrvl_dev.hcidev = hdev;
|
||||
hdev->driver_data = priv;
|
||||
hci_set_drvdata(hdev, priv);
|
||||
|
||||
hdev->bus = HCI_SDIO;
|
||||
hdev->open = btmrvl_open;
|
||||
hdev->close = btmrvl_close;
|
||||
hdev->flush = btmrvl_flush;
|
||||
hdev->send = btmrvl_send_frame;
|
||||
hdev->destruct = btmrvl_destruct;
|
||||
hdev->ioctl = btmrvl_ioctl;
|
||||
hdev->owner = THIS_MODULE;
|
||||
|
||||
btmrvl_send_module_cfg_cmd(priv, MODULE_BRINGUP_REQ);
|
||||
|
||||
|
@ -189,7 +189,7 @@ static void btsdio_interrupt(struct sdio_func *func)
|
||||
|
||||
static int btsdio_open(struct hci_dev *hdev)
|
||||
{
|
||||
struct btsdio_data *data = hdev->driver_data;
|
||||
struct btsdio_data *data = hci_get_drvdata(hdev);
|
||||
int err;
|
||||
|
||||
BT_DBG("%s", hdev->name);
|
||||
@ -225,7 +225,7 @@ release:
|
||||
|
||||
static int btsdio_close(struct hci_dev *hdev)
|
||||
{
|
||||
struct btsdio_data *data = hdev->driver_data;
|
||||
struct btsdio_data *data = hci_get_drvdata(hdev);
|
||||
|
||||
BT_DBG("%s", hdev->name);
|
||||
|
||||
@ -246,7 +246,7 @@ static int btsdio_close(struct hci_dev *hdev)
|
||||
|
||||
static int btsdio_flush(struct hci_dev *hdev)
|
||||
{
|
||||
struct btsdio_data *data = hdev->driver_data;
|
||||
struct btsdio_data *data = hci_get_drvdata(hdev);
|
||||
|
||||
BT_DBG("%s", hdev->name);
|
||||
|
||||
@ -258,7 +258,7 @@ static int btsdio_flush(struct hci_dev *hdev)
|
||||
static int btsdio_send_frame(struct sk_buff *skb)
|
||||
{
|
||||
struct hci_dev *hdev = (struct hci_dev *) skb->dev;
|
||||
struct btsdio_data *data = hdev->driver_data;
|
||||
struct btsdio_data *data = hci_get_drvdata(hdev);
|
||||
|
||||
BT_DBG("%s", hdev->name);
|
||||
|
||||
@ -289,15 +289,6 @@ static int btsdio_send_frame(struct sk_buff *skb)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void btsdio_destruct(struct hci_dev *hdev)
|
||||
{
|
||||
struct btsdio_data *data = hdev->driver_data;
|
||||
|
||||
BT_DBG("%s", hdev->name);
|
||||
|
||||
kfree(data);
|
||||
}
|
||||
|
||||
static int btsdio_probe(struct sdio_func *func,
|
||||
const struct sdio_device_id *id)
|
||||
{
|
||||
@ -330,7 +321,7 @@ static int btsdio_probe(struct sdio_func *func,
|
||||
}
|
||||
|
||||
hdev->bus = HCI_SDIO;
|
||||
hdev->driver_data = data;
|
||||
hci_set_drvdata(hdev, data);
|
||||
|
||||
if (id->class == SDIO_CLASS_BT_AMP)
|
||||
hdev->dev_type = HCI_AMP;
|
||||
@ -345,9 +336,6 @@ static int btsdio_probe(struct sdio_func *func,
|
||||
hdev->close = btsdio_close;
|
||||
hdev->flush = btsdio_flush;
|
||||
hdev->send = btsdio_send_frame;
|
||||
hdev->destruct = btsdio_destruct;
|
||||
|
||||
hdev->owner = THIS_MODULE;
|
||||
|
||||
err = hci_register_dev(hdev);
|
||||
if (err < 0) {
|
||||
@ -378,6 +366,7 @@ static void btsdio_remove(struct sdio_func *func)
|
||||
hci_unregister_dev(hdev);
|
||||
|
||||
hci_free_dev(hdev);
|
||||
kfree(data);
|
||||
}
|
||||
|
||||
static struct sdio_driver btsdio_driver = {
|
||||
|
@ -397,7 +397,7 @@ static void btuart_change_speed(btuart_info_t *info, unsigned int speed)
|
||||
|
||||
static int btuart_hci_flush(struct hci_dev *hdev)
|
||||
{
|
||||
btuart_info_t *info = (btuart_info_t *)(hdev->driver_data);
|
||||
btuart_info_t *info = hci_get_drvdata(hdev);
|
||||
|
||||
/* Drop TX queue */
|
||||
skb_queue_purge(&(info->txq));
|
||||
@ -435,7 +435,7 @@ static int btuart_hci_send_frame(struct sk_buff *skb)
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
info = (btuart_info_t *)(hdev->driver_data);
|
||||
info = hci_get_drvdata(hdev);
|
||||
|
||||
switch (bt_cb(skb)->pkt_type) {
|
||||
case HCI_COMMAND_PKT:
|
||||
@ -459,11 +459,6 @@ static int btuart_hci_send_frame(struct sk_buff *skb)
|
||||
}
|
||||
|
||||
|
||||
static void btuart_hci_destruct(struct hci_dev *hdev)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
static int btuart_hci_ioctl(struct hci_dev *hdev, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
return -ENOIOCTLCMD;
|
||||
@ -498,18 +493,15 @@ static int btuart_open(btuart_info_t *info)
|
||||
info->hdev = hdev;
|
||||
|
||||
hdev->bus = HCI_PCCARD;
|
||||
hdev->driver_data = info;
|
||||
hci_set_drvdata(hdev, info);
|
||||
SET_HCIDEV_DEV(hdev, &info->p_dev->dev);
|
||||
|
||||
hdev->open = btuart_hci_open;
|
||||
hdev->close = btuart_hci_close;
|
||||
hdev->flush = btuart_hci_flush;
|
||||
hdev->send = btuart_hci_send_frame;
|
||||
hdev->destruct = btuart_hci_destruct;
|
||||
hdev->ioctl = btuart_hci_ioctl;
|
||||
|
||||
hdev->owner = THIS_MODULE;
|
||||
|
||||
spin_lock_irqsave(&(info->lock), flags);
|
||||
|
||||
/* Reset UART */
|
||||
|
@ -102,6 +102,7 @@ static struct usb_device_id btusb_table[] = {
|
||||
|
||||
/* Broadcom BCM20702A0 */
|
||||
{ USB_DEVICE(0x0a5c, 0x21e3) },
|
||||
{ USB_DEVICE(0x0a5c, 0x21e6) },
|
||||
{ USB_DEVICE(0x0a5c, 0x21f3) },
|
||||
{ USB_DEVICE(0x413c, 0x8197) },
|
||||
|
||||
@ -121,12 +122,14 @@ static struct usb_device_id blacklist_table[] = {
|
||||
{ USB_DEVICE(0x0cf3, 0x3002), .driver_info = BTUSB_IGNORE },
|
||||
{ USB_DEVICE(0x13d3, 0x3304), .driver_info = BTUSB_IGNORE },
|
||||
{ USB_DEVICE(0x0930, 0x0215), .driver_info = BTUSB_IGNORE },
|
||||
{ USB_DEVICE(0x0489, 0xe03d), .driver_info = BTUSB_IGNORE },
|
||||
|
||||
/* Atheros AR9285 Malbec with sflash firmware */
|
||||
{ USB_DEVICE(0x03f0, 0x311d), .driver_info = BTUSB_IGNORE },
|
||||
|
||||
/* Atheros 3012 with sflash firmware */
|
||||
{ USB_DEVICE(0x0cf3, 0x3004), .driver_info = BTUSB_ATH3012 },
|
||||
{ USB_DEVICE(0x13d3, 0x3375), .driver_info = BTUSB_ATH3012 },
|
||||
|
||||
/* Atheros AR5BBU12 with sflash firmware */
|
||||
{ USB_DEVICE(0x0489, 0xe02c), .driver_info = BTUSB_IGNORE },
|
||||
@ -243,7 +246,7 @@ static int inc_tx(struct btusb_data *data)
|
||||
static void btusb_intr_complete(struct urb *urb)
|
||||
{
|
||||
struct hci_dev *hdev = urb->context;
|
||||
struct btusb_data *data = hdev->driver_data;
|
||||
struct btusb_data *data = hci_get_drvdata(hdev);
|
||||
int err;
|
||||
|
||||
BT_DBG("%s urb %p status %d count %d", hdev->name,
|
||||
@ -282,7 +285,7 @@ static void btusb_intr_complete(struct urb *urb)
|
||||
|
||||
static int btusb_submit_intr_urb(struct hci_dev *hdev, gfp_t mem_flags)
|
||||
{
|
||||
struct btusb_data *data = hdev->driver_data;
|
||||
struct btusb_data *data = hci_get_drvdata(hdev);
|
||||
struct urb *urb;
|
||||
unsigned char *buf;
|
||||
unsigned int pipe;
|
||||
@ -331,7 +334,7 @@ static int btusb_submit_intr_urb(struct hci_dev *hdev, gfp_t mem_flags)
|
||||
static void btusb_bulk_complete(struct urb *urb)
|
||||
{
|
||||
struct hci_dev *hdev = urb->context;
|
||||
struct btusb_data *data = hdev->driver_data;
|
||||
struct btusb_data *data = hci_get_drvdata(hdev);
|
||||
int err;
|
||||
|
||||
BT_DBG("%s urb %p status %d count %d", hdev->name,
|
||||
@ -370,7 +373,7 @@ static void btusb_bulk_complete(struct urb *urb)
|
||||
|
||||
static int btusb_submit_bulk_urb(struct hci_dev *hdev, gfp_t mem_flags)
|
||||
{
|
||||
struct btusb_data *data = hdev->driver_data;
|
||||
struct btusb_data *data = hci_get_drvdata(hdev);
|
||||
struct urb *urb;
|
||||
unsigned char *buf;
|
||||
unsigned int pipe;
|
||||
@ -417,7 +420,7 @@ static int btusb_submit_bulk_urb(struct hci_dev *hdev, gfp_t mem_flags)
|
||||
static void btusb_isoc_complete(struct urb *urb)
|
||||
{
|
||||
struct hci_dev *hdev = urb->context;
|
||||
struct btusb_data *data = hdev->driver_data;
|
||||
struct btusb_data *data = hci_get_drvdata(hdev);
|
||||
int i, err;
|
||||
|
||||
BT_DBG("%s urb %p status %d count %d", hdev->name,
|
||||
@ -484,7 +487,7 @@ static inline void __fill_isoc_descriptor(struct urb *urb, int len, int mtu)
|
||||
|
||||
static int btusb_submit_isoc_urb(struct hci_dev *hdev, gfp_t mem_flags)
|
||||
{
|
||||
struct btusb_data *data = hdev->driver_data;
|
||||
struct btusb_data *data = hci_get_drvdata(hdev);
|
||||
struct urb *urb;
|
||||
unsigned char *buf;
|
||||
unsigned int pipe;
|
||||
@ -537,7 +540,7 @@ static void btusb_tx_complete(struct urb *urb)
|
||||
{
|
||||
struct sk_buff *skb = urb->context;
|
||||
struct hci_dev *hdev = (struct hci_dev *) skb->dev;
|
||||
struct btusb_data *data = hdev->driver_data;
|
||||
struct btusb_data *data = hci_get_drvdata(hdev);
|
||||
|
||||
BT_DBG("%s urb %p status %d count %d", hdev->name,
|
||||
urb, urb->status, urb->actual_length);
|
||||
@ -584,7 +587,7 @@ done:
|
||||
|
||||
static int btusb_open(struct hci_dev *hdev)
|
||||
{
|
||||
struct btusb_data *data = hdev->driver_data;
|
||||
struct btusb_data *data = hci_get_drvdata(hdev);
|
||||
int err;
|
||||
|
||||
BT_DBG("%s", hdev->name);
|
||||
@ -634,7 +637,7 @@ static void btusb_stop_traffic(struct btusb_data *data)
|
||||
|
||||
static int btusb_close(struct hci_dev *hdev)
|
||||
{
|
||||
struct btusb_data *data = hdev->driver_data;
|
||||
struct btusb_data *data = hci_get_drvdata(hdev);
|
||||
int err;
|
||||
|
||||
BT_DBG("%s", hdev->name);
|
||||
@ -664,7 +667,7 @@ failed:
|
||||
|
||||
static int btusb_flush(struct hci_dev *hdev)
|
||||
{
|
||||
struct btusb_data *data = hdev->driver_data;
|
||||
struct btusb_data *data = hci_get_drvdata(hdev);
|
||||
|
||||
BT_DBG("%s", hdev->name);
|
||||
|
||||
@ -676,7 +679,7 @@ static int btusb_flush(struct hci_dev *hdev)
|
||||
static int btusb_send_frame(struct sk_buff *skb)
|
||||
{
|
||||
struct hci_dev *hdev = (struct hci_dev *) skb->dev;
|
||||
struct btusb_data *data = hdev->driver_data;
|
||||
struct btusb_data *data = hci_get_drvdata(hdev);
|
||||
struct usb_ctrlrequest *dr;
|
||||
struct urb *urb;
|
||||
unsigned int pipe;
|
||||
@ -784,18 +787,9 @@ done:
|
||||
return err;
|
||||
}
|
||||
|
||||
static void btusb_destruct(struct hci_dev *hdev)
|
||||
{
|
||||
struct btusb_data *data = hdev->driver_data;
|
||||
|
||||
BT_DBG("%s", hdev->name);
|
||||
|
||||
kfree(data);
|
||||
}
|
||||
|
||||
static void btusb_notify(struct hci_dev *hdev, unsigned int evt)
|
||||
{
|
||||
struct btusb_data *data = hdev->driver_data;
|
||||
struct btusb_data *data = hci_get_drvdata(hdev);
|
||||
|
||||
BT_DBG("%s evt %d", hdev->name, evt);
|
||||
|
||||
@ -807,7 +801,7 @@ static void btusb_notify(struct hci_dev *hdev, unsigned int evt)
|
||||
|
||||
static inline int __set_isoc_interface(struct hci_dev *hdev, int altsetting)
|
||||
{
|
||||
struct btusb_data *data = hdev->driver_data;
|
||||
struct btusb_data *data = hci_get_drvdata(hdev);
|
||||
struct usb_interface *intf = data->isoc;
|
||||
struct usb_endpoint_descriptor *ep_desc;
|
||||
int i, err;
|
||||
@ -995,7 +989,7 @@ static int btusb_probe(struct usb_interface *intf,
|
||||
}
|
||||
|
||||
hdev->bus = HCI_USB;
|
||||
hdev->driver_data = data;
|
||||
hci_set_drvdata(hdev, data);
|
||||
|
||||
data->hdev = hdev;
|
||||
|
||||
@ -1005,11 +999,8 @@ static int btusb_probe(struct usb_interface *intf,
|
||||
hdev->close = btusb_close;
|
||||
hdev->flush = btusb_flush;
|
||||
hdev->send = btusb_send_frame;
|
||||
hdev->destruct = btusb_destruct;
|
||||
hdev->notify = btusb_notify;
|
||||
|
||||
hdev->owner = THIS_MODULE;
|
||||
|
||||
/* Interface numbers are hardcoded in the specification */
|
||||
data->isoc = usb_ifnum_to_if(data->udev, 1);
|
||||
|
||||
@ -1091,9 +1082,6 @@ static void btusb_disconnect(struct usb_interface *intf)
|
||||
return;
|
||||
|
||||
hdev = data->hdev;
|
||||
|
||||
__hci_dev_hold(hdev);
|
||||
|
||||
usb_set_intfdata(data->intf, NULL);
|
||||
|
||||
if (data->isoc)
|
||||
@ -1106,9 +1094,8 @@ static void btusb_disconnect(struct usb_interface *intf)
|
||||
else if (data->isoc)
|
||||
usb_driver_release_interface(&btusb_driver, data->isoc);
|
||||
|
||||
__hci_dev_put(hdev);
|
||||
|
||||
hci_free_dev(hdev);
|
||||
kfree(data);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
|
@ -161,7 +161,7 @@ static int ti_st_open(struct hci_dev *hdev)
|
||||
return -EBUSY;
|
||||
|
||||
/* provide contexts for callbacks from ST */
|
||||
hst = hdev->driver_data;
|
||||
hst = hci_get_drvdata(hdev);
|
||||
|
||||
for (i = 0; i < MAX_BT_CHNL_IDS; i++) {
|
||||
ti_st_proto[i].priv_data = hst;
|
||||
@ -236,7 +236,7 @@ done:
|
||||
static int ti_st_close(struct hci_dev *hdev)
|
||||
{
|
||||
int err, i;
|
||||
struct ti_st *hst = hdev->driver_data;
|
||||
struct ti_st *hst = hci_get_drvdata(hdev);
|
||||
|
||||
if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
|
||||
return 0;
|
||||
@ -264,7 +264,7 @@ static int ti_st_send_frame(struct sk_buff *skb)
|
||||
if (!test_bit(HCI_RUNNING, &hdev->flags))
|
||||
return -EBUSY;
|
||||
|
||||
hst = hdev->driver_data;
|
||||
hst = hci_get_drvdata(hdev);
|
||||
|
||||
/* Prepend skb with frame type */
|
||||
memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1);
|
||||
@ -291,14 +291,6 @@ static int ti_st_send_frame(struct sk_buff *skb)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ti_st_destruct(struct hci_dev *hdev)
|
||||
{
|
||||
BT_DBG("%s", hdev->name);
|
||||
/* do nothing here, since platform remove
|
||||
* would free the hdev->driver_data
|
||||
*/
|
||||
}
|
||||
|
||||
static int bt_ti_probe(struct platform_device *pdev)
|
||||
{
|
||||
static struct ti_st *hst;
|
||||
@ -320,13 +312,11 @@ static int bt_ti_probe(struct platform_device *pdev)
|
||||
|
||||
hst->hdev = hdev;
|
||||
hdev->bus = HCI_UART;
|
||||
hdev->driver_data = hst;
|
||||
hci_set_drvdata(hdev, hst);
|
||||
hdev->open = ti_st_open;
|
||||
hdev->close = ti_st_close;
|
||||
hdev->flush = NULL;
|
||||
hdev->send = ti_st_send_frame;
|
||||
hdev->destruct = ti_st_destruct;
|
||||
hdev->owner = THIS_MODULE;
|
||||
|
||||
err = hci_register_dev(hdev);
|
||||
if (err < 0) {
|
||||
|
@ -83,9 +83,6 @@ typedef struct dtl1_info_t {
|
||||
|
||||
|
||||
static int dtl1_config(struct pcmcia_device *link);
|
||||
static void dtl1_release(struct pcmcia_device *link);
|
||||
|
||||
static void dtl1_detach(struct pcmcia_device *p_dev);
|
||||
|
||||
|
||||
/* Transmit states */
|
||||
@ -367,7 +364,7 @@ static int dtl1_hci_open(struct hci_dev *hdev)
|
||||
|
||||
static int dtl1_hci_flush(struct hci_dev *hdev)
|
||||
{
|
||||
dtl1_info_t *info = (dtl1_info_t *)(hdev->driver_data);
|
||||
dtl1_info_t *info = hci_get_drvdata(hdev);
|
||||
|
||||
/* Drop TX queue */
|
||||
skb_queue_purge(&(info->txq));
|
||||
@ -399,7 +396,7 @@ static int dtl1_hci_send_frame(struct sk_buff *skb)
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
info = (dtl1_info_t *)(hdev->driver_data);
|
||||
info = hci_get_drvdata(hdev);
|
||||
|
||||
switch (bt_cb(skb)->pkt_type) {
|
||||
case HCI_COMMAND_PKT:
|
||||
@ -442,11 +439,6 @@ static int dtl1_hci_send_frame(struct sk_buff *skb)
|
||||
}
|
||||
|
||||
|
||||
static void dtl1_hci_destruct(struct hci_dev *hdev)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
static int dtl1_hci_ioctl(struct hci_dev *hdev, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
return -ENOIOCTLCMD;
|
||||
@ -483,18 +475,15 @@ static int dtl1_open(dtl1_info_t *info)
|
||||
info->hdev = hdev;
|
||||
|
||||
hdev->bus = HCI_PCCARD;
|
||||
hdev->driver_data = info;
|
||||
hci_set_drvdata(hdev, info);
|
||||
SET_HCIDEV_DEV(hdev, &info->p_dev->dev);
|
||||
|
||||
hdev->open = dtl1_hci_open;
|
||||
hdev->close = dtl1_hci_close;
|
||||
hdev->flush = dtl1_hci_flush;
|
||||
hdev->send = dtl1_hci_send_frame;
|
||||
hdev->destruct = dtl1_hci_destruct;
|
||||
hdev->ioctl = dtl1_hci_ioctl;
|
||||
|
||||
hdev->owner = THIS_MODULE;
|
||||
|
||||
spin_lock_irqsave(&(info->lock), flags);
|
||||
|
||||
/* Reset UART */
|
||||
@ -579,8 +568,8 @@ static void dtl1_detach(struct pcmcia_device *link)
|
||||
{
|
||||
dtl1_info_t *info = link->priv;
|
||||
|
||||
dtl1_release(link);
|
||||
|
||||
dtl1_close(info);
|
||||
pcmcia_disable_device(link);
|
||||
kfree(info);
|
||||
}
|
||||
|
||||
@ -619,21 +608,10 @@ static int dtl1_config(struct pcmcia_device *link)
|
||||
return 0;
|
||||
|
||||
failed:
|
||||
dtl1_release(link);
|
||||
dtl1_detach(link);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
|
||||
static void dtl1_release(struct pcmcia_device *link)
|
||||
{
|
||||
dtl1_info_t *info = link->priv;
|
||||
|
||||
dtl1_close(info);
|
||||
|
||||
pcmcia_disable_device(link);
|
||||
}
|
||||
|
||||
|
||||
static const struct pcmcia_device_id dtl1_ids[] = {
|
||||
PCMCIA_DEVICE_PROD_ID12("Nokia Mobile Phones", "DTL-1", 0xe1bfdd64, 0xe168480d),
|
||||
PCMCIA_DEVICE_PROD_ID12("Nokia Mobile Phones", "DTL-4", 0xe1bfdd64, 0x9102bc82),
|
||||
|
@ -112,7 +112,7 @@ static int ath_open(struct hci_uart *hu)
|
||||
|
||||
BT_DBG("hu %p", hu);
|
||||
|
||||
ath = kzalloc(sizeof(*ath), GFP_ATOMIC);
|
||||
ath = kzalloc(sizeof(*ath), GFP_KERNEL);
|
||||
if (!ath)
|
||||
return -ENOMEM;
|
||||
|
||||
|
@ -692,7 +692,7 @@ static int bcsp_open(struct hci_uart *hu)
|
||||
|
||||
BT_DBG("hu %p", hu);
|
||||
|
||||
bcsp = kzalloc(sizeof(*bcsp), GFP_ATOMIC);
|
||||
bcsp = kzalloc(sizeof(*bcsp), GFP_KERNEL);
|
||||
if (!bcsp)
|
||||
return -ENOMEM;
|
||||
|
||||
|
@ -69,7 +69,7 @@ static int h4_open(struct hci_uart *hu)
|
||||
|
||||
BT_DBG("hu %p", hu);
|
||||
|
||||
h4 = kzalloc(sizeof(*h4), GFP_ATOMIC);
|
||||
h4 = kzalloc(sizeof(*h4), GFP_KERNEL);
|
||||
if (!h4)
|
||||
return -ENOMEM;
|
||||
|
||||
|
@ -48,8 +48,6 @@
|
||||
|
||||
#define VERSION "2.2"
|
||||
|
||||
static bool reset = 0;
|
||||
|
||||
static struct hci_uart_proto *hup[HCI_UART_MAX_PROTO];
|
||||
|
||||
int hci_uart_register_proto(struct hci_uart_proto *p)
|
||||
@ -174,7 +172,7 @@ static int hci_uart_open(struct hci_dev *hdev)
|
||||
/* Reset device */
|
||||
static int hci_uart_flush(struct hci_dev *hdev)
|
||||
{
|
||||
struct hci_uart *hu = (struct hci_uart *) hdev->driver_data;
|
||||
struct hci_uart *hu = hci_get_drvdata(hdev);
|
||||
struct tty_struct *tty = hu->tty;
|
||||
|
||||
BT_DBG("hdev %p tty %p", hdev, tty);
|
||||
@ -220,7 +218,7 @@ static int hci_uart_send_frame(struct sk_buff *skb)
|
||||
if (!test_bit(HCI_RUNNING, &hdev->flags))
|
||||
return -EBUSY;
|
||||
|
||||
hu = (struct hci_uart *) hdev->driver_data;
|
||||
hu = hci_get_drvdata(hdev);
|
||||
|
||||
BT_DBG("%s: type %d len %d", hdev->name, bt_cb(skb)->pkt_type, skb->len);
|
||||
|
||||
@ -231,15 +229,6 @@ static int hci_uart_send_frame(struct sk_buff *skb)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void hci_uart_destruct(struct hci_dev *hdev)
|
||||
{
|
||||
if (!hdev)
|
||||
return;
|
||||
|
||||
BT_DBG("%s", hdev->name);
|
||||
kfree(hdev->driver_data);
|
||||
}
|
||||
|
||||
/* ------ LDISC part ------ */
|
||||
/* hci_uart_tty_open
|
||||
*
|
||||
@ -316,6 +305,8 @@ static void hci_uart_tty_close(struct tty_struct *tty)
|
||||
hci_free_dev(hdev);
|
||||
}
|
||||
}
|
||||
|
||||
kfree(hu);
|
||||
}
|
||||
}
|
||||
|
||||
@ -391,23 +382,25 @@ static int hci_uart_register_dev(struct hci_uart *hu)
|
||||
hu->hdev = hdev;
|
||||
|
||||
hdev->bus = HCI_UART;
|
||||
hdev->driver_data = hu;
|
||||
hci_set_drvdata(hdev, hu);
|
||||
|
||||
hdev->open = hci_uart_open;
|
||||
hdev->close = hci_uart_close;
|
||||
hdev->flush = hci_uart_flush;
|
||||
hdev->send = hci_uart_send_frame;
|
||||
hdev->destruct = hci_uart_destruct;
|
||||
hdev->parent = hu->tty->dev;
|
||||
|
||||
hdev->owner = THIS_MODULE;
|
||||
|
||||
if (!reset)
|
||||
set_bit(HCI_QUIRK_NO_RESET, &hdev->quirks);
|
||||
|
||||
if (test_bit(HCI_UART_RAW_DEVICE, &hu->hdev_flags))
|
||||
set_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks);
|
||||
|
||||
if (!test_bit(HCI_UART_RESET_ON_INIT, &hu->hdev_flags))
|
||||
set_bit(HCI_QUIRK_NO_RESET, &hdev->quirks);
|
||||
|
||||
if (test_bit(HCI_UART_CREATE_AMP, &hu->hdev_flags))
|
||||
hdev->dev_type = HCI_AMP;
|
||||
else
|
||||
hdev->dev_type = HCI_BREDR;
|
||||
|
||||
if (hci_register_dev(hdev) < 0) {
|
||||
BT_ERR("Can't register HCI device");
|
||||
hci_free_dev(hdev);
|
||||
@ -594,9 +587,6 @@ static void __exit hci_uart_exit(void)
|
||||
module_init(hci_uart_init);
|
||||
module_exit(hci_uart_exit);
|
||||
|
||||
module_param(reset, bool, 0644);
|
||||
MODULE_PARM_DESC(reset, "Send HCI reset command on initialization");
|
||||
|
||||
MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
|
||||
MODULE_DESCRIPTION("Bluetooth HCI UART driver ver " VERSION);
|
||||
MODULE_VERSION(VERSION);
|
||||
|
@ -125,7 +125,7 @@ static int ll_open(struct hci_uart *hu)
|
||||
|
||||
BT_DBG("hu %p", hu);
|
||||
|
||||
ll = kzalloc(sizeof(*ll), GFP_ATOMIC);
|
||||
ll = kzalloc(sizeof(*ll), GFP_KERNEL);
|
||||
if (!ll)
|
||||
return -ENOMEM;
|
||||
|
||||
|
@ -45,6 +45,8 @@
|
||||
#define HCI_UART_ATH3K 5
|
||||
|
||||
#define HCI_UART_RAW_DEVICE 0
|
||||
#define HCI_UART_RESET_ON_INIT 1
|
||||
#define HCI_UART_CREATE_AMP 2
|
||||
|
||||
struct hci_uart;
|
||||
|
||||
|
@ -61,7 +61,7 @@ static int vhci_open_dev(struct hci_dev *hdev)
|
||||
|
||||
static int vhci_close_dev(struct hci_dev *hdev)
|
||||
{
|
||||
struct vhci_data *data = hdev->driver_data;
|
||||
struct vhci_data *data = hci_get_drvdata(hdev);
|
||||
|
||||
if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
|
||||
return 0;
|
||||
@ -73,7 +73,7 @@ static int vhci_close_dev(struct hci_dev *hdev)
|
||||
|
||||
static int vhci_flush(struct hci_dev *hdev)
|
||||
{
|
||||
struct vhci_data *data = hdev->driver_data;
|
||||
struct vhci_data *data = hci_get_drvdata(hdev);
|
||||
|
||||
skb_queue_purge(&data->readq);
|
||||
|
||||
@ -93,7 +93,7 @@ static int vhci_send_frame(struct sk_buff *skb)
|
||||
if (!test_bit(HCI_RUNNING, &hdev->flags))
|
||||
return -EBUSY;
|
||||
|
||||
data = hdev->driver_data;
|
||||
data = hci_get_drvdata(hdev);
|
||||
|
||||
memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1);
|
||||
skb_queue_tail(&data->readq, skb);
|
||||
@ -103,11 +103,6 @@ static int vhci_send_frame(struct sk_buff *skb)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void vhci_destruct(struct hci_dev *hdev)
|
||||
{
|
||||
kfree(hdev->driver_data);
|
||||
}
|
||||
|
||||
static inline ssize_t vhci_get_user(struct vhci_data *data,
|
||||
const char __user *buf, size_t count)
|
||||
{
|
||||
@ -239,7 +234,7 @@ static int vhci_open(struct inode *inode, struct file *file)
|
||||
data->hdev = hdev;
|
||||
|
||||
hdev->bus = HCI_VIRTUAL;
|
||||
hdev->driver_data = data;
|
||||
hci_set_drvdata(hdev, data);
|
||||
|
||||
if (amp)
|
||||
hdev->dev_type = HCI_AMP;
|
||||
@ -248,9 +243,6 @@ static int vhci_open(struct inode *inode, struct file *file)
|
||||
hdev->close = vhci_close_dev;
|
||||
hdev->flush = vhci_flush;
|
||||
hdev->send = vhci_send_frame;
|
||||
hdev->destruct = vhci_destruct;
|
||||
|
||||
hdev->owner = THIS_MODULE;
|
||||
|
||||
if (hci_register_dev(hdev) < 0) {
|
||||
BT_ERR("Can't register HCI device");
|
||||
@ -273,6 +265,7 @@ static int vhci_release(struct inode *inode, struct file *file)
|
||||
hci_free_dev(hdev);
|
||||
|
||||
file->private_data = NULL;
|
||||
kfree(data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -109,12 +109,14 @@ struct bt_power {
|
||||
*/
|
||||
#define BT_CHANNEL_POLICY_AMP_PREFERRED 2
|
||||
|
||||
__printf(2, 3)
|
||||
int bt_printk(const char *level, const char *fmt, ...);
|
||||
__printf(1, 2)
|
||||
int bt_info(const char *fmt, ...);
|
||||
__printf(1, 2)
|
||||
int bt_err(const char *fmt, ...);
|
||||
|
||||
#define BT_INFO(fmt, arg...) bt_printk(KERN_INFO, pr_fmt(fmt), ##arg)
|
||||
#define BT_ERR(fmt, arg...) bt_printk(KERN_ERR, pr_fmt(fmt), ##arg)
|
||||
#define BT_DBG(fmt, arg...) pr_debug(fmt "\n", ##arg)
|
||||
#define BT_INFO(fmt, ...) bt_info(fmt "\n", ##__VA_ARGS__)
|
||||
#define BT_ERR(fmt, ...) bt_err(fmt "\n", ##__VA_ARGS__)
|
||||
#define BT_DBG(fmt, ...) pr_debug(fmt "\n", ##__VA_ARGS__)
|
||||
|
||||
/* Connection and socket states */
|
||||
enum {
|
||||
@ -129,6 +131,33 @@ enum {
|
||||
BT_CLOSED
|
||||
};
|
||||
|
||||
/* If unused will be removed by compiler */
|
||||
static inline const char *state_to_string(int state)
|
||||
{
|
||||
switch (state) {
|
||||
case BT_CONNECTED:
|
||||
return "BT_CONNECTED";
|
||||
case BT_OPEN:
|
||||
return "BT_OPEN";
|
||||
case BT_BOUND:
|
||||
return "BT_BOUND";
|
||||
case BT_LISTEN:
|
||||
return "BT_LISTEN";
|
||||
case BT_CONNECT:
|
||||
return "BT_CONNECT";
|
||||
case BT_CONNECT2:
|
||||
return "BT_CONNECT2";
|
||||
case BT_CONFIG:
|
||||
return "BT_CONFIG";
|
||||
case BT_DISCONN:
|
||||
return "BT_DISCONN";
|
||||
case BT_CLOSED:
|
||||
return "BT_CLOSED";
|
||||
}
|
||||
|
||||
return "invalid state";
|
||||
}
|
||||
|
||||
/* BD Address */
|
||||
typedef struct {
|
||||
__u8 b[6];
|
||||
@ -193,7 +222,6 @@ struct bt_skb_cb {
|
||||
__u16 tx_seq;
|
||||
__u8 retries;
|
||||
__u8 sar;
|
||||
unsigned short channel;
|
||||
__u8 force_active;
|
||||
};
|
||||
#define bt_cb(skb) ((struct bt_skb_cb *)((skb)->cb))
|
||||
|
@ -77,14 +77,6 @@ enum {
|
||||
|
||||
HCI_RAW,
|
||||
|
||||
HCI_SETUP,
|
||||
HCI_AUTO_OFF,
|
||||
HCI_MGMT,
|
||||
HCI_PAIRABLE,
|
||||
HCI_SERVICE_CACHE,
|
||||
HCI_LINK_KEYS,
|
||||
HCI_DEBUG_KEYS,
|
||||
|
||||
HCI_RESET,
|
||||
};
|
||||
|
||||
@ -93,7 +85,22 @@ enum {
|
||||
* states from the controller.
|
||||
*/
|
||||
enum {
|
||||
HCI_SETUP,
|
||||
HCI_AUTO_OFF,
|
||||
HCI_MGMT,
|
||||
HCI_PAIRABLE,
|
||||
HCI_SERVICE_CACHE,
|
||||
HCI_LINK_KEYS,
|
||||
HCI_DEBUG_KEYS,
|
||||
|
||||
HCI_LE_SCAN,
|
||||
HCI_SSP_ENABLED,
|
||||
HCI_HS_ENABLED,
|
||||
HCI_LE_ENABLED,
|
||||
HCI_CONNECTABLE,
|
||||
HCI_DISCOVERABLE,
|
||||
HCI_LINK_SECURITY,
|
||||
HCI_PENDING_CLASS,
|
||||
};
|
||||
|
||||
/* HCI ioctl defines */
|
||||
@ -130,6 +137,7 @@ enum {
|
||||
#define HCI_IDLE_TIMEOUT (6000) /* 6 seconds */
|
||||
#define HCI_INIT_TIMEOUT (10000) /* 10 seconds */
|
||||
#define HCI_CMD_TIMEOUT (1000) /* 1 seconds */
|
||||
#define HCI_ACL_TX_TIMEOUT (45000) /* 45 seconds */
|
||||
|
||||
/* HCI data types */
|
||||
#define HCI_COMMAND_PKT 0x01
|
||||
@ -229,7 +237,9 @@ enum {
|
||||
#define LMP_EXTFEATURES 0x80
|
||||
|
||||
/* Extended LMP features */
|
||||
#define LMP_HOST_LE 0x02
|
||||
#define LMP_HOST_SSP 0x01
|
||||
#define LMP_HOST_LE 0x02
|
||||
#define LMP_HOST_LE_BREDR 0x04
|
||||
|
||||
/* Connection modes */
|
||||
#define HCI_CM_ACTIVE 0x0000
|
||||
@ -268,10 +278,11 @@ enum {
|
||||
#define HCI_LK_UNAUTH_COMBINATION 0x04
|
||||
#define HCI_LK_AUTH_COMBINATION 0x05
|
||||
#define HCI_LK_CHANGED_COMBINATION 0x06
|
||||
/* The spec doesn't define types for SMP keys */
|
||||
#define HCI_LK_SMP_LTK 0x81
|
||||
#define HCI_LK_SMP_IRK 0x82
|
||||
#define HCI_LK_SMP_CSRK 0x83
|
||||
/* The spec doesn't define types for SMP keys, the _MASTER suffix is implied */
|
||||
#define HCI_SMP_STK 0x80
|
||||
#define HCI_SMP_STK_SLAVE 0x81
|
||||
#define HCI_SMP_LTK 0x82
|
||||
#define HCI_SMP_LTK_SLAVE 0x83
|
||||
|
||||
/* ---- HCI Error Codes ---- */
|
||||
#define HCI_ERROR_AUTH_FAILURE 0x05
|
||||
@ -284,6 +295,22 @@ enum {
|
||||
#define HCI_FLOW_CTL_MODE_PACKET_BASED 0x00
|
||||
#define HCI_FLOW_CTL_MODE_BLOCK_BASED 0x01
|
||||
|
||||
/* Extended Inquiry Response field types */
|
||||
#define EIR_FLAGS 0x01 /* flags */
|
||||
#define EIR_UUID16_SOME 0x02 /* 16-bit UUID, more available */
|
||||
#define EIR_UUID16_ALL 0x03 /* 16-bit UUID, all listed */
|
||||
#define EIR_UUID32_SOME 0x04 /* 32-bit UUID, more available */
|
||||
#define EIR_UUID32_ALL 0x05 /* 32-bit UUID, all listed */
|
||||
#define EIR_UUID128_SOME 0x06 /* 128-bit UUID, more available */
|
||||
#define EIR_UUID128_ALL 0x07 /* 128-bit UUID, all listed */
|
||||
#define EIR_NAME_SHORT 0x08 /* shortened local name */
|
||||
#define EIR_NAME_COMPLETE 0x09 /* complete local name */
|
||||
#define EIR_TX_POWER 0x0A /* transmit power level */
|
||||
#define EIR_CLASS_OF_DEV 0x0D /* Class of Device */
|
||||
#define EIR_SSP_HASH_C 0x0E /* Simple Pairing Hash C */
|
||||
#define EIR_SSP_RAND_R 0x0F /* Simple Pairing Randomizer R */
|
||||
#define EIR_DEVICE_ID 0x10 /* device ID */
|
||||
|
||||
/* ----- HCI Commands ---- */
|
||||
#define HCI_OP_NOP 0x0000
|
||||
|
||||
@ -666,8 +693,8 @@ struct hci_cp_host_buffer_size {
|
||||
|
||||
#define HCI_OP_WRITE_EIR 0x0c52
|
||||
struct hci_cp_write_eir {
|
||||
uint8_t fec;
|
||||
uint8_t data[HCI_MAX_EIR_LENGTH];
|
||||
__u8 fec;
|
||||
__u8 data[HCI_MAX_EIR_LENGTH];
|
||||
} __packed;
|
||||
|
||||
#define HCI_OP_READ_SSP_MODE 0x0c55
|
||||
@ -698,8 +725,8 @@ struct hci_rp_read_flow_control_mode {
|
||||
|
||||
#define HCI_OP_WRITE_LE_HOST_SUPPORTED 0x0c6d
|
||||
struct hci_cp_write_le_host_supported {
|
||||
__u8 le;
|
||||
__u8 simul;
|
||||
__u8 le;
|
||||
__u8 simul;
|
||||
} __packed;
|
||||
|
||||
#define HCI_OP_READ_LOCAL_VERSION 0x1001
|
||||
@ -1155,6 +1182,19 @@ struct hci_ev_le_meta {
|
||||
__u8 subevent;
|
||||
} __packed;
|
||||
|
||||
#define HCI_EV_NUM_COMP_BLOCKS 0x48
|
||||
struct hci_comp_blocks_info {
|
||||
__le16 handle;
|
||||
__le16 pkts;
|
||||
__le16 blocks;
|
||||
} __packed;
|
||||
|
||||
struct hci_ev_num_comp_blocks {
|
||||
__le16 num_blocks;
|
||||
__u8 num_hndl;
|
||||
struct hci_comp_blocks_info handles[0];
|
||||
} __packed;
|
||||
|
||||
/* Low energy meta events */
|
||||
#define HCI_EV_LE_CONN_COMPLETE 0x01
|
||||
struct hci_ev_le_conn_complete {
|
||||
@ -1288,6 +1328,7 @@ struct sockaddr_hci {
|
||||
|
||||
#define HCI_CHANNEL_RAW 0
|
||||
#define HCI_CHANNEL_CONTROL 1
|
||||
#define HCI_CHANNEL_MONITOR 2
|
||||
|
||||
struct hci_filter {
|
||||
unsigned long type_mask;
|
||||
@ -1389,5 +1430,6 @@ struct hci_inquiry_req {
|
||||
#define IREQ_CACHE_FLUSH 0x0001
|
||||
|
||||
extern bool enable_hs;
|
||||
extern bool enable_le;
|
||||
|
||||
#endif /* __HCI_H */
|
||||
|
@ -44,14 +44,31 @@ struct inquiry_data {
|
||||
};
|
||||
|
||||
struct inquiry_entry {
|
||||
struct inquiry_entry *next;
|
||||
struct list_head all; /* inq_cache.all */
|
||||
struct list_head list; /* unknown or resolve */
|
||||
enum {
|
||||
NAME_NOT_KNOWN,
|
||||
NAME_NEEDED,
|
||||
NAME_PENDING,
|
||||
NAME_KNOWN,
|
||||
} name_state;
|
||||
__u32 timestamp;
|
||||
struct inquiry_data data;
|
||||
};
|
||||
|
||||
struct inquiry_cache {
|
||||
struct discovery_state {
|
||||
int type;
|
||||
enum {
|
||||
DISCOVERY_STOPPED,
|
||||
DISCOVERY_STARTING,
|
||||
DISCOVERY_FINDING,
|
||||
DISCOVERY_RESOLVING,
|
||||
DISCOVERY_STOPPING,
|
||||
} state;
|
||||
struct list_head all; /* All devices found during inquiry */
|
||||
struct list_head unknown; /* Name state not known */
|
||||
struct list_head resolve; /* Name needs to be resolved */
|
||||
__u32 timestamp;
|
||||
struct inquiry_entry *list;
|
||||
};
|
||||
|
||||
struct hci_conn_hash {
|
||||
@ -72,18 +89,16 @@ struct bt_uuid {
|
||||
u8 svc_hint;
|
||||
};
|
||||
|
||||
struct key_master_id {
|
||||
struct smp_ltk {
|
||||
struct list_head list;
|
||||
bdaddr_t bdaddr;
|
||||
u8 bdaddr_type;
|
||||
u8 authenticated;
|
||||
u8 type;
|
||||
u8 enc_size;
|
||||
__le16 ediv;
|
||||
u8 rand[8];
|
||||
} __packed;
|
||||
|
||||
struct link_key_data {
|
||||
bdaddr_t bdaddr;
|
||||
u8 type;
|
||||
u8 val[16];
|
||||
u8 pin_len;
|
||||
u8 dlen;
|
||||
u8 data[0];
|
||||
} __packed;
|
||||
|
||||
struct link_key {
|
||||
@ -92,8 +107,6 @@ struct link_key {
|
||||
u8 type;
|
||||
u8 val[16];
|
||||
u8 pin_len;
|
||||
u8 dlen;
|
||||
u8 data[0];
|
||||
};
|
||||
|
||||
struct oob_data {
|
||||
@ -109,11 +122,19 @@ struct adv_entry {
|
||||
u8 bdaddr_type;
|
||||
};
|
||||
|
||||
struct le_scan_params {
|
||||
u8 type;
|
||||
u16 interval;
|
||||
u16 window;
|
||||
int timeout;
|
||||
};
|
||||
|
||||
#define HCI_MAX_SHORT_NAME_LENGTH 10
|
||||
|
||||
#define NUM_REASSEMBLY 4
|
||||
struct hci_dev {
|
||||
struct list_head list;
|
||||
struct mutex lock;
|
||||
atomic_t refcnt;
|
||||
|
||||
char name[8];
|
||||
unsigned long flags;
|
||||
@ -122,6 +143,7 @@ struct hci_dev {
|
||||
__u8 dev_type;
|
||||
bdaddr_t bdaddr;
|
||||
__u8 dev_name[HCI_MAX_NAME_LENGTH];
|
||||
__u8 short_name[HCI_MAX_SHORT_NAME_LENGTH];
|
||||
__u8 eir[HCI_MAX_EIR_LENGTH];
|
||||
__u8 dev_class[3];
|
||||
__u8 major_class;
|
||||
@ -129,7 +151,6 @@ struct hci_dev {
|
||||
__u8 features[8];
|
||||
__u8 host_features[8];
|
||||
__u8 commands[64];
|
||||
__u8 ssp_mode;
|
||||
__u8 hci_ver;
|
||||
__u16 hci_rev;
|
||||
__u8 lmp_ver;
|
||||
@ -217,7 +238,7 @@ struct hci_dev {
|
||||
|
||||
struct list_head mgmt_pending;
|
||||
|
||||
struct inquiry_cache inq_cache;
|
||||
struct discovery_state discovery;
|
||||
struct hci_conn_hash conn_hash;
|
||||
struct list_head blacklist;
|
||||
|
||||
@ -225,6 +246,8 @@ struct hci_dev {
|
||||
|
||||
struct list_head link_keys;
|
||||
|
||||
struct list_head long_term_keys;
|
||||
|
||||
struct list_head remote_oob_data;
|
||||
|
||||
struct list_head adv_entries;
|
||||
@ -234,7 +257,6 @@ struct hci_dev {
|
||||
|
||||
struct sk_buff_head driver_init;
|
||||
|
||||
void *driver_data;
|
||||
void *core_data;
|
||||
|
||||
atomic_t promisc;
|
||||
@ -246,15 +268,17 @@ struct hci_dev {
|
||||
|
||||
struct rfkill *rfkill;
|
||||
|
||||
struct module *owner;
|
||||
|
||||
unsigned long dev_flags;
|
||||
|
||||
struct delayed_work le_scan_disable;
|
||||
|
||||
struct work_struct le_scan;
|
||||
struct le_scan_params le_scan_params;
|
||||
|
||||
int (*open)(struct hci_dev *hdev);
|
||||
int (*close)(struct hci_dev *hdev);
|
||||
int (*flush)(struct hci_dev *hdev);
|
||||
int (*send)(struct sk_buff *skb);
|
||||
void (*destruct)(struct hci_dev *hdev);
|
||||
void (*notify)(struct hci_dev *hdev, unsigned int evt);
|
||||
int (*ioctl)(struct hci_dev *hdev, unsigned int cmd, unsigned long arg);
|
||||
};
|
||||
@ -270,11 +294,10 @@ struct hci_conn {
|
||||
__u16 state;
|
||||
__u8 mode;
|
||||
__u8 type;
|
||||
__u8 out;
|
||||
bool out;
|
||||
__u8 attempt;
|
||||
__u8 dev_class[3];
|
||||
__u8 features[8];
|
||||
__u8 ssp_mode;
|
||||
__u16 interval;
|
||||
__u16 pkt_type;
|
||||
__u16 link_policy;
|
||||
@ -286,12 +309,10 @@ struct hci_conn {
|
||||
__u8 pin_length;
|
||||
__u8 enc_key_size;
|
||||
__u8 io_capability;
|
||||
__u8 power_save;
|
||||
__u16 disc_timeout;
|
||||
unsigned long pend;
|
||||
unsigned long flags;
|
||||
|
||||
__u8 remote_cap;
|
||||
__u8 remote_oob;
|
||||
__u8 remote_auth;
|
||||
|
||||
unsigned int sent;
|
||||
@ -348,21 +369,26 @@ extern int sco_recv_scodata(struct hci_conn *hcon, struct sk_buff *skb);
|
||||
#define INQUIRY_CACHE_AGE_MAX (HZ*30) /* 30 seconds */
|
||||
#define INQUIRY_ENTRY_AGE_MAX (HZ*60) /* 60 seconds */
|
||||
|
||||
static inline void inquiry_cache_init(struct hci_dev *hdev)
|
||||
static inline void discovery_init(struct hci_dev *hdev)
|
||||
{
|
||||
struct inquiry_cache *c = &hdev->inq_cache;
|
||||
c->list = NULL;
|
||||
hdev->discovery.state = DISCOVERY_STOPPED;
|
||||
INIT_LIST_HEAD(&hdev->discovery.all);
|
||||
INIT_LIST_HEAD(&hdev->discovery.unknown);
|
||||
INIT_LIST_HEAD(&hdev->discovery.resolve);
|
||||
}
|
||||
|
||||
bool hci_discovery_active(struct hci_dev *hdev);
|
||||
|
||||
void hci_discovery_set_state(struct hci_dev *hdev, int state);
|
||||
|
||||
static inline int inquiry_cache_empty(struct hci_dev *hdev)
|
||||
{
|
||||
struct inquiry_cache *c = &hdev->inq_cache;
|
||||
return c->list == NULL;
|
||||
return list_empty(&hdev->discovery.all);
|
||||
}
|
||||
|
||||
static inline long inquiry_cache_age(struct hci_dev *hdev)
|
||||
{
|
||||
struct inquiry_cache *c = &hdev->inq_cache;
|
||||
struct discovery_state *c = &hdev->discovery;
|
||||
return jiffies - c->timestamp;
|
||||
}
|
||||
|
||||
@ -372,8 +398,16 @@ static inline long inquiry_entry_age(struct inquiry_entry *e)
|
||||
}
|
||||
|
||||
struct inquiry_entry *hci_inquiry_cache_lookup(struct hci_dev *hdev,
|
||||
bdaddr_t *bdaddr);
|
||||
void hci_inquiry_cache_update(struct hci_dev *hdev, struct inquiry_data *data);
|
||||
bdaddr_t *bdaddr);
|
||||
struct inquiry_entry *hci_inquiry_cache_lookup_unknown(struct hci_dev *hdev,
|
||||
bdaddr_t *bdaddr);
|
||||
struct inquiry_entry *hci_inquiry_cache_lookup_resolve(struct hci_dev *hdev,
|
||||
bdaddr_t *bdaddr,
|
||||
int state);
|
||||
void hci_inquiry_cache_update_resolve(struct hci_dev *hdev,
|
||||
struct inquiry_entry *ie);
|
||||
bool hci_inquiry_cache_update(struct hci_dev *hdev, struct inquiry_data *data,
|
||||
bool name_known, bool *ssp);
|
||||
|
||||
/* ----- HCI Connections ----- */
|
||||
enum {
|
||||
@ -384,8 +418,19 @@ enum {
|
||||
HCI_CONN_MODE_CHANGE_PEND,
|
||||
HCI_CONN_SCO_SETUP_PEND,
|
||||
HCI_CONN_LE_SMP_PEND,
|
||||
HCI_CONN_MGMT_CONNECTED,
|
||||
HCI_CONN_SSP_ENABLED,
|
||||
HCI_CONN_POWER_SAVE,
|
||||
HCI_CONN_REMOTE_OOB,
|
||||
};
|
||||
|
||||
static inline bool hci_conn_ssp_enabled(struct hci_conn *conn)
|
||||
{
|
||||
struct hci_dev *hdev = conn->hdev;
|
||||
return (test_bit(HCI_SSP_ENABLED, &hdev->flags) &&
|
||||
test_bit(HCI_CONN_SSP_ENABLED, &conn->flags));
|
||||
}
|
||||
|
||||
static inline void hci_conn_hash_init(struct hci_dev *hdev)
|
||||
{
|
||||
struct hci_conn_hash *h = &hdev->conn_hash;
|
||||
@ -566,36 +611,33 @@ static inline void hci_conn_put(struct hci_conn *conn)
|
||||
}
|
||||
|
||||
/* ----- HCI Devices ----- */
|
||||
static inline void __hci_dev_put(struct hci_dev *d)
|
||||
static inline void hci_dev_put(struct hci_dev *d)
|
||||
{
|
||||
if (atomic_dec_and_test(&d->refcnt))
|
||||
d->destruct(d);
|
||||
put_device(&d->dev);
|
||||
}
|
||||
|
||||
/*
|
||||
* hci_dev_put and hci_dev_hold are macros to avoid dragging all the
|
||||
* overhead of all the modular infrastructure into this header.
|
||||
*/
|
||||
#define hci_dev_put(d) \
|
||||
do { \
|
||||
__hci_dev_put(d); \
|
||||
module_put(d->owner); \
|
||||
} while (0)
|
||||
|
||||
static inline struct hci_dev *__hci_dev_hold(struct hci_dev *d)
|
||||
static inline struct hci_dev *hci_dev_hold(struct hci_dev *d)
|
||||
{
|
||||
atomic_inc(&d->refcnt);
|
||||
get_device(&d->dev);
|
||||
return d;
|
||||
}
|
||||
|
||||
#define hci_dev_hold(d) \
|
||||
({ \
|
||||
try_module_get(d->owner) ? __hci_dev_hold(d) : NULL; \
|
||||
})
|
||||
|
||||
#define hci_dev_lock(d) mutex_lock(&d->lock)
|
||||
#define hci_dev_unlock(d) mutex_unlock(&d->lock)
|
||||
|
||||
#define to_hci_dev(d) container_of(d, struct hci_dev, dev)
|
||||
#define to_hci_conn(c) container_of(c, struct hci_conn, dev)
|
||||
|
||||
static inline void *hci_get_drvdata(struct hci_dev *hdev)
|
||||
{
|
||||
return dev_get_drvdata(&hdev->dev);
|
||||
}
|
||||
|
||||
static inline void hci_set_drvdata(struct hci_dev *hdev, void *data)
|
||||
{
|
||||
dev_set_drvdata(&hdev->dev, data);
|
||||
}
|
||||
|
||||
struct hci_dev *hci_dev_get(int index);
|
||||
struct hci_dev *hci_get_route(bdaddr_t *src, bdaddr_t *dst);
|
||||
|
||||
@ -619,20 +661,23 @@ int hci_inquiry(void __user *arg);
|
||||
|
||||
struct bdaddr_list *hci_blacklist_lookup(struct hci_dev *hdev, bdaddr_t *bdaddr);
|
||||
int hci_blacklist_clear(struct hci_dev *hdev);
|
||||
int hci_blacklist_add(struct hci_dev *hdev, bdaddr_t *bdaddr);
|
||||
int hci_blacklist_del(struct hci_dev *hdev, bdaddr_t *bdaddr);
|
||||
int hci_blacklist_add(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type);
|
||||
int hci_blacklist_del(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type);
|
||||
|
||||
int hci_uuids_clear(struct hci_dev *hdev);
|
||||
|
||||
int hci_link_keys_clear(struct hci_dev *hdev);
|
||||
struct link_key *hci_find_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr);
|
||||
int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key,
|
||||
bdaddr_t *bdaddr, u8 *val, u8 type, u8 pin_len);
|
||||
struct link_key *hci_find_ltk(struct hci_dev *hdev, __le16 ediv, u8 rand[8]);
|
||||
struct link_key *hci_find_link_key_type(struct hci_dev *hdev,
|
||||
bdaddr_t *bdaddr, u8 type);
|
||||
int hci_add_ltk(struct hci_dev *hdev, int new_key, bdaddr_t *bdaddr,
|
||||
u8 key_size, __le16 ediv, u8 rand[8], u8 ltk[16]);
|
||||
bdaddr_t *bdaddr, u8 *val, u8 type, u8 pin_len);
|
||||
struct smp_ltk *hci_find_ltk(struct hci_dev *hdev, __le16 ediv, u8 rand[8]);
|
||||
int hci_add_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type, u8 type,
|
||||
int new_key, u8 authenticated, u8 tk[16], u8 enc_size, u16 ediv,
|
||||
u8 rand[8]);
|
||||
struct smp_ltk *hci_find_ltk_by_addr(struct hci_dev *hdev, bdaddr_t *bdaddr,
|
||||
u8 addr_type);
|
||||
int hci_remove_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr);
|
||||
int hci_smp_ltks_clear(struct hci_dev *hdev);
|
||||
int hci_remove_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr);
|
||||
|
||||
int hci_remote_oob_data_clear(struct hci_dev *hdev);
|
||||
@ -674,6 +719,7 @@ void hci_conn_del_sysfs(struct hci_conn *conn);
|
||||
#define lmp_ssp_capable(dev) ((dev)->features[6] & LMP_SIMPLE_PAIR)
|
||||
#define lmp_no_flush_capable(dev) ((dev)->features[6] & LMP_NO_FLUSH)
|
||||
#define lmp_le_capable(dev) ((dev)->features[4] & LMP_LE)
|
||||
#define lmp_bredr_capable(dev) (!((dev)->features[4] & LMP_NO_BREDR))
|
||||
|
||||
/* ----- Extended LMP capabilities ----- */
|
||||
#define lmp_host_le_capable(dev) ((dev)->host_features[0] & LMP_HOST_LE)
|
||||
@ -755,7 +801,7 @@ static inline void hci_proto_auth_cfm(struct hci_conn *conn, __u8 status)
|
||||
if (conn->type != ACL_LINK && conn->type != LE_LINK)
|
||||
return;
|
||||
|
||||
if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend))
|
||||
if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags))
|
||||
return;
|
||||
|
||||
encrypt = (conn->link_mode & HCI_LM_ENCRYPT) ? 0x01 : 0x00;
|
||||
@ -796,7 +842,7 @@ static inline void hci_auth_cfm(struct hci_conn *conn, __u8 status)
|
||||
|
||||
hci_proto_auth_cfm(conn, status);
|
||||
|
||||
if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend))
|
||||
if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags))
|
||||
return;
|
||||
|
||||
encrypt = (conn->link_mode & HCI_LM_ENCRYPT) ? 0x01 : 0x00;
|
||||
@ -859,25 +905,71 @@ static inline void hci_role_switch_cfm(struct hci_conn *conn, __u8 status,
|
||||
read_unlock(&hci_cb_list_lock);
|
||||
}
|
||||
|
||||
static inline bool eir_has_data_type(u8 *data, size_t data_len, u8 type)
|
||||
{
|
||||
u8 field_len;
|
||||
size_t parsed;
|
||||
|
||||
for (parsed = 0; parsed < data_len - 1; parsed += field_len) {
|
||||
field_len = data[0];
|
||||
|
||||
if (field_len == 0)
|
||||
break;
|
||||
|
||||
parsed += field_len + 1;
|
||||
|
||||
if (parsed > data_len)
|
||||
break;
|
||||
|
||||
if (data[1] == type)
|
||||
return true;
|
||||
|
||||
data += field_len + 1;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline u16 eir_append_data(u8 *eir, u16 eir_len, u8 type, u8 *data,
|
||||
u8 data_len)
|
||||
{
|
||||
eir[eir_len++] = sizeof(type) + data_len;
|
||||
eir[eir_len++] = type;
|
||||
memcpy(&eir[eir_len], data, data_len);
|
||||
eir_len += data_len;
|
||||
|
||||
return eir_len;
|
||||
}
|
||||
|
||||
int hci_register_cb(struct hci_cb *hcb);
|
||||
int hci_unregister_cb(struct hci_cb *hcb);
|
||||
|
||||
int hci_register_notifier(struct notifier_block *nb);
|
||||
int hci_unregister_notifier(struct notifier_block *nb);
|
||||
|
||||
int hci_send_cmd(struct hci_dev *hdev, __u16 opcode, __u32 plen, void *param);
|
||||
void hci_send_acl(struct hci_chan *chan, struct sk_buff *skb, __u16 flags);
|
||||
void hci_send_sco(struct hci_conn *conn, struct sk_buff *skb);
|
||||
|
||||
void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 opcode);
|
||||
|
||||
void hci_si_event(struct hci_dev *hdev, int type, int dlen, void *data);
|
||||
|
||||
/* ----- HCI Sockets ----- */
|
||||
void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb,
|
||||
struct sock *skip_sk);
|
||||
void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb);
|
||||
void hci_send_to_control(struct sk_buff *skb, struct sock *skip_sk);
|
||||
void hci_send_to_monitor(struct hci_dev *hdev, struct sk_buff *skb);
|
||||
|
||||
void hci_sock_dev_event(struct hci_dev *hdev, int event);
|
||||
|
||||
/* Management interface */
|
||||
#define MGMT_ADDR_BREDR 0x00
|
||||
#define MGMT_ADDR_LE_PUBLIC 0x01
|
||||
#define MGMT_ADDR_LE_RANDOM 0x02
|
||||
#define MGMT_ADDR_INVALID 0xff
|
||||
|
||||
#define DISCOV_TYPE_BREDR (BIT(MGMT_ADDR_BREDR))
|
||||
#define DISCOV_TYPE_LE (BIT(MGMT_ADDR_LE_PUBLIC) | \
|
||||
BIT(MGMT_ADDR_LE_RANDOM))
|
||||
#define DISCOV_TYPE_INTERLEAVED (BIT(MGMT_ADDR_BREDR) | \
|
||||
BIT(MGMT_ADDR_LE_PUBLIC) | \
|
||||
BIT(MGMT_ADDR_LE_RANDOM))
|
||||
|
||||
int mgmt_control(struct sock *sk, struct msghdr *msg, size_t len);
|
||||
int mgmt_index_added(struct hci_dev *hdev);
|
||||
int mgmt_index_removed(struct hci_dev *hdev);
|
||||
@ -886,56 +978,67 @@ int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable);
|
||||
int mgmt_connectable(struct hci_dev *hdev, u8 connectable);
|
||||
int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status);
|
||||
int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
|
||||
u8 persistent);
|
||||
int mgmt_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
|
||||
u8 addr_type);
|
||||
int mgmt_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
|
||||
u8 addr_type);
|
||||
int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 status);
|
||||
u8 persistent);
|
||||
int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
|
||||
u8 addr_type, u32 flags, u8 *name, u8 name_len,
|
||||
u8 *dev_class);
|
||||
int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
|
||||
u8 link_type, u8 addr_type);
|
||||
int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
|
||||
u8 link_type, u8 addr_type, u8 status);
|
||||
int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
|
||||
u8 addr_type, u8 status);
|
||||
u8 addr_type, u8 status);
|
||||
int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure);
|
||||
int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
|
||||
u8 status);
|
||||
u8 status);
|
||||
int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
|
||||
u8 status);
|
||||
u8 status);
|
||||
int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
|
||||
__le32 value, u8 confirm_hint);
|
||||
u8 link_type, u8 addr_type, __le32 value,
|
||||
u8 confirm_hint);
|
||||
int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
|
||||
u8 status);
|
||||
int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev,
|
||||
bdaddr_t *bdaddr, u8 status);
|
||||
int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr);
|
||||
u8 link_type, u8 addr_type, u8 status);
|
||||
int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
|
||||
u8 link_type, u8 addr_type, u8 status);
|
||||
int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
|
||||
u8 link_type, u8 addr_type);
|
||||
int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
|
||||
u8 status);
|
||||
int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev,
|
||||
bdaddr_t *bdaddr, u8 status);
|
||||
int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 status);
|
||||
u8 link_type, u8 addr_type, u8 status);
|
||||
int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
|
||||
u8 link_type, u8 addr_type, u8 status);
|
||||
int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
|
||||
u8 addr_type, u8 status);
|
||||
int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status);
|
||||
int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status);
|
||||
int mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
|
||||
u8 status);
|
||||
int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status);
|
||||
int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
|
||||
u8 *randomizer, u8 status);
|
||||
u8 *randomizer, u8 status);
|
||||
int mgmt_le_enable_complete(struct hci_dev *hdev, u8 enable, u8 status);
|
||||
int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
|
||||
u8 addr_type, u8 *dev_class, s8 rssi, u8 *eir);
|
||||
int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *name);
|
||||
u8 addr_type, u8 *dev_class, s8 rssi, u8 cfm_name,
|
||||
u8 ssp, u8 *eir, u16 eir_len);
|
||||
int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
|
||||
u8 addr_type, s8 rssi, u8 *name, u8 name_len);
|
||||
int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status);
|
||||
int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status);
|
||||
int mgmt_discovering(struct hci_dev *hdev, u8 discovering);
|
||||
int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr);
|
||||
int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr);
|
||||
int mgmt_interleaved_discovery(struct hci_dev *hdev);
|
||||
int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type);
|
||||
int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type);
|
||||
|
||||
int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent);
|
||||
|
||||
/* HCI info for socket */
|
||||
#define hci_pi(sk) ((struct hci_pinfo *) sk)
|
||||
|
||||
/* HCI socket flags */
|
||||
#define HCI_PI_MGMT_INIT 0
|
||||
|
||||
struct hci_pinfo {
|
||||
struct bt_sock bt;
|
||||
struct hci_dev *hdev;
|
||||
struct hci_filter filter;
|
||||
__u32 cmsg_mask;
|
||||
unsigned short channel;
|
||||
unsigned long flags;
|
||||
};
|
||||
|
||||
/* HCI security filter */
|
||||
@ -966,5 +1069,7 @@ void hci_le_ltk_neg_reply(struct hci_conn *conn);
|
||||
|
||||
int hci_do_inquiry(struct hci_dev *hdev, u8 length);
|
||||
int hci_cancel_inquiry(struct hci_dev *hdev);
|
||||
int hci_le_scan(struct hci_dev *hdev, u8 type, u16 interval, u16 window,
|
||||
int timeout);
|
||||
|
||||
#endif /* __HCI_CORE_H */
|
||||
|
51
include/net/bluetooth/hci_mon.h
Normal file
51
include/net/bluetooth/hci_mon.h
Normal file
@ -0,0 +1,51 @@
|
||||
/*
|
||||
BlueZ - Bluetooth protocol stack for Linux
|
||||
|
||||
Copyright (C) 2011-2012 Intel Corporation
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License version 2 as
|
||||
published by the Free Software Foundation;
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
|
||||
IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
|
||||
CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
|
||||
COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
|
||||
SOFTWARE IS DISCLAIMED.
|
||||
*/
|
||||
|
||||
#ifndef __HCI_MON_H
|
||||
#define __HCI_MON_H
|
||||
|
||||
struct hci_mon_hdr {
|
||||
__le16 opcode;
|
||||
__le16 index;
|
||||
__le16 len;
|
||||
} __packed;
|
||||
#define HCI_MON_HDR_SIZE 6
|
||||
|
||||
#define HCI_MON_NEW_INDEX 0
|
||||
#define HCI_MON_DEL_INDEX 1
|
||||
#define HCI_MON_COMMAND_PKT 2
|
||||
#define HCI_MON_EVENT_PKT 3
|
||||
#define HCI_MON_ACL_TX_PKT 4
|
||||
#define HCI_MON_ACL_RX_PKT 5
|
||||
#define HCI_MON_SCO_TX_PKT 6
|
||||
#define HCI_MON_SCO_RX_PKT 7
|
||||
|
||||
struct hci_mon_new_index {
|
||||
__u8 type;
|
||||
__u8 bus;
|
||||
bdaddr_t bdaddr;
|
||||
char name[8];
|
||||
} __packed;
|
||||
#define HCI_MON_NEW_INDEX_SIZE 16
|
||||
|
||||
#endif /* __HCI_MON_H */
|
@ -45,11 +45,11 @@
|
||||
#define L2CAP_DEFAULT_SDU_ITIME 0xFFFFFFFF
|
||||
#define L2CAP_DEFAULT_ACC_LAT 0xFFFFFFFF
|
||||
|
||||
#define L2CAP_DISC_TIMEOUT (100)
|
||||
#define L2CAP_DISC_REJ_TIMEOUT (5000) /* 5 seconds */
|
||||
#define L2CAP_ENC_TIMEOUT (5000) /* 5 seconds */
|
||||
#define L2CAP_CONN_TIMEOUT (40000) /* 40 seconds */
|
||||
#define L2CAP_INFO_TIMEOUT (4000) /* 4 seconds */
|
||||
#define L2CAP_DISC_TIMEOUT msecs_to_jiffies(100)
|
||||
#define L2CAP_DISC_REJ_TIMEOUT msecs_to_jiffies(5000)
|
||||
#define L2CAP_ENC_TIMEOUT msecs_to_jiffies(5000)
|
||||
#define L2CAP_CONN_TIMEOUT msecs_to_jiffies(40000)
|
||||
#define L2CAP_INFO_TIMEOUT msecs_to_jiffies(4000)
|
||||
|
||||
/* L2CAP socket address */
|
||||
struct sockaddr_l2 {
|
||||
@ -492,51 +492,56 @@ struct l2cap_chan {
|
||||
struct sk_buff_head srej_q;
|
||||
struct list_head srej_l;
|
||||
|
||||
struct list_head list;
|
||||
struct list_head global_l;
|
||||
struct list_head list;
|
||||
struct list_head global_l;
|
||||
|
||||
void *data;
|
||||
struct l2cap_ops *ops;
|
||||
void *data;
|
||||
struct l2cap_ops *ops;
|
||||
struct mutex lock;
|
||||
};
|
||||
|
||||
struct l2cap_ops {
|
||||
char *name;
|
||||
char *name;
|
||||
|
||||
struct l2cap_chan *(*new_connection) (void *data);
|
||||
int (*recv) (void *data, struct sk_buff *skb);
|
||||
void (*close) (void *data);
|
||||
void (*state_change) (void *data, int state);
|
||||
struct sk_buff *(*alloc_skb) (struct l2cap_chan *chan,
|
||||
unsigned long len, int nb, int *err);
|
||||
|
||||
};
|
||||
|
||||
struct l2cap_conn {
|
||||
struct hci_conn *hcon;
|
||||
struct hci_chan *hchan;
|
||||
struct hci_conn *hcon;
|
||||
struct hci_chan *hchan;
|
||||
|
||||
bdaddr_t *dst;
|
||||
bdaddr_t *src;
|
||||
bdaddr_t *dst;
|
||||
bdaddr_t *src;
|
||||
|
||||
unsigned int mtu;
|
||||
unsigned int mtu;
|
||||
|
||||
__u32 feat_mask;
|
||||
__u32 feat_mask;
|
||||
__u8 fixed_chan_mask;
|
||||
|
||||
__u8 info_state;
|
||||
__u8 info_ident;
|
||||
__u8 info_state;
|
||||
__u8 info_ident;
|
||||
|
||||
struct delayed_work info_timer;
|
||||
struct delayed_work info_timer;
|
||||
|
||||
spinlock_t lock;
|
||||
spinlock_t lock;
|
||||
|
||||
struct sk_buff *rx_skb;
|
||||
__u32 rx_len;
|
||||
__u8 tx_ident;
|
||||
struct sk_buff *rx_skb;
|
||||
__u32 rx_len;
|
||||
__u8 tx_ident;
|
||||
|
||||
__u8 disc_reason;
|
||||
__u8 disc_reason;
|
||||
|
||||
struct delayed_work security_timer;
|
||||
struct smp_chan *smp_chan;
|
||||
struct delayed_work security_timer;
|
||||
struct smp_chan *smp_chan;
|
||||
|
||||
struct list_head chan_l;
|
||||
struct mutex chan_lock;
|
||||
struct list_head chan_l;
|
||||
struct mutex chan_lock;
|
||||
};
|
||||
|
||||
#define L2CAP_INFO_CL_MTU_REQ_SENT 0x01
|
||||
@ -551,9 +556,9 @@ struct l2cap_conn {
|
||||
#define l2cap_pi(sk) ((struct l2cap_pinfo *) sk)
|
||||
|
||||
struct l2cap_pinfo {
|
||||
struct bt_sock bt;
|
||||
struct bt_sock bt;
|
||||
struct l2cap_chan *chan;
|
||||
struct sk_buff *rx_busy_skb;
|
||||
struct sk_buff *rx_busy_skb;
|
||||
};
|
||||
|
||||
enum {
|
||||
@ -606,21 +611,37 @@ static inline void l2cap_chan_put(struct l2cap_chan *c)
|
||||
kfree(c);
|
||||
}
|
||||
|
||||
static inline void l2cap_chan_lock(struct l2cap_chan *chan)
|
||||
{
|
||||
mutex_lock(&chan->lock);
|
||||
}
|
||||
|
||||
static inline void l2cap_chan_unlock(struct l2cap_chan *chan)
|
||||
{
|
||||
mutex_unlock(&chan->lock);
|
||||
}
|
||||
|
||||
static inline void l2cap_set_timer(struct l2cap_chan *chan,
|
||||
struct delayed_work *work, long timeout)
|
||||
{
|
||||
BT_DBG("chan %p state %d timeout %ld", chan, chan->state, timeout);
|
||||
BT_DBG("chan %p state %s timeout %ld", chan,
|
||||
state_to_string(chan->state), timeout);
|
||||
|
||||
if (!cancel_delayed_work(work))
|
||||
l2cap_chan_hold(chan);
|
||||
schedule_delayed_work(work, timeout);
|
||||
}
|
||||
|
||||
static inline void l2cap_clear_timer(struct l2cap_chan *chan,
|
||||
static inline bool l2cap_clear_timer(struct l2cap_chan *chan,
|
||||
struct delayed_work *work)
|
||||
{
|
||||
if (cancel_delayed_work(work))
|
||||
bool ret;
|
||||
|
||||
ret = cancel_delayed_work(work);
|
||||
if (ret)
|
||||
l2cap_chan_put(chan);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define __set_chan_timer(c, t) l2cap_set_timer(c, &c->chan_timer, (t))
|
||||
|
@ -2,6 +2,7 @@
|
||||
BlueZ - Bluetooth protocol stack for Linux
|
||||
|
||||
Copyright (C) 2010 Nokia Corporation
|
||||
Copyright (C) 2011-2012 Intel Corporation
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License version 2 as
|
||||
@ -39,29 +40,47 @@
|
||||
#define MGMT_STATUS_INVALID_PARAMS 0x0d
|
||||
#define MGMT_STATUS_DISCONNECTED 0x0e
|
||||
#define MGMT_STATUS_NOT_POWERED 0x0f
|
||||
#define MGMT_STATUS_CANCELLED 0x10
|
||||
#define MGMT_STATUS_INVALID_INDEX 0x11
|
||||
|
||||
struct mgmt_hdr {
|
||||
__le16 opcode;
|
||||
__le16 index;
|
||||
__le16 len;
|
||||
__le16 opcode;
|
||||
__le16 index;
|
||||
__le16 len;
|
||||
} __packed;
|
||||
|
||||
struct mgmt_addr_info {
|
||||
bdaddr_t bdaddr;
|
||||
__u8 type;
|
||||
} __packed;
|
||||
#define MGMT_ADDR_INFO_SIZE 7
|
||||
|
||||
#define MGMT_OP_READ_VERSION 0x0001
|
||||
#define MGMT_READ_VERSION_SIZE 0
|
||||
struct mgmt_rp_read_version {
|
||||
__u8 version;
|
||||
__le16 revision;
|
||||
__u8 version;
|
||||
__le16 revision;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OP_READ_COMMANDS 0x0002
|
||||
#define MGMT_READ_COMMANDS_SIZE 0
|
||||
struct mgmt_rp_read_commands {
|
||||
__le16 num_commands;
|
||||
__le16 num_events;
|
||||
__le16 opcodes[0];
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OP_READ_INDEX_LIST 0x0003
|
||||
#define MGMT_READ_INDEX_LIST_SIZE 0
|
||||
struct mgmt_rp_read_index_list {
|
||||
__le16 num_controllers;
|
||||
__le16 index[0];
|
||||
__le16 num_controllers;
|
||||
__le16 index[0];
|
||||
} __packed;
|
||||
|
||||
/* Reserve one extra byte for names in management messages so that they
|
||||
* are always guaranteed to be nul-terminated */
|
||||
#define MGMT_MAX_NAME_LENGTH (HCI_MAX_NAME_LENGTH + 1)
|
||||
#define MGMT_MAX_SHORT_NAME_LENGTH (10 + 1)
|
||||
#define MGMT_MAX_SHORT_NAME_LENGTH (HCI_MAX_SHORT_NAME_LENGTH + 1)
|
||||
|
||||
#define MGMT_SETTING_POWERED 0x00000001
|
||||
#define MGMT_SETTING_CONNECTABLE 0x00000002
|
||||
@ -75,28 +94,32 @@ struct mgmt_rp_read_index_list {
|
||||
#define MGMT_SETTING_LE 0x00000200
|
||||
|
||||
#define MGMT_OP_READ_INFO 0x0004
|
||||
#define MGMT_READ_INFO_SIZE 0
|
||||
struct mgmt_rp_read_info {
|
||||
bdaddr_t bdaddr;
|
||||
__u8 version;
|
||||
__le16 manufacturer;
|
||||
__le32 supported_settings;
|
||||
__le32 current_settings;
|
||||
__u8 dev_class[3];
|
||||
__u8 name[MGMT_MAX_NAME_LENGTH];
|
||||
__u8 short_name[MGMT_MAX_SHORT_NAME_LENGTH];
|
||||
bdaddr_t bdaddr;
|
||||
__u8 version;
|
||||
__le16 manufacturer;
|
||||
__le32 supported_settings;
|
||||
__le32 current_settings;
|
||||
__u8 dev_class[3];
|
||||
__u8 name[MGMT_MAX_NAME_LENGTH];
|
||||
__u8 short_name[MGMT_MAX_SHORT_NAME_LENGTH];
|
||||
} __packed;
|
||||
|
||||
struct mgmt_mode {
|
||||
__u8 val;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_SETTING_SIZE 1
|
||||
|
||||
#define MGMT_OP_SET_POWERED 0x0005
|
||||
|
||||
#define MGMT_OP_SET_DISCOVERABLE 0x0006
|
||||
struct mgmt_cp_set_discoverable {
|
||||
__u8 val;
|
||||
__u16 timeout;
|
||||
__u8 val;
|
||||
__u16 timeout;
|
||||
} __packed;
|
||||
#define MGMT_SET_DISCOVERABLE_SIZE 3
|
||||
|
||||
#define MGMT_OP_SET_CONNECTABLE 0x0007
|
||||
|
||||
@ -111,73 +134,76 @@ struct mgmt_cp_set_discoverable {
|
||||
#define MGMT_OP_SET_HS 0x000C
|
||||
|
||||
#define MGMT_OP_SET_LE 0x000D
|
||||
|
||||
#define MGMT_OP_SET_DEV_CLASS 0x000E
|
||||
struct mgmt_cp_set_dev_class {
|
||||
__u8 major;
|
||||
__u8 minor;
|
||||
__u8 major;
|
||||
__u8 minor;
|
||||
} __packed;
|
||||
#define MGMT_SET_DEV_CLASS_SIZE 2
|
||||
|
||||
#define MGMT_OP_SET_LOCAL_NAME 0x000F
|
||||
struct mgmt_cp_set_local_name {
|
||||
__u8 name[MGMT_MAX_NAME_LENGTH];
|
||||
__u8 name[MGMT_MAX_NAME_LENGTH];
|
||||
__u8 short_name[MGMT_MAX_SHORT_NAME_LENGTH];
|
||||
} __packed;
|
||||
#define MGMT_SET_LOCAL_NAME_SIZE 260
|
||||
|
||||
#define MGMT_OP_ADD_UUID 0x0010
|
||||
struct mgmt_cp_add_uuid {
|
||||
__u8 uuid[16];
|
||||
__u8 svc_hint;
|
||||
__u8 uuid[16];
|
||||
__u8 svc_hint;
|
||||
} __packed;
|
||||
#define MGMT_ADD_UUID_SIZE 17
|
||||
|
||||
#define MGMT_OP_REMOVE_UUID 0x0011
|
||||
struct mgmt_cp_remove_uuid {
|
||||
__u8 uuid[16];
|
||||
__u8 uuid[16];
|
||||
} __packed;
|
||||
#define MGMT_REMOVE_UUID_SIZE 16
|
||||
|
||||
struct mgmt_link_key_info {
|
||||
bdaddr_t bdaddr;
|
||||
u8 type;
|
||||
u8 val[16];
|
||||
u8 pin_len;
|
||||
struct mgmt_addr_info addr;
|
||||
__u8 type;
|
||||
__u8 val[16];
|
||||
__u8 pin_len;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OP_LOAD_LINK_KEYS 0x0012
|
||||
struct mgmt_cp_load_link_keys {
|
||||
__u8 debug_keys;
|
||||
__le16 key_count;
|
||||
struct mgmt_link_key_info keys[0];
|
||||
__u8 debug_keys;
|
||||
__le16 key_count;
|
||||
struct mgmt_link_key_info keys[0];
|
||||
} __packed;
|
||||
#define MGMT_LOAD_LINK_KEYS_SIZE 3
|
||||
|
||||
struct mgmt_ltk_info {
|
||||
struct mgmt_addr_info addr;
|
||||
__u8 authenticated;
|
||||
__u8 master;
|
||||
__u8 enc_size;
|
||||
__le16 ediv;
|
||||
__u8 rand[8];
|
||||
__u8 val[16];
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OP_REMOVE_KEYS 0x0013
|
||||
struct mgmt_cp_remove_keys {
|
||||
bdaddr_t bdaddr;
|
||||
__u8 disconnect;
|
||||
#define MGMT_OP_LOAD_LONG_TERM_KEYS 0x0013
|
||||
struct mgmt_cp_load_long_term_keys {
|
||||
__le16 key_count;
|
||||
struct mgmt_ltk_info keys[0];
|
||||
} __packed;
|
||||
struct mgmt_rp_remove_keys {
|
||||
bdaddr_t bdaddr;
|
||||
__u8 status;
|
||||
};
|
||||
#define MGMT_LOAD_LONG_TERM_KEYS_SIZE 2
|
||||
|
||||
#define MGMT_OP_DISCONNECT 0x0014
|
||||
struct mgmt_cp_disconnect {
|
||||
bdaddr_t bdaddr;
|
||||
struct mgmt_addr_info addr;
|
||||
} __packed;
|
||||
#define MGMT_DISCONNECT_SIZE MGMT_ADDR_INFO_SIZE
|
||||
struct mgmt_rp_disconnect {
|
||||
bdaddr_t bdaddr;
|
||||
__u8 status;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_ADDR_BREDR 0x00
|
||||
#define MGMT_ADDR_LE_PUBLIC 0x01
|
||||
#define MGMT_ADDR_LE_RANDOM 0x02
|
||||
#define MGMT_ADDR_INVALID 0xff
|
||||
|
||||
struct mgmt_addr_info {
|
||||
bdaddr_t bdaddr;
|
||||
__u8 type;
|
||||
struct mgmt_addr_info addr;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OP_GET_CONNECTIONS 0x0015
|
||||
#define MGMT_GET_CONNECTIONS_SIZE 0
|
||||
struct mgmt_rp_get_connections {
|
||||
__le16 conn_count;
|
||||
struct mgmt_addr_info addr[0];
|
||||
@ -185,124 +211,152 @@ struct mgmt_rp_get_connections {
|
||||
|
||||
#define MGMT_OP_PIN_CODE_REPLY 0x0016
|
||||
struct mgmt_cp_pin_code_reply {
|
||||
bdaddr_t bdaddr;
|
||||
__u8 pin_len;
|
||||
__u8 pin_code[16];
|
||||
struct mgmt_addr_info addr;
|
||||
__u8 pin_len;
|
||||
__u8 pin_code[16];
|
||||
} __packed;
|
||||
#define MGMT_PIN_CODE_REPLY_SIZE (MGMT_ADDR_INFO_SIZE + 17)
|
||||
struct mgmt_rp_pin_code_reply {
|
||||
bdaddr_t bdaddr;
|
||||
uint8_t status;
|
||||
struct mgmt_addr_info addr;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OP_PIN_CODE_NEG_REPLY 0x0017
|
||||
struct mgmt_cp_pin_code_neg_reply {
|
||||
bdaddr_t bdaddr;
|
||||
struct mgmt_addr_info addr;
|
||||
} __packed;
|
||||
#define MGMT_PIN_CODE_NEG_REPLY_SIZE MGMT_ADDR_INFO_SIZE
|
||||
|
||||
#define MGMT_OP_SET_IO_CAPABILITY 0x0018
|
||||
struct mgmt_cp_set_io_capability {
|
||||
__u8 io_capability;
|
||||
__u8 io_capability;
|
||||
} __packed;
|
||||
#define MGMT_SET_IO_CAPABILITY_SIZE 1
|
||||
|
||||
#define MGMT_OP_PAIR_DEVICE 0x0019
|
||||
struct mgmt_cp_pair_device {
|
||||
struct mgmt_addr_info addr;
|
||||
__u8 io_cap;
|
||||
__u8 io_cap;
|
||||
} __packed;
|
||||
#define MGMT_PAIR_DEVICE_SIZE (MGMT_ADDR_INFO_SIZE + 1)
|
||||
struct mgmt_rp_pair_device {
|
||||
struct mgmt_addr_info addr;
|
||||
__u8 status;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OP_USER_CONFIRM_REPLY 0x001A
|
||||
#define MGMT_OP_CANCEL_PAIR_DEVICE 0x001A
|
||||
#define MGMT_CANCEL_PAIR_DEVICE_SIZE MGMT_ADDR_INFO_SIZE
|
||||
|
||||
#define MGMT_OP_UNPAIR_DEVICE 0x001B
|
||||
struct mgmt_cp_unpair_device {
|
||||
struct mgmt_addr_info addr;
|
||||
__u8 disconnect;
|
||||
} __packed;
|
||||
#define MGMT_UNPAIR_DEVICE_SIZE (MGMT_ADDR_INFO_SIZE + 1)
|
||||
struct mgmt_rp_unpair_device {
|
||||
struct mgmt_addr_info addr;
|
||||
};
|
||||
|
||||
#define MGMT_OP_USER_CONFIRM_REPLY 0x001C
|
||||
struct mgmt_cp_user_confirm_reply {
|
||||
bdaddr_t bdaddr;
|
||||
struct mgmt_addr_info addr;
|
||||
} __packed;
|
||||
#define MGMT_USER_CONFIRM_REPLY_SIZE MGMT_ADDR_INFO_SIZE
|
||||
struct mgmt_rp_user_confirm_reply {
|
||||
bdaddr_t bdaddr;
|
||||
__u8 status;
|
||||
struct mgmt_addr_info addr;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OP_USER_CONFIRM_NEG_REPLY 0x001B
|
||||
#define MGMT_OP_USER_CONFIRM_NEG_REPLY 0x001D
|
||||
struct mgmt_cp_user_confirm_neg_reply {
|
||||
bdaddr_t bdaddr;
|
||||
struct mgmt_addr_info addr;
|
||||
} __packed;
|
||||
#define MGMT_USER_CONFIRM_NEG_REPLY_SIZE MGMT_ADDR_INFO_SIZE
|
||||
|
||||
#define MGMT_OP_USER_PASSKEY_REPLY 0x001C
|
||||
#define MGMT_OP_USER_PASSKEY_REPLY 0x001E
|
||||
struct mgmt_cp_user_passkey_reply {
|
||||
bdaddr_t bdaddr;
|
||||
__le32 passkey;
|
||||
struct mgmt_addr_info addr;
|
||||
__le32 passkey;
|
||||
} __packed;
|
||||
#define MGMT_USER_PASSKEY_REPLY_SIZE (MGMT_ADDR_INFO_SIZE + 4)
|
||||
struct mgmt_rp_user_passkey_reply {
|
||||
bdaddr_t bdaddr;
|
||||
__u8 status;
|
||||
struct mgmt_addr_info addr;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OP_USER_PASSKEY_NEG_REPLY 0x001D
|
||||
#define MGMT_OP_USER_PASSKEY_NEG_REPLY 0x001F
|
||||
struct mgmt_cp_user_passkey_neg_reply {
|
||||
bdaddr_t bdaddr;
|
||||
struct mgmt_addr_info addr;
|
||||
} __packed;
|
||||
#define MGMT_USER_PASSKEY_NEG_REPLY_SIZE MGMT_ADDR_INFO_SIZE
|
||||
|
||||
#define MGMT_OP_READ_LOCAL_OOB_DATA 0x001E
|
||||
#define MGMT_OP_READ_LOCAL_OOB_DATA 0x0020
|
||||
#define MGMT_READ_LOCAL_OOB_DATA_SIZE 0
|
||||
struct mgmt_rp_read_local_oob_data {
|
||||
__u8 hash[16];
|
||||
__u8 randomizer[16];
|
||||
__u8 hash[16];
|
||||
__u8 randomizer[16];
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OP_ADD_REMOTE_OOB_DATA 0x001F
|
||||
#define MGMT_OP_ADD_REMOTE_OOB_DATA 0x0021
|
||||
struct mgmt_cp_add_remote_oob_data {
|
||||
bdaddr_t bdaddr;
|
||||
__u8 hash[16];
|
||||
__u8 randomizer[16];
|
||||
struct mgmt_addr_info addr;
|
||||
__u8 hash[16];
|
||||
__u8 randomizer[16];
|
||||
} __packed;
|
||||
#define MGMT_ADD_REMOTE_OOB_DATA_SIZE (MGMT_ADDR_INFO_SIZE + 32)
|
||||
|
||||
#define MGMT_OP_REMOVE_REMOTE_OOB_DATA 0x0020
|
||||
#define MGMT_OP_REMOVE_REMOTE_OOB_DATA 0x0022
|
||||
struct mgmt_cp_remove_remote_oob_data {
|
||||
bdaddr_t bdaddr;
|
||||
struct mgmt_addr_info addr;
|
||||
} __packed;
|
||||
#define MGMT_REMOVE_REMOTE_OOB_DATA_SIZE MGMT_ADDR_INFO_SIZE
|
||||
|
||||
#define MGMT_OP_START_DISCOVERY 0x0021
|
||||
#define MGMT_OP_START_DISCOVERY 0x0023
|
||||
struct mgmt_cp_start_discovery {
|
||||
__u8 type;
|
||||
} __packed;
|
||||
#define MGMT_START_DISCOVERY_SIZE 1
|
||||
|
||||
#define MGMT_OP_STOP_DISCOVERY 0x0022
|
||||
#define MGMT_OP_STOP_DISCOVERY 0x0024
|
||||
struct mgmt_cp_stop_discovery {
|
||||
__u8 type;
|
||||
} __packed;
|
||||
#define MGMT_STOP_DISCOVERY_SIZE 1
|
||||
|
||||
#define MGMT_OP_CONFIRM_NAME 0x0023
|
||||
#define MGMT_OP_CONFIRM_NAME 0x0025
|
||||
struct mgmt_cp_confirm_name {
|
||||
bdaddr_t bdaddr;
|
||||
__u8 name_known;
|
||||
struct mgmt_addr_info addr;
|
||||
__u8 name_known;
|
||||
} __packed;
|
||||
#define MGMT_CONFIRM_NAME_SIZE (MGMT_ADDR_INFO_SIZE + 1)
|
||||
struct mgmt_rp_confirm_name {
|
||||
bdaddr_t bdaddr;
|
||||
__u8 status;
|
||||
struct mgmt_addr_info addr;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OP_BLOCK_DEVICE 0x0024
|
||||
#define MGMT_OP_BLOCK_DEVICE 0x0026
|
||||
struct mgmt_cp_block_device {
|
||||
bdaddr_t bdaddr;
|
||||
struct mgmt_addr_info addr;
|
||||
} __packed;
|
||||
#define MGMT_BLOCK_DEVICE_SIZE MGMT_ADDR_INFO_SIZE
|
||||
|
||||
#define MGMT_OP_UNBLOCK_DEVICE 0x0025
|
||||
#define MGMT_OP_UNBLOCK_DEVICE 0x0027
|
||||
struct mgmt_cp_unblock_device {
|
||||
bdaddr_t bdaddr;
|
||||
struct mgmt_addr_info addr;
|
||||
} __packed;
|
||||
#define MGMT_UNBLOCK_DEVICE_SIZE MGMT_ADDR_INFO_SIZE
|
||||
|
||||
#define MGMT_EV_CMD_COMPLETE 0x0001
|
||||
struct mgmt_ev_cmd_complete {
|
||||
__le16 opcode;
|
||||
__u8 data[0];
|
||||
__le16 opcode;
|
||||
__u8 status;
|
||||
__u8 data[0];
|
||||
} __packed;
|
||||
|
||||
#define MGMT_EV_CMD_STATUS 0x0002
|
||||
struct mgmt_ev_cmd_status {
|
||||
__u8 status;
|
||||
__le16 opcode;
|
||||
__le16 opcode;
|
||||
__u8 status;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_EV_CONTROLLER_ERROR 0x0003
|
||||
struct mgmt_ev_controller_error {
|
||||
__u8 error_code;
|
||||
__u8 error_code;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_EV_INDEX_ADDED 0x0004
|
||||
@ -313,78 +367,96 @@ struct mgmt_ev_controller_error {
|
||||
|
||||
#define MGMT_EV_CLASS_OF_DEV_CHANGED 0x0007
|
||||
struct mgmt_ev_class_of_dev_changed {
|
||||
__u8 dev_class[3];
|
||||
__u8 dev_class[3];
|
||||
};
|
||||
|
||||
#define MGMT_EV_LOCAL_NAME_CHANGED 0x0008
|
||||
struct mgmt_ev_local_name_changed {
|
||||
__u8 name[MGMT_MAX_NAME_LENGTH];
|
||||
__u8 short_name[MGMT_MAX_SHORT_NAME_LENGTH];
|
||||
__u8 name[MGMT_MAX_NAME_LENGTH];
|
||||
__u8 short_name[MGMT_MAX_SHORT_NAME_LENGTH];
|
||||
} __packed;
|
||||
|
||||
#define MGMT_EV_NEW_LINK_KEY 0x0009
|
||||
struct mgmt_ev_new_link_key {
|
||||
__u8 store_hint;
|
||||
__u8 store_hint;
|
||||
struct mgmt_link_key_info key;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_EV_CONNECTED 0x000A
|
||||
#define MGMT_EV_NEW_LONG_TERM_KEY 0x000A
|
||||
struct mgmt_ev_new_long_term_key {
|
||||
__u8 store_hint;
|
||||
struct mgmt_ltk_info key;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_EV_DISCONNECTED 0x000B
|
||||
#define MGMT_EV_DEVICE_CONNECTED 0x000B
|
||||
struct mgmt_ev_device_connected {
|
||||
struct mgmt_addr_info addr;
|
||||
__le32 flags;
|
||||
__le16 eir_len;
|
||||
__u8 eir[0];
|
||||
} __packed;
|
||||
|
||||
#define MGMT_EV_CONNECT_FAILED 0x000C
|
||||
#define MGMT_EV_DEVICE_DISCONNECTED 0x000C
|
||||
|
||||
#define MGMT_EV_CONNECT_FAILED 0x000D
|
||||
struct mgmt_ev_connect_failed {
|
||||
struct mgmt_addr_info addr;
|
||||
__u8 status;
|
||||
__u8 status;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_EV_PIN_CODE_REQUEST 0x000D
|
||||
#define MGMT_EV_PIN_CODE_REQUEST 0x000E
|
||||
struct mgmt_ev_pin_code_request {
|
||||
bdaddr_t bdaddr;
|
||||
__u8 secure;
|
||||
struct mgmt_addr_info addr;
|
||||
__u8 secure;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_EV_USER_CONFIRM_REQUEST 0x000E
|
||||
#define MGMT_EV_USER_CONFIRM_REQUEST 0x000F
|
||||
struct mgmt_ev_user_confirm_request {
|
||||
bdaddr_t bdaddr;
|
||||
__u8 confirm_hint;
|
||||
__le32 value;
|
||||
struct mgmt_addr_info addr;
|
||||
__u8 confirm_hint;
|
||||
__le32 value;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_EV_USER_PASSKEY_REQUEST 0x000F
|
||||
#define MGMT_EV_USER_PASSKEY_REQUEST 0x0010
|
||||
struct mgmt_ev_user_passkey_request {
|
||||
bdaddr_t bdaddr;
|
||||
struct mgmt_addr_info addr;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_EV_AUTH_FAILED 0x0010
|
||||
#define MGMT_EV_AUTH_FAILED 0x0011
|
||||
struct mgmt_ev_auth_failed {
|
||||
bdaddr_t bdaddr;
|
||||
__u8 status;
|
||||
struct mgmt_addr_info addr;
|
||||
__u8 status;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_EV_DEVICE_FOUND 0x0011
|
||||
#define MGMT_DEV_FOUND_CONFIRM_NAME 0x01
|
||||
#define MGMT_DEV_FOUND_LEGACY_PAIRING 0x02
|
||||
|
||||
#define MGMT_EV_DEVICE_FOUND 0x0012
|
||||
struct mgmt_ev_device_found {
|
||||
struct mgmt_addr_info addr;
|
||||
__u8 dev_class[3];
|
||||
__s8 rssi;
|
||||
__u8 confirm_name;
|
||||
__u8 eir[HCI_MAX_EIR_LENGTH];
|
||||
} __packed;
|
||||
|
||||
#define MGMT_EV_REMOTE_NAME 0x0012
|
||||
struct mgmt_ev_remote_name {
|
||||
bdaddr_t bdaddr;
|
||||
__u8 name[MGMT_MAX_NAME_LENGTH];
|
||||
__s8 rssi;
|
||||
__u8 flags[4];
|
||||
__le16 eir_len;
|
||||
__u8 eir[0];
|
||||
} __packed;
|
||||
|
||||
#define MGMT_EV_DISCOVERING 0x0013
|
||||
struct mgmt_ev_discovering {
|
||||
__u8 type;
|
||||
__u8 discovering;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_EV_DEVICE_BLOCKED 0x0014
|
||||
struct mgmt_ev_device_blocked {
|
||||
bdaddr_t bdaddr;
|
||||
struct mgmt_addr_info addr;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_EV_DEVICE_UNBLOCKED 0x0015
|
||||
struct mgmt_ev_device_unblocked {
|
||||
bdaddr_t bdaddr;
|
||||
struct mgmt_addr_info addr;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_EV_DEVICE_UNPAIRED 0x0016
|
||||
struct mgmt_ev_device_unpaired {
|
||||
struct mgmt_addr_info addr;
|
||||
} __packed;
|
||||
|
@ -127,7 +127,7 @@ struct smp_chan {
|
||||
u8 rrnd[16]; /* SMP Pairing Random (remote) */
|
||||
u8 pcnf[16]; /* SMP Pairing Confirm */
|
||||
u8 tk[16]; /* SMP Temporary Key */
|
||||
u8 smp_key_size;
|
||||
u8 enc_key_size;
|
||||
unsigned long smp_flags;
|
||||
struct crypto_blkcipher *tfm;
|
||||
struct work_struct confirm;
|
||||
|
@ -29,7 +29,6 @@ menuconfig BT
|
||||
BNEP Module (Bluetooth Network Encapsulation Protocol)
|
||||
CMTP Module (CAPI Message Transport Protocol)
|
||||
HIDP Module (Human Interface Device Protocol)
|
||||
SMP Module (Security Manager Protocol)
|
||||
|
||||
Say Y here to compile Bluetooth support into the kernel or say M to
|
||||
compile it as module (bluetooth).
|
||||
|
@ -143,10 +143,10 @@ static int bnep_sock_compat_ioctl(struct socket *sock, unsigned int cmd, unsigne
|
||||
{
|
||||
if (cmd == BNEPGETCONNLIST) {
|
||||
struct bnep_connlist_req cl;
|
||||
uint32_t uci;
|
||||
u32 uci;
|
||||
int err;
|
||||
|
||||
if (get_user(cl.cnum, (uint32_t __user *) arg) ||
|
||||
if (get_user(cl.cnum, (u32 __user *) arg) ||
|
||||
get_user(uci, (u32 __user *) (arg + 4)))
|
||||
return -EFAULT;
|
||||
|
||||
@ -157,7 +157,7 @@ static int bnep_sock_compat_ioctl(struct socket *sock, unsigned int cmd, unsigne
|
||||
|
||||
err = bnep_get_connlist(&cl);
|
||||
|
||||
if (!err && put_user(cl.cnum, (uint32_t __user *) arg))
|
||||
if (!err && put_user(cl.cnum, (u32 __user *) arg))
|
||||
err = -EFAULT;
|
||||
|
||||
return err;
|
||||
|
@ -137,10 +137,10 @@ static int cmtp_sock_compat_ioctl(struct socket *sock, unsigned int cmd, unsigne
|
||||
{
|
||||
if (cmd == CMTPGETCONNLIST) {
|
||||
struct cmtp_connlist_req cl;
|
||||
uint32_t uci;
|
||||
u32 uci;
|
||||
int err;
|
||||
|
||||
if (get_user(cl.cnum, (uint32_t __user *) arg) ||
|
||||
if (get_user(cl.cnum, (u32 __user *) arg) ||
|
||||
get_user(uci, (u32 __user *) (arg + 4)))
|
||||
return -EFAULT;
|
||||
|
||||
@ -151,7 +151,7 @@ static int cmtp_sock_compat_ioctl(struct socket *sock, unsigned int cmd, unsigne
|
||||
|
||||
err = cmtp_get_connlist(&cl);
|
||||
|
||||
if (!err && put_user(cl.cnum, (uint32_t __user *) arg))
|
||||
if (!err && put_user(cl.cnum, (u32 __user *) arg))
|
||||
err = -EFAULT;
|
||||
|
||||
return err;
|
||||
|
@ -35,7 +35,6 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/notifier.h>
|
||||
#include <net/sock.h>
|
||||
|
||||
#include <asm/system.h>
|
||||
@ -51,7 +50,7 @@ static void hci_le_connect(struct hci_conn *conn)
|
||||
struct hci_cp_le_create_conn cp;
|
||||
|
||||
conn->state = BT_CONNECT;
|
||||
conn->out = 1;
|
||||
conn->out = true;
|
||||
conn->link_mode |= HCI_LM_MASTER;
|
||||
conn->sec_level = BT_SECURITY_LOW;
|
||||
|
||||
@ -80,10 +79,10 @@ void hci_acl_connect(struct hci_conn *conn)
|
||||
struct inquiry_entry *ie;
|
||||
struct hci_cp_create_conn cp;
|
||||
|
||||
BT_DBG("%p", conn);
|
||||
BT_DBG("hcon %p", conn);
|
||||
|
||||
conn->state = BT_CONNECT;
|
||||
conn->out = 1;
|
||||
conn->out = true;
|
||||
|
||||
conn->link_mode = HCI_LM_MASTER;
|
||||
|
||||
@ -105,7 +104,8 @@ void hci_acl_connect(struct hci_conn *conn)
|
||||
}
|
||||
|
||||
memcpy(conn->dev_class, ie->data.dev_class, 3);
|
||||
conn->ssp_mode = ie->data.ssp_mode;
|
||||
if (ie->data.ssp_mode > 0)
|
||||
set_bit(HCI_CONN_SSP_ENABLED, &conn->flags);
|
||||
}
|
||||
|
||||
cp.pkt_type = cpu_to_le16(conn->pkt_type);
|
||||
@ -151,7 +151,7 @@ void hci_add_sco(struct hci_conn *conn, __u16 handle)
|
||||
BT_DBG("%p", conn);
|
||||
|
||||
conn->state = BT_CONNECT;
|
||||
conn->out = 1;
|
||||
conn->out = true;
|
||||
|
||||
conn->attempt++;
|
||||
|
||||
@ -169,7 +169,7 @@ void hci_setup_sync(struct hci_conn *conn, __u16 handle)
|
||||
BT_DBG("%p", conn);
|
||||
|
||||
conn->state = BT_CONNECT;
|
||||
conn->out = 1;
|
||||
conn->out = true;
|
||||
|
||||
conn->attempt++;
|
||||
|
||||
@ -279,16 +279,13 @@ static void hci_conn_timeout(struct work_struct *work)
|
||||
{
|
||||
struct hci_conn *conn = container_of(work, struct hci_conn,
|
||||
disc_work.work);
|
||||
struct hci_dev *hdev = conn->hdev;
|
||||
__u8 reason;
|
||||
|
||||
BT_DBG("conn %p state %d", conn, conn->state);
|
||||
BT_DBG("conn %p state %s", conn, state_to_string(conn->state));
|
||||
|
||||
if (atomic_read(&conn->refcnt))
|
||||
return;
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
|
||||
switch (conn->state) {
|
||||
case BT_CONNECT:
|
||||
case BT_CONNECT2:
|
||||
@ -308,8 +305,6 @@ static void hci_conn_timeout(struct work_struct *work)
|
||||
conn->state = BT_CLOSED;
|
||||
break;
|
||||
}
|
||||
|
||||
hci_dev_unlock(hdev);
|
||||
}
|
||||
|
||||
/* Enter sniff mode */
|
||||
@ -337,7 +332,7 @@ static void hci_conn_enter_sniff_mode(struct hci_conn *conn)
|
||||
hci_send_cmd(hdev, HCI_OP_SNIFF_SUBRATE, sizeof(cp), &cp);
|
||||
}
|
||||
|
||||
if (!test_and_set_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->pend)) {
|
||||
if (!test_and_set_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->flags)) {
|
||||
struct hci_cp_sniff_mode cp;
|
||||
cp.handle = cpu_to_le16(conn->handle);
|
||||
cp.max_interval = cpu_to_le16(hdev->sniff_max_interval);
|
||||
@ -372,7 +367,7 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst)
|
||||
|
||||
BT_DBG("%s dst %s", hdev->name, batostr(dst));
|
||||
|
||||
conn = kzalloc(sizeof(struct hci_conn), GFP_ATOMIC);
|
||||
conn = kzalloc(sizeof(struct hci_conn), GFP_KERNEL);
|
||||
if (!conn)
|
||||
return NULL;
|
||||
|
||||
@ -386,7 +381,7 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst)
|
||||
conn->remote_auth = 0xff;
|
||||
conn->key_type = 0xff;
|
||||
|
||||
conn->power_save = 1;
|
||||
set_bit(HCI_CONN_POWER_SAVE, &conn->flags);
|
||||
conn->disc_timeout = HCI_DISCONN_TIMEOUT;
|
||||
|
||||
switch (type) {
|
||||
@ -407,7 +402,7 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst)
|
||||
|
||||
skb_queue_head_init(&conn->data_q);
|
||||
|
||||
INIT_LIST_HEAD(&conn->chan_list);;
|
||||
INIT_LIST_HEAD(&conn->chan_list);
|
||||
|
||||
INIT_DELAYED_WORK(&conn->disc_work, hci_conn_timeout);
|
||||
setup_timer(&conn->idle_timer, hci_conn_idle, (unsigned long)conn);
|
||||
@ -555,7 +550,7 @@ struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, __u8
|
||||
if (!acl) {
|
||||
acl = hci_conn_add(hdev, ACL_LINK, dst);
|
||||
if (!acl)
|
||||
return NULL;
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
hci_conn_hold(acl);
|
||||
@ -575,7 +570,7 @@ struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, __u8
|
||||
sco = hci_conn_add(hdev, type, dst);
|
||||
if (!sco) {
|
||||
hci_conn_put(acl);
|
||||
return NULL;
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
}
|
||||
|
||||
@ -586,12 +581,12 @@ struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, __u8
|
||||
|
||||
if (acl->state == BT_CONNECTED &&
|
||||
(sco->state == BT_OPEN || sco->state == BT_CLOSED)) {
|
||||
acl->power_save = 1;
|
||||
set_bit(HCI_CONN_POWER_SAVE, &acl->flags);
|
||||
hci_conn_enter_active_mode(acl, BT_POWER_FORCE_ACTIVE_ON);
|
||||
|
||||
if (test_bit(HCI_CONN_MODE_CHANGE_PEND, &acl->pend)) {
|
||||
if (test_bit(HCI_CONN_MODE_CHANGE_PEND, &acl->flags)) {
|
||||
/* defer SCO setup until mode change completed */
|
||||
set_bit(HCI_CONN_SCO_SETUP_PEND, &acl->pend);
|
||||
set_bit(HCI_CONN_SCO_SETUP_PEND, &acl->flags);
|
||||
return sco;
|
||||
}
|
||||
|
||||
@ -607,8 +602,7 @@ int hci_conn_check_link_mode(struct hci_conn *conn)
|
||||
{
|
||||
BT_DBG("conn %p", conn);
|
||||
|
||||
if (conn->ssp_mode > 0 && conn->hdev->ssp_mode > 0 &&
|
||||
!(conn->link_mode & HCI_LM_ENCRYPT))
|
||||
if (hci_conn_ssp_enabled(conn) && !(conn->link_mode & HCI_LM_ENCRYPT))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
@ -633,17 +627,17 @@ static int hci_conn_auth(struct hci_conn *conn, __u8 sec_level, __u8 auth_type)
|
||||
|
||||
conn->auth_type = auth_type;
|
||||
|
||||
if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->pend)) {
|
||||
if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->flags)) {
|
||||
struct hci_cp_auth_requested cp;
|
||||
|
||||
/* encrypt must be pending if auth is also pending */
|
||||
set_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend);
|
||||
set_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags);
|
||||
|
||||
cp.handle = cpu_to_le16(conn->handle);
|
||||
hci_send_cmd(conn->hdev, HCI_OP_AUTH_REQUESTED,
|
||||
sizeof(cp), &cp);
|
||||
if (conn->key_type != 0xff)
|
||||
set_bit(HCI_CONN_REAUTH_PEND, &conn->pend);
|
||||
set_bit(HCI_CONN_REAUTH_PEND, &conn->flags);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -654,7 +648,7 @@ static void hci_conn_encrypt(struct hci_conn *conn)
|
||||
{
|
||||
BT_DBG("conn %p", conn);
|
||||
|
||||
if (!test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend)) {
|
||||
if (!test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags)) {
|
||||
struct hci_cp_set_conn_encrypt cp;
|
||||
cp.handle = cpu_to_le16(conn->handle);
|
||||
cp.encrypt = 0x01;
|
||||
@ -674,8 +668,7 @@ int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type)
|
||||
|
||||
/* For non 2.1 devices and low security level we don't need the link
|
||||
key. */
|
||||
if (sec_level == BT_SECURITY_LOW &&
|
||||
(!conn->ssp_mode || !conn->hdev->ssp_mode))
|
||||
if (sec_level == BT_SECURITY_LOW && !hci_conn_ssp_enabled(conn))
|
||||
return 1;
|
||||
|
||||
/* For other security levels we need the link key. */
|
||||
@ -704,7 +697,7 @@ int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type)
|
||||
goto encrypt;
|
||||
|
||||
auth:
|
||||
if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend))
|
||||
if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags))
|
||||
return 0;
|
||||
|
||||
if (!hci_conn_auth(conn, sec_level, auth_type))
|
||||
@ -739,7 +732,7 @@ int hci_conn_change_link_key(struct hci_conn *conn)
|
||||
{
|
||||
BT_DBG("conn %p", conn);
|
||||
|
||||
if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->pend)) {
|
||||
if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->flags)) {
|
||||
struct hci_cp_change_conn_link_key cp;
|
||||
cp.handle = cpu_to_le16(conn->handle);
|
||||
hci_send_cmd(conn->hdev, HCI_OP_CHANGE_CONN_LINK_KEY,
|
||||
@ -758,7 +751,7 @@ int hci_conn_switch_role(struct hci_conn *conn, __u8 role)
|
||||
if (!role && conn->link_mode & HCI_LM_MASTER)
|
||||
return 1;
|
||||
|
||||
if (!test_and_set_bit(HCI_CONN_RSWITCH_PEND, &conn->pend)) {
|
||||
if (!test_and_set_bit(HCI_CONN_RSWITCH_PEND, &conn->flags)) {
|
||||
struct hci_cp_switch_role cp;
|
||||
bacpy(&cp.bdaddr, &conn->dst);
|
||||
cp.role = role;
|
||||
@ -782,10 +775,10 @@ void hci_conn_enter_active_mode(struct hci_conn *conn, __u8 force_active)
|
||||
if (conn->mode != HCI_CM_SNIFF)
|
||||
goto timer;
|
||||
|
||||
if (!conn->power_save && !force_active)
|
||||
if (!test_bit(HCI_CONN_POWER_SAVE, &conn->flags) && !force_active)
|
||||
goto timer;
|
||||
|
||||
if (!test_and_set_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->pend)) {
|
||||
if (!test_and_set_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->flags)) {
|
||||
struct hci_cp_exit_sniff_mode cp;
|
||||
cp.handle = cpu_to_le16(conn->handle);
|
||||
hci_send_cmd(hdev, HCI_OP_EXIT_SNIFF_MODE, sizeof(cp), &cp);
|
||||
@ -801,11 +794,11 @@ timer:
|
||||
void hci_conn_hash_flush(struct hci_dev *hdev)
|
||||
{
|
||||
struct hci_conn_hash *h = &hdev->conn_hash;
|
||||
struct hci_conn *c;
|
||||
struct hci_conn *c, *n;
|
||||
|
||||
BT_DBG("hdev %s", hdev->name);
|
||||
|
||||
list_for_each_entry_rcu(c, &h->list, list) {
|
||||
list_for_each_entry_safe(c, n, &h->list, list) {
|
||||
c->state = BT_CLOSED;
|
||||
|
||||
hci_proto_disconn_cfm(c, HCI_ERROR_LOCAL_HOST_TERM);
|
||||
@ -950,7 +943,7 @@ struct hci_chan *hci_chan_create(struct hci_conn *conn)
|
||||
|
||||
BT_DBG("%s conn %p", hdev->name, conn);
|
||||
|
||||
chan = kzalloc(sizeof(struct hci_chan), GFP_ATOMIC);
|
||||
chan = kzalloc(sizeof(struct hci_chan), GFP_KERNEL);
|
||||
if (!chan)
|
||||
return NULL;
|
||||
|
||||
@ -981,10 +974,10 @@ int hci_chan_del(struct hci_chan *chan)
|
||||
|
||||
void hci_chan_list_flush(struct hci_conn *conn)
|
||||
{
|
||||
struct hci_chan *chan;
|
||||
struct hci_chan *chan, *n;
|
||||
|
||||
BT_DBG("conn %p", conn);
|
||||
|
||||
list_for_each_entry_rcu(chan, &conn->chan_list, list)
|
||||
list_for_each_entry_safe(chan, n, &conn->chan_list, list)
|
||||
hci_chan_del(chan);
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -48,8 +48,9 @@
|
||||
|
||||
#include <net/bluetooth/bluetooth.h>
|
||||
#include <net/bluetooth/hci_core.h>
|
||||
#include <net/bluetooth/hci_mon.h>
|
||||
|
||||
static bool enable_mgmt;
|
||||
static atomic_t monitor_promisc = ATOMIC_INIT(0);
|
||||
|
||||
/* ----- HCI socket interface ----- */
|
||||
|
||||
@ -85,22 +86,20 @@ static struct bt_sock_list hci_sk_list = {
|
||||
};
|
||||
|
||||
/* Send frame to RAW socket */
|
||||
void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb,
|
||||
struct sock *skip_sk)
|
||||
void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
struct sock *sk;
|
||||
struct hlist_node *node;
|
||||
struct sk_buff *skb_copy = NULL;
|
||||
|
||||
BT_DBG("hdev %p len %d", hdev, skb->len);
|
||||
|
||||
read_lock(&hci_sk_list.lock);
|
||||
|
||||
sk_for_each(sk, node, &hci_sk_list.head) {
|
||||
struct hci_filter *flt;
|
||||
struct sk_buff *nskb;
|
||||
|
||||
if (sk == skip_sk)
|
||||
continue;
|
||||
|
||||
if (sk->sk_state != BT_BOUND || hci_pi(sk)->hdev != hdev)
|
||||
continue;
|
||||
|
||||
@ -108,12 +107,9 @@ void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb,
|
||||
if (skb->sk == sk)
|
||||
continue;
|
||||
|
||||
if (bt_cb(skb)->channel != hci_pi(sk)->channel)
|
||||
if (hci_pi(sk)->channel != HCI_CHANNEL_RAW)
|
||||
continue;
|
||||
|
||||
if (bt_cb(skb)->channel == HCI_CHANNEL_CONTROL)
|
||||
goto clone;
|
||||
|
||||
/* Apply filter */
|
||||
flt = &hci_pi(sk)->filter;
|
||||
|
||||
@ -137,19 +133,301 @@ void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb,
|
||||
continue;
|
||||
}
|
||||
|
||||
clone:
|
||||
nskb = skb_clone(skb, GFP_ATOMIC);
|
||||
if (!skb_copy) {
|
||||
/* Create a private copy with headroom */
|
||||
skb_copy = __pskb_copy(skb, 1, GFP_ATOMIC);
|
||||
if (!skb_copy)
|
||||
continue;
|
||||
|
||||
/* Put type byte before the data */
|
||||
memcpy(skb_push(skb_copy, 1), &bt_cb(skb)->pkt_type, 1);
|
||||
}
|
||||
|
||||
nskb = skb_clone(skb_copy, GFP_ATOMIC);
|
||||
if (!nskb)
|
||||
continue;
|
||||
|
||||
/* Put type byte before the data */
|
||||
if (bt_cb(skb)->channel == HCI_CHANNEL_RAW)
|
||||
memcpy(skb_push(nskb, 1), &bt_cb(nskb)->pkt_type, 1);
|
||||
|
||||
if (sock_queue_rcv_skb(sk, nskb))
|
||||
kfree_skb(nskb);
|
||||
}
|
||||
|
||||
read_unlock(&hci_sk_list.lock);
|
||||
|
||||
kfree_skb(skb_copy);
|
||||
}
|
||||
|
||||
/* Send frame to control socket */
|
||||
void hci_send_to_control(struct sk_buff *skb, struct sock *skip_sk)
|
||||
{
|
||||
struct sock *sk;
|
||||
struct hlist_node *node;
|
||||
|
||||
BT_DBG("len %d", skb->len);
|
||||
|
||||
read_lock(&hci_sk_list.lock);
|
||||
|
||||
sk_for_each(sk, node, &hci_sk_list.head) {
|
||||
struct sk_buff *nskb;
|
||||
|
||||
/* Skip the original socket */
|
||||
if (sk == skip_sk)
|
||||
continue;
|
||||
|
||||
if (sk->sk_state != BT_BOUND)
|
||||
continue;
|
||||
|
||||
if (hci_pi(sk)->channel != HCI_CHANNEL_CONTROL)
|
||||
continue;
|
||||
|
||||
nskb = skb_clone(skb, GFP_ATOMIC);
|
||||
if (!nskb)
|
||||
continue;
|
||||
|
||||
if (sock_queue_rcv_skb(sk, nskb))
|
||||
kfree_skb(nskb);
|
||||
}
|
||||
|
||||
read_unlock(&hci_sk_list.lock);
|
||||
}
|
||||
|
||||
/* Send frame to monitor socket */
|
||||
void hci_send_to_monitor(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
struct sock *sk;
|
||||
struct hlist_node *node;
|
||||
struct sk_buff *skb_copy = NULL;
|
||||
__le16 opcode;
|
||||
|
||||
if (!atomic_read(&monitor_promisc))
|
||||
return;
|
||||
|
||||
BT_DBG("hdev %p len %d", hdev, skb->len);
|
||||
|
||||
switch (bt_cb(skb)->pkt_type) {
|
||||
case HCI_COMMAND_PKT:
|
||||
opcode = __constant_cpu_to_le16(HCI_MON_COMMAND_PKT);
|
||||
break;
|
||||
case HCI_EVENT_PKT:
|
||||
opcode = __constant_cpu_to_le16(HCI_MON_EVENT_PKT);
|
||||
break;
|
||||
case HCI_ACLDATA_PKT:
|
||||
if (bt_cb(skb)->incoming)
|
||||
opcode = __constant_cpu_to_le16(HCI_MON_ACL_RX_PKT);
|
||||
else
|
||||
opcode = __constant_cpu_to_le16(HCI_MON_ACL_TX_PKT);
|
||||
break;
|
||||
case HCI_SCODATA_PKT:
|
||||
if (bt_cb(skb)->incoming)
|
||||
opcode = __constant_cpu_to_le16(HCI_MON_SCO_RX_PKT);
|
||||
else
|
||||
opcode = __constant_cpu_to_le16(HCI_MON_SCO_TX_PKT);
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
read_lock(&hci_sk_list.lock);
|
||||
|
||||
sk_for_each(sk, node, &hci_sk_list.head) {
|
||||
struct sk_buff *nskb;
|
||||
|
||||
if (sk->sk_state != BT_BOUND)
|
||||
continue;
|
||||
|
||||
if (hci_pi(sk)->channel != HCI_CHANNEL_MONITOR)
|
||||
continue;
|
||||
|
||||
if (!skb_copy) {
|
||||
struct hci_mon_hdr *hdr;
|
||||
|
||||
/* Create a private copy with headroom */
|
||||
skb_copy = __pskb_copy(skb, HCI_MON_HDR_SIZE, GFP_ATOMIC);
|
||||
if (!skb_copy)
|
||||
continue;
|
||||
|
||||
/* Put header before the data */
|
||||
hdr = (void *) skb_push(skb_copy, HCI_MON_HDR_SIZE);
|
||||
hdr->opcode = opcode;
|
||||
hdr->index = cpu_to_le16(hdev->id);
|
||||
hdr->len = cpu_to_le16(skb->len);
|
||||
}
|
||||
|
||||
nskb = skb_clone(skb_copy, GFP_ATOMIC);
|
||||
if (!nskb)
|
||||
continue;
|
||||
|
||||
if (sock_queue_rcv_skb(sk, nskb))
|
||||
kfree_skb(nskb);
|
||||
}
|
||||
|
||||
read_unlock(&hci_sk_list.lock);
|
||||
|
||||
kfree_skb(skb_copy);
|
||||
}
|
||||
|
||||
static void send_monitor_event(struct sk_buff *skb)
|
||||
{
|
||||
struct sock *sk;
|
||||
struct hlist_node *node;
|
||||
|
||||
BT_DBG("len %d", skb->len);
|
||||
|
||||
read_lock(&hci_sk_list.lock);
|
||||
|
||||
sk_for_each(sk, node, &hci_sk_list.head) {
|
||||
struct sk_buff *nskb;
|
||||
|
||||
if (sk->sk_state != BT_BOUND)
|
||||
continue;
|
||||
|
||||
if (hci_pi(sk)->channel != HCI_CHANNEL_MONITOR)
|
||||
continue;
|
||||
|
||||
nskb = skb_clone(skb, GFP_ATOMIC);
|
||||
if (!nskb)
|
||||
continue;
|
||||
|
||||
if (sock_queue_rcv_skb(sk, nskb))
|
||||
kfree_skb(nskb);
|
||||
}
|
||||
|
||||
read_unlock(&hci_sk_list.lock);
|
||||
}
|
||||
|
||||
static struct sk_buff *create_monitor_event(struct hci_dev *hdev, int event)
|
||||
{
|
||||
struct hci_mon_hdr *hdr;
|
||||
struct hci_mon_new_index *ni;
|
||||
struct sk_buff *skb;
|
||||
__le16 opcode;
|
||||
|
||||
switch (event) {
|
||||
case HCI_DEV_REG:
|
||||
skb = bt_skb_alloc(HCI_MON_NEW_INDEX_SIZE, GFP_ATOMIC);
|
||||
if (!skb)
|
||||
return NULL;
|
||||
|
||||
ni = (void *) skb_put(skb, HCI_MON_NEW_INDEX_SIZE);
|
||||
ni->type = hdev->dev_type;
|
||||
ni->bus = hdev->bus;
|
||||
bacpy(&ni->bdaddr, &hdev->bdaddr);
|
||||
memcpy(ni->name, hdev->name, 8);
|
||||
|
||||
opcode = __constant_cpu_to_le16(HCI_MON_NEW_INDEX);
|
||||
break;
|
||||
|
||||
case HCI_DEV_UNREG:
|
||||
skb = bt_skb_alloc(0, GFP_ATOMIC);
|
||||
if (!skb)
|
||||
return NULL;
|
||||
|
||||
opcode = __constant_cpu_to_le16(HCI_MON_DEL_INDEX);
|
||||
break;
|
||||
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
__net_timestamp(skb);
|
||||
|
||||
hdr = (void *) skb_push(skb, HCI_MON_HDR_SIZE);
|
||||
hdr->opcode = opcode;
|
||||
hdr->index = cpu_to_le16(hdev->id);
|
||||
hdr->len = cpu_to_le16(skb->len - HCI_MON_HDR_SIZE);
|
||||
|
||||
return skb;
|
||||
}
|
||||
|
||||
static void send_monitor_replay(struct sock *sk)
|
||||
{
|
||||
struct hci_dev *hdev;
|
||||
|
||||
read_lock(&hci_dev_list_lock);
|
||||
|
||||
list_for_each_entry(hdev, &hci_dev_list, list) {
|
||||
struct sk_buff *skb;
|
||||
|
||||
skb = create_monitor_event(hdev, HCI_DEV_REG);
|
||||
if (!skb)
|
||||
continue;
|
||||
|
||||
if (sock_queue_rcv_skb(sk, skb))
|
||||
kfree_skb(skb);
|
||||
}
|
||||
|
||||
read_unlock(&hci_dev_list_lock);
|
||||
}
|
||||
|
||||
/* Generate internal stack event */
|
||||
static void hci_si_event(struct hci_dev *hdev, int type, int dlen, void *data)
|
||||
{
|
||||
struct hci_event_hdr *hdr;
|
||||
struct hci_ev_stack_internal *ev;
|
||||
struct sk_buff *skb;
|
||||
|
||||
skb = bt_skb_alloc(HCI_EVENT_HDR_SIZE + sizeof(*ev) + dlen, GFP_ATOMIC);
|
||||
if (!skb)
|
||||
return;
|
||||
|
||||
hdr = (void *) skb_put(skb, HCI_EVENT_HDR_SIZE);
|
||||
hdr->evt = HCI_EV_STACK_INTERNAL;
|
||||
hdr->plen = sizeof(*ev) + dlen;
|
||||
|
||||
ev = (void *) skb_put(skb, sizeof(*ev) + dlen);
|
||||
ev->type = type;
|
||||
memcpy(ev->data, data, dlen);
|
||||
|
||||
bt_cb(skb)->incoming = 1;
|
||||
__net_timestamp(skb);
|
||||
|
||||
bt_cb(skb)->pkt_type = HCI_EVENT_PKT;
|
||||
skb->dev = (void *) hdev;
|
||||
hci_send_to_sock(hdev, skb);
|
||||
kfree_skb(skb);
|
||||
}
|
||||
|
||||
void hci_sock_dev_event(struct hci_dev *hdev, int event)
|
||||
{
|
||||
struct hci_ev_si_device ev;
|
||||
|
||||
BT_DBG("hdev %s event %d", hdev->name, event);
|
||||
|
||||
/* Send event to monitor */
|
||||
if (atomic_read(&monitor_promisc)) {
|
||||
struct sk_buff *skb;
|
||||
|
||||
skb = create_monitor_event(hdev, event);
|
||||
if (skb) {
|
||||
send_monitor_event(skb);
|
||||
kfree_skb(skb);
|
||||
}
|
||||
}
|
||||
|
||||
/* Send event to sockets */
|
||||
ev.event = event;
|
||||
ev.dev_id = hdev->id;
|
||||
hci_si_event(NULL, HCI_EV_SI_DEVICE, sizeof(ev), &ev);
|
||||
|
||||
if (event == HCI_DEV_UNREG) {
|
||||
struct sock *sk;
|
||||
struct hlist_node *node;
|
||||
|
||||
/* Detach sockets from device */
|
||||
read_lock(&hci_sk_list.lock);
|
||||
sk_for_each(sk, node, &hci_sk_list.head) {
|
||||
bh_lock_sock_nested(sk);
|
||||
if (hci_pi(sk)->hdev == hdev) {
|
||||
hci_pi(sk)->hdev = NULL;
|
||||
sk->sk_err = EPIPE;
|
||||
sk->sk_state = BT_OPEN;
|
||||
sk->sk_state_change(sk);
|
||||
|
||||
hci_dev_put(hdev);
|
||||
}
|
||||
bh_unlock_sock(sk);
|
||||
}
|
||||
read_unlock(&hci_sk_list.lock);
|
||||
}
|
||||
}
|
||||
|
||||
static int hci_sock_release(struct socket *sock)
|
||||
@ -164,6 +442,9 @@ static int hci_sock_release(struct socket *sock)
|
||||
|
||||
hdev = hci_pi(sk)->hdev;
|
||||
|
||||
if (hci_pi(sk)->channel == HCI_CHANNEL_MONITOR)
|
||||
atomic_dec(&monitor_promisc);
|
||||
|
||||
bt_sock_unlink(&hci_sk_list, sk);
|
||||
|
||||
if (hdev) {
|
||||
@ -190,7 +471,7 @@ static int hci_sock_blacklist_add(struct hci_dev *hdev, void __user *arg)
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
|
||||
err = hci_blacklist_add(hdev, &bdaddr);
|
||||
err = hci_blacklist_add(hdev, &bdaddr, 0);
|
||||
|
||||
hci_dev_unlock(hdev);
|
||||
|
||||
@ -207,7 +488,7 @@ static int hci_sock_blacklist_del(struct hci_dev *hdev, void __user *arg)
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
|
||||
err = hci_blacklist_del(hdev, &bdaddr);
|
||||
err = hci_blacklist_del(hdev, &bdaddr, 0);
|
||||
|
||||
hci_dev_unlock(hdev);
|
||||
|
||||
@ -340,34 +621,69 @@ static int hci_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_le
|
||||
if (haddr.hci_family != AF_BLUETOOTH)
|
||||
return -EINVAL;
|
||||
|
||||
if (haddr.hci_channel > HCI_CHANNEL_CONTROL)
|
||||
return -EINVAL;
|
||||
|
||||
if (haddr.hci_channel == HCI_CHANNEL_CONTROL) {
|
||||
if (!enable_mgmt)
|
||||
return -EINVAL;
|
||||
set_bit(HCI_PI_MGMT_INIT, &hci_pi(sk)->flags);
|
||||
}
|
||||
|
||||
lock_sock(sk);
|
||||
|
||||
if (sk->sk_state == BT_BOUND || hci_pi(sk)->hdev) {
|
||||
if (sk->sk_state == BT_BOUND) {
|
||||
err = -EALREADY;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (haddr.hci_dev != HCI_DEV_NONE) {
|
||||
hdev = hci_dev_get(haddr.hci_dev);
|
||||
if (!hdev) {
|
||||
err = -ENODEV;
|
||||
switch (haddr.hci_channel) {
|
||||
case HCI_CHANNEL_RAW:
|
||||
if (hci_pi(sk)->hdev) {
|
||||
err = -EALREADY;
|
||||
goto done;
|
||||
}
|
||||
|
||||
atomic_inc(&hdev->promisc);
|
||||
if (haddr.hci_dev != HCI_DEV_NONE) {
|
||||
hdev = hci_dev_get(haddr.hci_dev);
|
||||
if (!hdev) {
|
||||
err = -ENODEV;
|
||||
goto done;
|
||||
}
|
||||
|
||||
atomic_inc(&hdev->promisc);
|
||||
}
|
||||
|
||||
hci_pi(sk)->hdev = hdev;
|
||||
break;
|
||||
|
||||
case HCI_CHANNEL_CONTROL:
|
||||
if (haddr.hci_dev != HCI_DEV_NONE) {
|
||||
err = -EINVAL;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (!capable(CAP_NET_ADMIN)) {
|
||||
err = -EPERM;
|
||||
goto done;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case HCI_CHANNEL_MONITOR:
|
||||
if (haddr.hci_dev != HCI_DEV_NONE) {
|
||||
err = -EINVAL;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (!capable(CAP_NET_RAW)) {
|
||||
err = -EPERM;
|
||||
goto done;
|
||||
}
|
||||
|
||||
send_monitor_replay(sk);
|
||||
|
||||
atomic_inc(&monitor_promisc);
|
||||
break;
|
||||
|
||||
default:
|
||||
err = -EINVAL;
|
||||
goto done;
|
||||
}
|
||||
|
||||
|
||||
hci_pi(sk)->channel = haddr.hci_channel;
|
||||
hci_pi(sk)->hdev = hdev;
|
||||
sk->sk_state = BT_BOUND;
|
||||
|
||||
done:
|
||||
@ -461,7 +777,15 @@ static int hci_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
|
||||
skb_reset_transport_header(skb);
|
||||
err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
|
||||
|
||||
hci_sock_cmsg(sk, msg, skb);
|
||||
switch (hci_pi(sk)->channel) {
|
||||
case HCI_CHANNEL_RAW:
|
||||
hci_sock_cmsg(sk, msg, skb);
|
||||
break;
|
||||
case HCI_CHANNEL_CONTROL:
|
||||
case HCI_CHANNEL_MONITOR:
|
||||
sock_recv_timestamp(msg, sk, skb);
|
||||
break;
|
||||
}
|
||||
|
||||
skb_free_datagram(sk, skb);
|
||||
|
||||
@ -495,6 +819,9 @@ static int hci_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
|
||||
case HCI_CHANNEL_CONTROL:
|
||||
err = mgmt_control(sk, msg, len);
|
||||
goto done;
|
||||
case HCI_CHANNEL_MONITOR:
|
||||
err = -EOPNOTSUPP;
|
||||
goto done;
|
||||
default:
|
||||
err = -EINVAL;
|
||||
goto done;
|
||||
@ -574,6 +901,11 @@ static int hci_sock_setsockopt(struct socket *sock, int level, int optname, char
|
||||
|
||||
lock_sock(sk);
|
||||
|
||||
if (hci_pi(sk)->channel != HCI_CHANNEL_RAW) {
|
||||
err = -EINVAL;
|
||||
goto done;
|
||||
}
|
||||
|
||||
switch (optname) {
|
||||
case HCI_DATA_DIR:
|
||||
if (get_user(opt, (int __user *)optval)) {
|
||||
@ -636,6 +968,7 @@ static int hci_sock_setsockopt(struct socket *sock, int level, int optname, char
|
||||
break;
|
||||
}
|
||||
|
||||
done:
|
||||
release_sock(sk);
|
||||
return err;
|
||||
}
|
||||
@ -644,11 +977,20 @@ static int hci_sock_getsockopt(struct socket *sock, int level, int optname, char
|
||||
{
|
||||
struct hci_ufilter uf;
|
||||
struct sock *sk = sock->sk;
|
||||
int len, opt;
|
||||
int len, opt, err = 0;
|
||||
|
||||
BT_DBG("sk %p, opt %d", sk, optname);
|
||||
|
||||
if (get_user(len, optlen))
|
||||
return -EFAULT;
|
||||
|
||||
lock_sock(sk);
|
||||
|
||||
if (hci_pi(sk)->channel != HCI_CHANNEL_RAW) {
|
||||
err = -EINVAL;
|
||||
goto done;
|
||||
}
|
||||
|
||||
switch (optname) {
|
||||
case HCI_DATA_DIR:
|
||||
if (hci_pi(sk)->cmsg_mask & HCI_CMSG_DIR)
|
||||
@ -657,7 +999,7 @@ static int hci_sock_getsockopt(struct socket *sock, int level, int optname, char
|
||||
opt = 0;
|
||||
|
||||
if (put_user(opt, optval))
|
||||
return -EFAULT;
|
||||
err = -EFAULT;
|
||||
break;
|
||||
|
||||
case HCI_TIME_STAMP:
|
||||
@ -667,7 +1009,7 @@ static int hci_sock_getsockopt(struct socket *sock, int level, int optname, char
|
||||
opt = 0;
|
||||
|
||||
if (put_user(opt, optval))
|
||||
return -EFAULT;
|
||||
err = -EFAULT;
|
||||
break;
|
||||
|
||||
case HCI_FILTER:
|
||||
@ -682,15 +1024,17 @@ static int hci_sock_getsockopt(struct socket *sock, int level, int optname, char
|
||||
|
||||
len = min_t(unsigned int, len, sizeof(uf));
|
||||
if (copy_to_user(optval, &uf, len))
|
||||
return -EFAULT;
|
||||
err = -EFAULT;
|
||||
break;
|
||||
|
||||
default:
|
||||
return -ENOPROTOOPT;
|
||||
err = -ENOPROTOOPT;
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
done:
|
||||
release_sock(sk);
|
||||
return err;
|
||||
}
|
||||
|
||||
static const struct proto_ops hci_sock_ops = {
|
||||
@ -748,52 +1092,12 @@ static int hci_sock_create(struct net *net, struct socket *sock, int protocol,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hci_sock_dev_event(struct notifier_block *this, unsigned long event, void *ptr)
|
||||
{
|
||||
struct hci_dev *hdev = (struct hci_dev *) ptr;
|
||||
struct hci_ev_si_device ev;
|
||||
|
||||
BT_DBG("hdev %s event %ld", hdev->name, event);
|
||||
|
||||
/* Send event to sockets */
|
||||
ev.event = event;
|
||||
ev.dev_id = hdev->id;
|
||||
hci_si_event(NULL, HCI_EV_SI_DEVICE, sizeof(ev), &ev);
|
||||
|
||||
if (event == HCI_DEV_UNREG) {
|
||||
struct sock *sk;
|
||||
struct hlist_node *node;
|
||||
|
||||
/* Detach sockets from device */
|
||||
read_lock(&hci_sk_list.lock);
|
||||
sk_for_each(sk, node, &hci_sk_list.head) {
|
||||
bh_lock_sock_nested(sk);
|
||||
if (hci_pi(sk)->hdev == hdev) {
|
||||
hci_pi(sk)->hdev = NULL;
|
||||
sk->sk_err = EPIPE;
|
||||
sk->sk_state = BT_OPEN;
|
||||
sk->sk_state_change(sk);
|
||||
|
||||
hci_dev_put(hdev);
|
||||
}
|
||||
bh_unlock_sock(sk);
|
||||
}
|
||||
read_unlock(&hci_sk_list.lock);
|
||||
}
|
||||
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
|
||||
static const struct net_proto_family hci_sock_family_ops = {
|
||||
.family = PF_BLUETOOTH,
|
||||
.owner = THIS_MODULE,
|
||||
.create = hci_sock_create,
|
||||
};
|
||||
|
||||
static struct notifier_block hci_sock_nblock = {
|
||||
.notifier_call = hci_sock_dev_event
|
||||
};
|
||||
|
||||
int __init hci_sock_init(void)
|
||||
{
|
||||
int err;
|
||||
@ -806,8 +1110,6 @@ int __init hci_sock_init(void)
|
||||
if (err < 0)
|
||||
goto error;
|
||||
|
||||
hci_register_notifier(&hci_sock_nblock);
|
||||
|
||||
BT_INFO("HCI socket layer initialized");
|
||||
|
||||
return 0;
|
||||
@ -823,10 +1125,5 @@ void hci_sock_cleanup(void)
|
||||
if (bt_sock_unregister(BTPROTO_HCI) < 0)
|
||||
BT_ERR("HCI socket unregistration failed");
|
||||
|
||||
hci_unregister_notifier(&hci_sock_nblock);
|
||||
|
||||
proto_unregister(&hci_sk_proto);
|
||||
}
|
||||
|
||||
module_param(enable_mgmt, bool, 0644);
|
||||
MODULE_PARM_DESC(enable_mgmt, "Enable Management interface");
|
||||
|
@ -33,19 +33,19 @@ static inline char *link_typetostr(int type)
|
||||
|
||||
static ssize_t show_link_type(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct hci_conn *conn = dev_get_drvdata(dev);
|
||||
struct hci_conn *conn = to_hci_conn(dev);
|
||||
return sprintf(buf, "%s\n", link_typetostr(conn->type));
|
||||
}
|
||||
|
||||
static ssize_t show_link_address(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct hci_conn *conn = dev_get_drvdata(dev);
|
||||
struct hci_conn *conn = to_hci_conn(dev);
|
||||
return sprintf(buf, "%s\n", batostr(&conn->dst));
|
||||
}
|
||||
|
||||
static ssize_t show_link_features(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct hci_conn *conn = dev_get_drvdata(dev);
|
||||
struct hci_conn *conn = to_hci_conn(dev);
|
||||
|
||||
return sprintf(buf, "0x%02x%02x%02x%02x%02x%02x%02x%02x\n",
|
||||
conn->features[0], conn->features[1],
|
||||
@ -79,8 +79,8 @@ static const struct attribute_group *bt_link_groups[] = {
|
||||
|
||||
static void bt_link_release(struct device *dev)
|
||||
{
|
||||
void *data = dev_get_drvdata(dev);
|
||||
kfree(data);
|
||||
struct hci_conn *conn = to_hci_conn(dev);
|
||||
kfree(conn);
|
||||
}
|
||||
|
||||
static struct device_type bt_link = {
|
||||
@ -120,8 +120,6 @@ void hci_conn_add_sysfs(struct hci_conn *conn)
|
||||
|
||||
dev_set_name(&conn->dev, "%s:%d", hdev->name, conn->handle);
|
||||
|
||||
dev_set_drvdata(&conn->dev, conn);
|
||||
|
||||
if (device_add(&conn->dev) < 0) {
|
||||
BT_ERR("Failed to register connection device");
|
||||
return;
|
||||
@ -189,19 +187,19 @@ static inline char *host_typetostr(int type)
|
||||
|
||||
static ssize_t show_bus(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct hci_dev *hdev = dev_get_drvdata(dev);
|
||||
struct hci_dev *hdev = to_hci_dev(dev);
|
||||
return sprintf(buf, "%s\n", host_bustostr(hdev->bus));
|
||||
}
|
||||
|
||||
static ssize_t show_type(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct hci_dev *hdev = dev_get_drvdata(dev);
|
||||
struct hci_dev *hdev = to_hci_dev(dev);
|
||||
return sprintf(buf, "%s\n", host_typetostr(hdev->dev_type));
|
||||
}
|
||||
|
||||
static ssize_t show_name(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct hci_dev *hdev = dev_get_drvdata(dev);
|
||||
struct hci_dev *hdev = to_hci_dev(dev);
|
||||
char name[HCI_MAX_NAME_LENGTH + 1];
|
||||
int i;
|
||||
|
||||
@ -214,20 +212,20 @@ static ssize_t show_name(struct device *dev, struct device_attribute *attr, char
|
||||
|
||||
static ssize_t show_class(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct hci_dev *hdev = dev_get_drvdata(dev);
|
||||
struct hci_dev *hdev = to_hci_dev(dev);
|
||||
return sprintf(buf, "0x%.2x%.2x%.2x\n",
|
||||
hdev->dev_class[2], hdev->dev_class[1], hdev->dev_class[0]);
|
||||
}
|
||||
|
||||
static ssize_t show_address(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct hci_dev *hdev = dev_get_drvdata(dev);
|
||||
struct hci_dev *hdev = to_hci_dev(dev);
|
||||
return sprintf(buf, "%s\n", batostr(&hdev->bdaddr));
|
||||
}
|
||||
|
||||
static ssize_t show_features(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct hci_dev *hdev = dev_get_drvdata(dev);
|
||||
struct hci_dev *hdev = to_hci_dev(dev);
|
||||
|
||||
return sprintf(buf, "0x%02x%02x%02x%02x%02x%02x%02x%02x\n",
|
||||
hdev->features[0], hdev->features[1],
|
||||
@ -238,31 +236,31 @@ static ssize_t show_features(struct device *dev, struct device_attribute *attr,
|
||||
|
||||
static ssize_t show_manufacturer(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct hci_dev *hdev = dev_get_drvdata(dev);
|
||||
struct hci_dev *hdev = to_hci_dev(dev);
|
||||
return sprintf(buf, "%d\n", hdev->manufacturer);
|
||||
}
|
||||
|
||||
static ssize_t show_hci_version(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct hci_dev *hdev = dev_get_drvdata(dev);
|
||||
struct hci_dev *hdev = to_hci_dev(dev);
|
||||
return sprintf(buf, "%d\n", hdev->hci_ver);
|
||||
}
|
||||
|
||||
static ssize_t show_hci_revision(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct hci_dev *hdev = dev_get_drvdata(dev);
|
||||
struct hci_dev *hdev = to_hci_dev(dev);
|
||||
return sprintf(buf, "%d\n", hdev->hci_rev);
|
||||
}
|
||||
|
||||
static ssize_t show_idle_timeout(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct hci_dev *hdev = dev_get_drvdata(dev);
|
||||
struct hci_dev *hdev = to_hci_dev(dev);
|
||||
return sprintf(buf, "%d\n", hdev->idle_timeout);
|
||||
}
|
||||
|
||||
static ssize_t store_idle_timeout(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
|
||||
{
|
||||
struct hci_dev *hdev = dev_get_drvdata(dev);
|
||||
struct hci_dev *hdev = to_hci_dev(dev);
|
||||
unsigned int val;
|
||||
int rv;
|
||||
|
||||
@ -280,13 +278,13 @@ static ssize_t store_idle_timeout(struct device *dev, struct device_attribute *a
|
||||
|
||||
static ssize_t show_sniff_max_interval(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct hci_dev *hdev = dev_get_drvdata(dev);
|
||||
struct hci_dev *hdev = to_hci_dev(dev);
|
||||
return sprintf(buf, "%d\n", hdev->sniff_max_interval);
|
||||
}
|
||||
|
||||
static ssize_t store_sniff_max_interval(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
|
||||
{
|
||||
struct hci_dev *hdev = dev_get_drvdata(dev);
|
||||
struct hci_dev *hdev = to_hci_dev(dev);
|
||||
u16 val;
|
||||
int rv;
|
||||
|
||||
@ -304,13 +302,13 @@ static ssize_t store_sniff_max_interval(struct device *dev, struct device_attrib
|
||||
|
||||
static ssize_t show_sniff_min_interval(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct hci_dev *hdev = dev_get_drvdata(dev);
|
||||
struct hci_dev *hdev = to_hci_dev(dev);
|
||||
return sprintf(buf, "%d\n", hdev->sniff_min_interval);
|
||||
}
|
||||
|
||||
static ssize_t store_sniff_min_interval(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
|
||||
{
|
||||
struct hci_dev *hdev = dev_get_drvdata(dev);
|
||||
struct hci_dev *hdev = to_hci_dev(dev);
|
||||
u16 val;
|
||||
int rv;
|
||||
|
||||
@ -370,8 +368,9 @@ static const struct attribute_group *bt_host_groups[] = {
|
||||
|
||||
static void bt_host_release(struct device *dev)
|
||||
{
|
||||
void *data = dev_get_drvdata(dev);
|
||||
kfree(data);
|
||||
struct hci_dev *hdev = to_hci_dev(dev);
|
||||
kfree(hdev);
|
||||
module_put(THIS_MODULE);
|
||||
}
|
||||
|
||||
static struct device_type bt_host = {
|
||||
@ -383,12 +382,12 @@ static struct device_type bt_host = {
|
||||
static int inquiry_cache_show(struct seq_file *f, void *p)
|
||||
{
|
||||
struct hci_dev *hdev = f->private;
|
||||
struct inquiry_cache *cache = &hdev->inq_cache;
|
||||
struct discovery_state *cache = &hdev->discovery;
|
||||
struct inquiry_entry *e;
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
|
||||
for (e = cache->list; e; e = e->next) {
|
||||
list_for_each_entry(e, &cache->all, all) {
|
||||
struct inquiry_data *data = &e->data;
|
||||
seq_printf(f, "%s %d %d %d 0x%.2x%.2x%.2x 0x%.4x %d %d %u\n",
|
||||
batostr(&data->bdaddr),
|
||||
@ -523,7 +522,7 @@ void hci_init_sysfs(struct hci_dev *hdev)
|
||||
dev->type = &bt_host;
|
||||
dev->class = bt_class;
|
||||
|
||||
dev_set_drvdata(dev, hdev);
|
||||
__module_get(THIS_MODULE);
|
||||
device_initialize(dev);
|
||||
}
|
||||
|
||||
|
@ -160,10 +160,10 @@ static int hidp_sock_compat_ioctl(struct socket *sock, unsigned int cmd, unsigne
|
||||
{
|
||||
if (cmd == HIDPGETCONNLIST) {
|
||||
struct hidp_connlist_req cl;
|
||||
uint32_t uci;
|
||||
u32 uci;
|
||||
int err;
|
||||
|
||||
if (get_user(cl.cnum, (uint32_t __user *) arg) ||
|
||||
if (get_user(cl.cnum, (u32 __user *) arg) ||
|
||||
get_user(uci, (u32 __user *) (arg + 4)))
|
||||
return -EFAULT;
|
||||
|
||||
@ -174,7 +174,7 @@ static int hidp_sock_compat_ioctl(struct socket *sock, unsigned int cmd, unsigne
|
||||
|
||||
err = hidp_get_connlist(&cl);
|
||||
|
||||
if (!err && put_user(cl.cnum, (uint32_t __user *) arg))
|
||||
if (!err && put_user(cl.cnum, (u32 __user *) arg))
|
||||
err = -EFAULT;
|
||||
|
||||
return err;
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -125,13 +125,15 @@ static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int al
|
||||
|
||||
err = l2cap_chan_connect(chan, la.l2_psm, la.l2_cid, &la.l2_bdaddr);
|
||||
if (err)
|
||||
goto done;
|
||||
return err;
|
||||
|
||||
lock_sock(sk);
|
||||
|
||||
err = bt_sock_wait_state(sk, BT_CONNECTED,
|
||||
sock_sndtimeo(sk, flags & O_NONBLOCK));
|
||||
done:
|
||||
if (sock_owned_by_user(sk))
|
||||
release_sock(sk);
|
||||
|
||||
release_sock(sk);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -783,7 +785,7 @@ static void l2cap_sock_kill(struct sock *sk)
|
||||
if (!sock_flag(sk, SOCK_ZAPPED) || sk->sk_socket)
|
||||
return;
|
||||
|
||||
BT_DBG("sk %p state %d", sk, sk->sk_state);
|
||||
BT_DBG("sk %p state %s", sk, state_to_string(sk->sk_state));
|
||||
|
||||
/* Kill poor orphan */
|
||||
|
||||
@ -795,7 +797,8 @@ static void l2cap_sock_kill(struct sock *sk)
|
||||
static int l2cap_sock_shutdown(struct socket *sock, int how)
|
||||
{
|
||||
struct sock *sk = sock->sk;
|
||||
struct l2cap_chan *chan = l2cap_pi(sk)->chan;
|
||||
struct l2cap_chan *chan;
|
||||
struct l2cap_conn *conn;
|
||||
int err = 0;
|
||||
|
||||
BT_DBG("sock %p, sk %p", sock, sk);
|
||||
@ -803,13 +806,24 @@ static int l2cap_sock_shutdown(struct socket *sock, int how)
|
||||
if (!sk)
|
||||
return 0;
|
||||
|
||||
chan = l2cap_pi(sk)->chan;
|
||||
conn = chan->conn;
|
||||
|
||||
if (conn)
|
||||
mutex_lock(&conn->chan_lock);
|
||||
|
||||
l2cap_chan_lock(chan);
|
||||
lock_sock(sk);
|
||||
|
||||
if (!sk->sk_shutdown) {
|
||||
if (chan->mode == L2CAP_MODE_ERTM)
|
||||
err = __l2cap_wait_ack(sk);
|
||||
|
||||
sk->sk_shutdown = SHUTDOWN_MASK;
|
||||
|
||||
release_sock(sk);
|
||||
l2cap_chan_close(chan, 0);
|
||||
lock_sock(sk);
|
||||
|
||||
if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime)
|
||||
err = bt_sock_wait_state(sk, BT_CLOSED,
|
||||
@ -820,6 +834,11 @@ static int l2cap_sock_shutdown(struct socket *sock, int how)
|
||||
err = -sk->sk_err;
|
||||
|
||||
release_sock(sk);
|
||||
l2cap_chan_unlock(chan);
|
||||
|
||||
if (conn)
|
||||
mutex_unlock(&conn->chan_lock);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -862,8 +881,12 @@ static int l2cap_sock_recv_cb(void *data, struct sk_buff *skb)
|
||||
struct sock *sk = data;
|
||||
struct l2cap_pinfo *pi = l2cap_pi(sk);
|
||||
|
||||
if (pi->rx_busy_skb)
|
||||
return -ENOMEM;
|
||||
lock_sock(sk);
|
||||
|
||||
if (pi->rx_busy_skb) {
|
||||
err = -ENOMEM;
|
||||
goto done;
|
||||
}
|
||||
|
||||
err = sock_queue_rcv_skb(sk, skb);
|
||||
|
||||
@ -882,6 +905,9 @@ static int l2cap_sock_recv_cb(void *data, struct sk_buff *skb)
|
||||
err = 0;
|
||||
}
|
||||
|
||||
done:
|
||||
release_sock(sk);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -899,12 +925,22 @@ static void l2cap_sock_state_change_cb(void *data, int state)
|
||||
sk->sk_state = state;
|
||||
}
|
||||
|
||||
static struct sk_buff *l2cap_sock_alloc_skb_cb(struct l2cap_chan *chan,
|
||||
unsigned long len, int nb,
|
||||
int *err)
|
||||
{
|
||||
struct sock *sk = chan->sk;
|
||||
|
||||
return bt_skb_send_alloc(sk, len, nb, err);
|
||||
}
|
||||
|
||||
static struct l2cap_ops l2cap_chan_ops = {
|
||||
.name = "L2CAP Socket Interface",
|
||||
.new_connection = l2cap_sock_new_connection_cb,
|
||||
.recv = l2cap_sock_recv_cb,
|
||||
.close = l2cap_sock_close_cb,
|
||||
.state_change = l2cap_sock_state_change_cb,
|
||||
.alloc_skb = l2cap_sock_alloc_skb_cb,
|
||||
};
|
||||
|
||||
static void l2cap_sock_destruct(struct sock *sk)
|
||||
@ -1004,7 +1040,7 @@ static struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock, int p
|
||||
INIT_LIST_HEAD(&bt_sk(sk)->accept_q);
|
||||
|
||||
sk->sk_destruct = l2cap_sock_destruct;
|
||||
sk->sk_sndtimeo = msecs_to_jiffies(L2CAP_CONN_TIMEOUT);
|
||||
sk->sk_sndtimeo = L2CAP_CONN_TIMEOUT;
|
||||
|
||||
sock_reset_flag(sk, SOCK_ZAPPED);
|
||||
|
||||
|
@ -24,6 +24,8 @@
|
||||
|
||||
/* Bluetooth kernel library. */
|
||||
|
||||
#define pr_fmt(fmt) "Bluetooth: " fmt
|
||||
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <linux/kernel.h>
|
||||
@ -151,7 +153,7 @@ int bt_to_errno(__u16 code)
|
||||
}
|
||||
EXPORT_SYMBOL(bt_to_errno);
|
||||
|
||||
int bt_printk(const char *level, const char *format, ...)
|
||||
int bt_info(const char *format, ...)
|
||||
{
|
||||
struct va_format vaf;
|
||||
va_list args;
|
||||
@ -162,10 +164,29 @@ int bt_printk(const char *level, const char *format, ...)
|
||||
vaf.fmt = format;
|
||||
vaf.va = &args;
|
||||
|
||||
r = printk("%sBluetooth: %pV\n", level, &vaf);
|
||||
r = pr_info("%pV", &vaf);
|
||||
|
||||
va_end(args);
|
||||
|
||||
return r;
|
||||
}
|
||||
EXPORT_SYMBOL(bt_printk);
|
||||
EXPORT_SYMBOL(bt_info);
|
||||
|
||||
int bt_err(const char *format, ...)
|
||||
{
|
||||
struct va_format vaf;
|
||||
va_list args;
|
||||
int r;
|
||||
|
||||
va_start(args, format);
|
||||
|
||||
vaf.fmt = format;
|
||||
vaf.va = &args;
|
||||
|
||||
r = pr_err("%pV", &vaf);
|
||||
|
||||
va_end(args);
|
||||
|
||||
return r;
|
||||
}
|
||||
EXPORT_SYMBOL(bt_err);
|
||||
|
2693
net/bluetooth/mgmt.c
2693
net/bluetooth/mgmt.c
File diff suppressed because it is too large
Load Diff
@ -196,7 +196,7 @@ static DEVICE_ATTR(channel, S_IRUGO, show_channel, NULL);
|
||||
static int rfcomm_dev_add(struct rfcomm_dev_req *req, struct rfcomm_dlc *dlc)
|
||||
{
|
||||
struct rfcomm_dev *dev, *entry;
|
||||
struct list_head *head = &rfcomm_dev_list, *p;
|
||||
struct list_head *head = &rfcomm_dev_list;
|
||||
int err = 0;
|
||||
|
||||
BT_DBG("id %d channel %d", req->dev_id, req->channel);
|
||||
@ -215,7 +215,7 @@ static int rfcomm_dev_add(struct rfcomm_dev_req *req, struct rfcomm_dlc *dlc)
|
||||
break;
|
||||
|
||||
dev->id++;
|
||||
head = p;
|
||||
head = &entry->list;
|
||||
}
|
||||
} else {
|
||||
dev->id = req->dev_id;
|
||||
@ -229,7 +229,7 @@ static int rfcomm_dev_add(struct rfcomm_dev_req *req, struct rfcomm_dlc *dlc)
|
||||
if (entry->id > dev->id - 1)
|
||||
break;
|
||||
|
||||
head = p;
|
||||
head = &entry->list;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -29,7 +29,7 @@
|
||||
#include <linux/scatterlist.h>
|
||||
#include <crypto/b128ops.h>
|
||||
|
||||
#define SMP_TIMEOUT 30000 /* 30 seconds */
|
||||
#define SMP_TIMEOUT msecs_to_jiffies(30000)
|
||||
|
||||
static inline void swap128(u8 src[16], u8 dst[16])
|
||||
{
|
||||
@ -186,8 +186,7 @@ static void smp_send_cmd(struct l2cap_conn *conn, u8 code, u16 len, void *data)
|
||||
hci_send_acl(conn->hchan, skb, 0);
|
||||
|
||||
cancel_delayed_work_sync(&conn->security_timer);
|
||||
schedule_delayed_work(&conn->security_timer,
|
||||
msecs_to_jiffies(SMP_TIMEOUT));
|
||||
schedule_delayed_work(&conn->security_timer, SMP_TIMEOUT);
|
||||
}
|
||||
|
||||
static __u8 authreq_to_seclevel(__u8 authreq)
|
||||
@ -217,7 +216,7 @@ static void build_pairing_cmd(struct l2cap_conn *conn,
|
||||
{
|
||||
u8 dist_keys = 0;
|
||||
|
||||
if (test_bit(HCI_PAIRABLE, &conn->hcon->hdev->flags)) {
|
||||
if (test_bit(HCI_PAIRABLE, &conn->hcon->hdev->dev_flags)) {
|
||||
dist_keys = SMP_DIST_ENC_KEY;
|
||||
authreq |= SMP_AUTH_BONDING;
|
||||
} else {
|
||||
@ -250,21 +249,27 @@ static u8 check_enc_key_size(struct l2cap_conn *conn, __u8 max_key_size)
|
||||
(max_key_size < SMP_MIN_ENC_KEY_SIZE))
|
||||
return SMP_ENC_KEY_SIZE;
|
||||
|
||||
smp->smp_key_size = max_key_size;
|
||||
smp->enc_key_size = max_key_size;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void smp_failure(struct l2cap_conn *conn, u8 reason, u8 send)
|
||||
{
|
||||
struct hci_conn *hcon = conn->hcon;
|
||||
|
||||
if (send)
|
||||
smp_send_cmd(conn, SMP_CMD_PAIRING_FAIL, sizeof(reason),
|
||||
&reason);
|
||||
|
||||
clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->hcon->pend);
|
||||
mgmt_auth_failed(conn->hcon->hdev, conn->dst, reason);
|
||||
cancel_delayed_work_sync(&conn->security_timer);
|
||||
smp_chan_destroy(conn);
|
||||
clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->hcon->flags);
|
||||
mgmt_auth_failed(conn->hcon->hdev, conn->dst, hcon->type,
|
||||
hcon->dst_type, reason);
|
||||
|
||||
if (test_and_clear_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->flags)) {
|
||||
cancel_delayed_work_sync(&conn->security_timer);
|
||||
smp_chan_destroy(conn);
|
||||
}
|
||||
}
|
||||
|
||||
#define JUST_WORKS 0x00
|
||||
@ -305,7 +310,7 @@ static int tk_request(struct l2cap_conn *conn, u8 remote_oob, u8 auth,
|
||||
remote_io > SMP_IO_KEYBOARD_DISPLAY)
|
||||
method = JUST_WORKS;
|
||||
else
|
||||
method = gen_method[local_io][remote_io];
|
||||
method = gen_method[remote_io][local_io];
|
||||
|
||||
/* If not bonding, don't ask user to confirm a Zero TK */
|
||||
if (!(auth & SMP_AUTH_BONDING) && method == JUST_CFM)
|
||||
@ -346,9 +351,11 @@ static int tk_request(struct l2cap_conn *conn, u8 remote_oob, u8 auth,
|
||||
hci_dev_lock(hcon->hdev);
|
||||
|
||||
if (method == REQ_PASSKEY)
|
||||
ret = mgmt_user_passkey_request(hcon->hdev, conn->dst);
|
||||
ret = mgmt_user_passkey_request(hcon->hdev, conn->dst,
|
||||
hcon->type, hcon->dst_type);
|
||||
else
|
||||
ret = mgmt_user_confirm_request(hcon->hdev, conn->dst,
|
||||
hcon->type, hcon->dst_type,
|
||||
cpu_to_le32(passkey), 0);
|
||||
|
||||
hci_dev_unlock(hcon->hdev);
|
||||
@ -377,12 +384,11 @@ static void confirm_work(struct work_struct *work)
|
||||
|
||||
if (conn->hcon->out)
|
||||
ret = smp_c1(tfm, smp->tk, smp->prnd, smp->preq, smp->prsp, 0,
|
||||
conn->src, conn->hcon->dst_type, conn->dst,
|
||||
res);
|
||||
conn->src, conn->hcon->dst_type, conn->dst, res);
|
||||
else
|
||||
ret = smp_c1(tfm, smp->tk, smp->prnd, smp->preq, smp->prsp,
|
||||
conn->hcon->dst_type, conn->dst, 0, conn->src,
|
||||
res);
|
||||
conn->hcon->dst_type, conn->dst, 0, conn->src,
|
||||
res);
|
||||
if (ret) {
|
||||
reason = SMP_UNSPECIFIED;
|
||||
goto error;
|
||||
@ -417,12 +423,10 @@ static void random_work(struct work_struct *work)
|
||||
|
||||
if (hcon->out)
|
||||
ret = smp_c1(tfm, smp->tk, smp->rrnd, smp->preq, smp->prsp, 0,
|
||||
conn->src, hcon->dst_type, conn->dst,
|
||||
res);
|
||||
conn->src, hcon->dst_type, conn->dst, res);
|
||||
else
|
||||
ret = smp_c1(tfm, smp->tk, smp->rrnd, smp->preq, smp->prsp,
|
||||
hcon->dst_type, conn->dst, 0, conn->src,
|
||||
res);
|
||||
hcon->dst_type, conn->dst, 0, conn->src, res);
|
||||
if (ret) {
|
||||
reason = SMP_UNSPECIFIED;
|
||||
goto error;
|
||||
@ -446,16 +450,16 @@ static void random_work(struct work_struct *work)
|
||||
smp_s1(tfm, smp->tk, smp->rrnd, smp->prnd, key);
|
||||
swap128(key, stk);
|
||||
|
||||
memset(stk + smp->smp_key_size, 0,
|
||||
SMP_MAX_ENC_KEY_SIZE - smp->smp_key_size);
|
||||
memset(stk + smp->enc_key_size, 0,
|
||||
SMP_MAX_ENC_KEY_SIZE - smp->enc_key_size);
|
||||
|
||||
if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend)) {
|
||||
if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &hcon->flags)) {
|
||||
reason = SMP_UNSPECIFIED;
|
||||
goto error;
|
||||
}
|
||||
|
||||
hci_le_start_enc(hcon, ediv, rand, stk);
|
||||
hcon->enc_key_size = smp->smp_key_size;
|
||||
hcon->enc_key_size = smp->enc_key_size;
|
||||
} else {
|
||||
u8 stk[16], r[16], rand[8];
|
||||
__le16 ediv;
|
||||
@ -469,11 +473,12 @@ static void random_work(struct work_struct *work)
|
||||
smp_s1(tfm, smp->tk, smp->prnd, smp->rrnd, key);
|
||||
swap128(key, stk);
|
||||
|
||||
memset(stk + smp->smp_key_size, 0,
|
||||
SMP_MAX_ENC_KEY_SIZE - smp->smp_key_size);
|
||||
memset(stk + smp->enc_key_size, 0,
|
||||
SMP_MAX_ENC_KEY_SIZE - smp->enc_key_size);
|
||||
|
||||
hci_add_ltk(hcon->hdev, 0, conn->dst, smp->smp_key_size,
|
||||
ediv, rand, stk);
|
||||
hci_add_ltk(hcon->hdev, conn->dst, hcon->dst_type,
|
||||
HCI_SMP_STK_SLAVE, 0, 0, stk, smp->enc_key_size,
|
||||
ediv, rand);
|
||||
}
|
||||
|
||||
return;
|
||||
@ -506,7 +511,7 @@ void smp_chan_destroy(struct l2cap_conn *conn)
|
||||
{
|
||||
struct smp_chan *smp = conn->smp_chan;
|
||||
|
||||
clear_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->pend);
|
||||
BUG_ON(!smp);
|
||||
|
||||
if (smp->tfm)
|
||||
crypto_free_blkcipher(smp->tfm);
|
||||
@ -571,7 +576,7 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb)
|
||||
if (conn->hcon->link_mode & HCI_LM_MASTER)
|
||||
return SMP_CMD_NOTSUPP;
|
||||
|
||||
if (!test_and_set_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->pend))
|
||||
if (!test_and_set_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->flags))
|
||||
smp = smp_chan_create(conn);
|
||||
|
||||
smp = conn->smp_chan;
|
||||
@ -584,6 +589,8 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb)
|
||||
if (req->auth_req & SMP_AUTH_BONDING)
|
||||
auth = req->auth_req;
|
||||
|
||||
conn->hcon->pending_sec_level = authreq_to_seclevel(auth);
|
||||
|
||||
build_pairing_cmd(conn, req, &rsp, auth);
|
||||
|
||||
key_size = min(req->max_key_size, rsp.max_key_size);
|
||||
@ -698,23 +705,18 @@ static u8 smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb)
|
||||
|
||||
static u8 smp_ltk_encrypt(struct l2cap_conn *conn)
|
||||
{
|
||||
struct link_key *key;
|
||||
struct key_master_id *master;
|
||||
struct smp_ltk *key;
|
||||
struct hci_conn *hcon = conn->hcon;
|
||||
|
||||
key = hci_find_link_key_type(hcon->hdev, conn->dst,
|
||||
HCI_LK_SMP_LTK);
|
||||
key = hci_find_ltk_by_addr(hcon->hdev, conn->dst, hcon->dst_type);
|
||||
if (!key)
|
||||
return 0;
|
||||
|
||||
if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND,
|
||||
&hcon->pend))
|
||||
if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &hcon->flags))
|
||||
return 1;
|
||||
|
||||
master = (void *) key->data;
|
||||
hci_le_start_enc(hcon, master->ediv, master->rand,
|
||||
key->val);
|
||||
hcon->enc_key_size = key->pin_len;
|
||||
hci_le_start_enc(hcon, key->ediv, key->rand, key->val);
|
||||
hcon->enc_key_size = key->enc_size;
|
||||
|
||||
return 1;
|
||||
|
||||
@ -733,7 +735,7 @@ static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb)
|
||||
if (smp_ltk_encrypt(conn))
|
||||
return 0;
|
||||
|
||||
if (test_and_set_bit(HCI_CONN_LE_SMP_PEND, &hcon->pend))
|
||||
if (test_and_set_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags))
|
||||
return 0;
|
||||
|
||||
smp = smp_chan_create(conn);
|
||||
@ -772,7 +774,7 @@ int smp_conn_security(struct l2cap_conn *conn, __u8 sec_level)
|
||||
if (smp_ltk_encrypt(conn))
|
||||
goto done;
|
||||
|
||||
if (test_and_set_bit(HCI_CONN_LE_SMP_PEND, &hcon->pend))
|
||||
if (test_and_set_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags))
|
||||
return 0;
|
||||
|
||||
smp = smp_chan_create(conn);
|
||||
@ -817,13 +819,19 @@ static int smp_cmd_master_ident(struct l2cap_conn *conn, struct sk_buff *skb)
|
||||
{
|
||||
struct smp_cmd_master_ident *rp = (void *) skb->data;
|
||||
struct smp_chan *smp = conn->smp_chan;
|
||||
struct hci_dev *hdev = conn->hcon->hdev;
|
||||
struct hci_conn *hcon = conn->hcon;
|
||||
u8 authenticated;
|
||||
|
||||
skb_pull(skb, sizeof(*rp));
|
||||
|
||||
hci_add_ltk(conn->hcon->hdev, 1, conn->dst, smp->smp_key_size,
|
||||
rp->ediv, rp->rand, smp->tk);
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
authenticated = (conn->hcon->sec_level == BT_SECURITY_HIGH);
|
||||
hci_add_ltk(conn->hcon->hdev, conn->dst, hcon->dst_type,
|
||||
HCI_SMP_LTK, 1, authenticated, smp->tk, smp->enc_key_size,
|
||||
rp->ediv, rp->rand);
|
||||
smp_distribute_keys(conn, 1);
|
||||
hci_dev_unlock(hdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -908,7 +916,7 @@ int smp_distribute_keys(struct l2cap_conn *conn, __u8 force)
|
||||
|
||||
BT_DBG("conn %p force %d", conn, force);
|
||||
|
||||
if (!test_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->pend))
|
||||
if (!test_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->flags))
|
||||
return 0;
|
||||
|
||||
rsp = (void *) &smp->prsp[1];
|
||||
@ -933,6 +941,8 @@ int smp_distribute_keys(struct l2cap_conn *conn, __u8 force)
|
||||
if (*keydist & SMP_DIST_ENC_KEY) {
|
||||
struct smp_cmd_encrypt_info enc;
|
||||
struct smp_cmd_master_ident ident;
|
||||
struct hci_conn *hcon = conn->hcon;
|
||||
u8 authenticated;
|
||||
__le16 ediv;
|
||||
|
||||
get_random_bytes(enc.ltk, sizeof(enc.ltk));
|
||||
@ -941,8 +951,10 @@ int smp_distribute_keys(struct l2cap_conn *conn, __u8 force)
|
||||
|
||||
smp_send_cmd(conn, SMP_CMD_ENCRYPT_INFO, sizeof(enc), &enc);
|
||||
|
||||
hci_add_ltk(conn->hcon->hdev, 1, conn->dst, smp->smp_key_size,
|
||||
ediv, ident.rand, enc.ltk);
|
||||
authenticated = hcon->sec_level == BT_SECURITY_HIGH;
|
||||
hci_add_ltk(conn->hcon->hdev, conn->dst, hcon->dst_type,
|
||||
HCI_SMP_LTK_SLAVE, 1, authenticated,
|
||||
enc.ltk, smp->enc_key_size, ediv, ident.rand);
|
||||
|
||||
ident.ediv = cpu_to_le16(ediv);
|
||||
|
||||
@ -982,7 +994,7 @@ int smp_distribute_keys(struct l2cap_conn *conn, __u8 force)
|
||||
}
|
||||
|
||||
if (conn->hcon->out || force) {
|
||||
clear_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->pend);
|
||||
clear_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->flags);
|
||||
cancel_delayed_work_sync(&conn->security_timer);
|
||||
smp_chan_destroy(conn);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user