diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index aaeaf0938ec0..128157db0680 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -109,6 +109,7 @@ enum { HCI_SERVICE_CACHE, HCI_DEBUG_KEYS, HCI_UNREGISTER, + HCI_USER_CHANNEL, HCI_LE_SCAN, HCI_SSP_ENABLED, diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 0976eabdafb0..0ee0f01d33df 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -984,6 +984,11 @@ int hci_inquiry(void __user *arg) if (!hdev) return -ENODEV; + if (test_bit(HCI_USER_CHANNEL, &hdev->dev_flags)) { + err = -EBUSY; + goto done; + } + hci_dev_lock(hdev); if (inquiry_cache_age(hdev) > INQUIRY_CACHE_AGE_MAX || inquiry_cache_empty(hdev) || ir.flags & IREQ_CACHE_FLUSH) { @@ -1177,7 +1182,8 @@ int hci_dev_open(__u16 dev) if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks)) set_bit(HCI_RAW, &hdev->flags); - if (!test_bit(HCI_RAW, &hdev->flags)) + if (!test_bit(HCI_RAW, &hdev->flags) && + !test_bit(HCI_USER_CHANNEL, &hdev->dev_flags)) ret = __hci_init(hdev); } @@ -1188,6 +1194,7 @@ int hci_dev_open(__u16 dev) set_bit(HCI_UP, &hdev->flags); hci_notify(hdev, HCI_DEV_UP); if (!test_bit(HCI_SETUP, &hdev->dev_flags) && + !test_bit(HCI_USER_CHANNEL, &hdev->dev_flags) && mgmt_valid_hdev(hdev)) { hci_dev_lock(hdev); mgmt_powered(hdev, 1); @@ -1324,11 +1331,17 @@ int hci_dev_close(__u16 dev) if (!hdev) return -ENODEV; + if (test_bit(HCI_USER_CHANNEL, &hdev->dev_flags)) { + err = -EBUSY; + goto done; + } + if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) cancel_delayed_work(&hdev->power_off); err = hci_dev_do_close(hdev); +done: hci_dev_put(hdev); return err; } @@ -1349,6 +1362,11 @@ int hci_dev_reset(__u16 dev) goto done; } + if (test_bit(HCI_USER_CHANNEL, &hdev->dev_flags)) { + ret = -EBUSY; + goto done; + } + /* Drop queues */ skb_queue_purge(&hdev->rx_q); skb_queue_purge(&hdev->cmd_q); @@ -1382,10 +1400,15 @@ int hci_dev_reset_stat(__u16 dev) if (!hdev) return -ENODEV; + if (test_bit(HCI_USER_CHANNEL, &hdev->dev_flags)) { + ret = -EBUSY; + goto done; + } + memset(&hdev->stat, 0, sizeof(struct hci_dev_stats)); +done: hci_dev_put(hdev); - return ret; } @@ -1402,6 +1425,11 @@ int hci_dev_cmd(unsigned int cmd, void __user *arg) if (!hdev) return -ENODEV; + if (test_bit(HCI_USER_CHANNEL, &hdev->dev_flags)) { + err = -EBUSY; + goto done; + } + switch (cmd) { case HCISETAUTH: err = hci_req_sync(hdev, hci_auth_req, dr.dev_opt, @@ -1460,6 +1488,7 @@ int hci_dev_cmd(unsigned int cmd, void __user *arg) break; } +done: hci_dev_put(hdev); return err; } @@ -1568,6 +1597,9 @@ static int hci_rfkill_set_block(void *data, bool blocked) BT_DBG("%p name %s blocked %d", hdev, hdev->name, blocked); + if (test_bit(HCI_USER_CHANNEL, &hdev->dev_flags)) + return -EBUSY; + if (!blocked) return 0; @@ -3459,7 +3491,8 @@ static void hci_rx_work(struct work_struct *work) hci_send_to_sock(hdev, skb); } - if (test_bit(HCI_RAW, &hdev->flags)) { + if (test_bit(HCI_RAW, &hdev->flags) || + test_bit(HCI_USER_CHANNEL, &hdev->dev_flags)) { kfree_skb(skb); continue; } diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c index ab570387f505..59e68f199178 100644 --- a/net/bluetooth/hci_sock.c +++ b/net/bluetooth/hci_sock.c @@ -500,6 +500,9 @@ static int hci_sock_bound_ioctl(struct sock *sk, unsigned int cmd, if (!hdev) return -EBADFD; + if (test_bit(HCI_USER_CHANNEL, &hdev->dev_flags)) + return -EBUSY; + switch (cmd) { case HCISETRAW: if (!capable(CAP_NET_ADMIN)) @@ -530,19 +533,19 @@ static int hci_sock_bound_ioctl(struct sock *sk, unsigned int cmd, if (!capable(CAP_NET_ADMIN)) return -EPERM; return hci_sock_blacklist_del(hdev, (void __user *) arg); - - default: - if (hdev->ioctl) - return hdev->ioctl(hdev, cmd, arg); - return -EINVAL; } + + if (hdev->ioctl) + return hdev->ioctl(hdev, cmd, arg); + + return -EINVAL; } static int hci_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) { - struct sock *sk = sock->sk; void __user *argp = (void __user *) arg; + struct sock *sk = sock->sk; int err; BT_DBG("cmd %x arg %lx", cmd, arg); diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index fedc5399d465..3070e772db6b 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -339,6 +339,9 @@ static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data, if (test_bit(HCI_SETUP, &d->dev_flags)) continue; + if (test_bit(HCI_USER_CHANNEL, &d->dev_flags)) + continue; + if (!mgmt_valid_hdev(d)) continue; @@ -3320,6 +3323,12 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) MGMT_STATUS_INVALID_INDEX); goto done; } + + if (test_bit(HCI_USER_CHANNEL, &hdev->dev_flags)) { + err = cmd_status(sk, index, opcode, + MGMT_STATUS_INVALID_INDEX); + goto done; + } } if (opcode >= ARRAY_SIZE(mgmt_handlers) ||