Commit fee746b0 authored by Marcel Holtmann's avatar Marcel Holtmann

Bluetooth: Restrict access for raw-only controllers

Bluetooth controllers that are marked for raw-only usage can only be
used with user channel access. Any other operation should be rejected.

This simplifies the whole raw-only support since it now depends on
the fact that the controller is marked with HCI_QUIRK_RAW_DEVICE and
runtime raw access is restricted to user channel operation.

The kernel internal processing of HCI commands and events is designed
around the case that either the kernel has full control over the device
or that the device is driven from userspace. This now makes a clear
distinction between these two possible operation modes.
Signed-off-by: default avatarMarcel Holtmann <marcel@holtmann.org>
Signed-off-by: default avatarJohan Hedberg <johan.hedberg@intel.com>
parent 95868426
...@@ -346,9 +346,6 @@ static void hci_conn_idle(struct work_struct *work) ...@@ -346,9 +346,6 @@ static void hci_conn_idle(struct work_struct *work)
BT_DBG("hcon %p mode %d", conn, conn->mode); BT_DBG("hcon %p mode %d", conn, conn->mode);
if (test_bit(HCI_RAW, &hdev->flags))
return;
if (!lmp_sniff_capable(hdev) || !lmp_sniff_capable(conn)) if (!lmp_sniff_capable(hdev) || !lmp_sniff_capable(conn))
return; return;
...@@ -539,7 +536,6 @@ struct hci_dev *hci_get_route(bdaddr_t *dst, bdaddr_t *src) ...@@ -539,7 +536,6 @@ struct hci_dev *hci_get_route(bdaddr_t *dst, bdaddr_t *src)
list_for_each_entry(d, &hci_dev_list, list) { list_for_each_entry(d, &hci_dev_list, list) {
if (!test_bit(HCI_UP, &d->flags) || if (!test_bit(HCI_UP, &d->flags) ||
test_bit(HCI_RAW, &d->flags) ||
test_bit(HCI_USER_CHANNEL, &d->dev_flags) || test_bit(HCI_USER_CHANNEL, &d->dev_flags) ||
d->dev_type != HCI_BREDR) d->dev_type != HCI_BREDR)
continue; continue;
...@@ -1059,9 +1055,6 @@ void hci_conn_enter_active_mode(struct hci_conn *conn, __u8 force_active) ...@@ -1059,9 +1055,6 @@ void hci_conn_enter_active_mode(struct hci_conn *conn, __u8 force_active)
BT_DBG("hcon %p mode %d", conn, conn->mode); BT_DBG("hcon %p mode %d", conn, conn->mode);
if (test_bit(HCI_RAW, &hdev->flags))
return;
if (conn->mode != HCI_CM_SNIFF) if (conn->mode != HCI_CM_SNIFF)
goto timer; goto timer;
......
...@@ -2117,6 +2117,11 @@ int hci_inquiry(void __user *arg) ...@@ -2117,6 +2117,11 @@ int hci_inquiry(void __user *arg)
goto done; goto done;
} }
if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks)) {
err = -EOPNOTSUPP;
goto done;
}
if (hdev->dev_type != HCI_BREDR) { if (hdev->dev_type != HCI_BREDR) {
err = -EOPNOTSUPP; err = -EOPNOTSUPP;
goto done; goto done;
...@@ -2246,10 +2251,7 @@ static int hci_dev_do_open(struct hci_dev *hdev) ...@@ -2246,10 +2251,7 @@ static int hci_dev_do_open(struct hci_dev *hdev)
ret = hdev->setup(hdev); ret = hdev->setup(hdev);
if (!ret) { if (!ret) {
if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks)) if (!test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks) &&
set_bit(HCI_RAW, &hdev->flags);
if (!test_bit(HCI_RAW, &hdev->flags) &&
!test_bit(HCI_USER_CHANNEL, &hdev->dev_flags)) !test_bit(HCI_USER_CHANNEL, &hdev->dev_flags))
ret = __hci_init(hdev); ret = __hci_init(hdev);
} }
...@@ -2286,7 +2288,7 @@ static int hci_dev_do_open(struct hci_dev *hdev) ...@@ -2286,7 +2288,7 @@ static int hci_dev_do_open(struct hci_dev *hdev)
} }
hdev->close(hdev); hdev->close(hdev);
hdev->flags = 0; hdev->flags &= BIT(HCI_RAW);
} }
done: done:
...@@ -2305,6 +2307,21 @@ int hci_dev_open(__u16 dev) ...@@ -2305,6 +2307,21 @@ int hci_dev_open(__u16 dev)
if (!hdev) if (!hdev)
return -ENODEV; return -ENODEV;
/* Devices that are marked for raw-only usage can only be powered
* up as user channel. Trying to bring them up as normal devices
* will result into a failure. Only user channel operation is
* possible.
*
* When this function is called for a user channel, the flag
* HCI_USER_CHANNEL will be set first before attempting to
* open the device.
*/
if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks) &&
!test_bit(HCI_USER_CHANNEL, &hdev->dev_flags)) {
err = -EOPNOTSUPP;
goto done;
}
/* We need to ensure that no other power on/off work is pending /* We need to ensure that no other power on/off work is pending
* before proceeding to call hci_dev_do_open. This is * before proceeding to call hci_dev_do_open. This is
* particularly important if the setup procedure has not yet * particularly important if the setup procedure has not yet
...@@ -2321,8 +2338,8 @@ int hci_dev_open(__u16 dev) ...@@ -2321,8 +2338,8 @@ int hci_dev_open(__u16 dev)
err = hci_dev_do_open(hdev); err = hci_dev_do_open(hdev);
done:
hci_dev_put(hdev); hci_dev_put(hdev);
return err; return err;
} }
...@@ -2374,7 +2391,7 @@ static int hci_dev_do_close(struct hci_dev *hdev) ...@@ -2374,7 +2391,7 @@ static int hci_dev_do_close(struct hci_dev *hdev)
/* Reset device */ /* Reset device */
skb_queue_purge(&hdev->cmd_q); skb_queue_purge(&hdev->cmd_q);
atomic_set(&hdev->cmd_cnt, 1); atomic_set(&hdev->cmd_cnt, 1);
if (!test_bit(HCI_RAW, &hdev->flags) && if (!test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks) &&
!test_bit(HCI_AUTO_OFF, &hdev->dev_flags) && !test_bit(HCI_AUTO_OFF, &hdev->dev_flags) &&
test_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks)) { test_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks)) {
set_bit(HCI_INIT, &hdev->flags); set_bit(HCI_INIT, &hdev->flags);
...@@ -2405,7 +2422,7 @@ static int hci_dev_do_close(struct hci_dev *hdev) ...@@ -2405,7 +2422,7 @@ static int hci_dev_do_close(struct hci_dev *hdev)
hdev->close(hdev); hdev->close(hdev);
/* Clear flags */ /* Clear flags */
hdev->flags = 0; hdev->flags &= BIT(HCI_RAW);
hdev->dev_flags &= ~HCI_PERSISTENT_MASK; hdev->dev_flags &= ~HCI_PERSISTENT_MASK;
if (!test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) { if (!test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) {
...@@ -2474,6 +2491,11 @@ int hci_dev_reset(__u16 dev) ...@@ -2474,6 +2491,11 @@ int hci_dev_reset(__u16 dev)
goto done; goto done;
} }
if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks)) {
ret = -EOPNOTSUPP;
goto done;
}
/* Drop queues */ /* Drop queues */
skb_queue_purge(&hdev->rx_q); skb_queue_purge(&hdev->rx_q);
skb_queue_purge(&hdev->cmd_q); skb_queue_purge(&hdev->cmd_q);
...@@ -2489,7 +2511,6 @@ int hci_dev_reset(__u16 dev) ...@@ -2489,7 +2511,6 @@ int hci_dev_reset(__u16 dev)
atomic_set(&hdev->cmd_cnt, 1); atomic_set(&hdev->cmd_cnt, 1);
hdev->acl_cnt = 0; hdev->sco_cnt = 0; hdev->le_cnt = 0; hdev->acl_cnt = 0; hdev->sco_cnt = 0; hdev->le_cnt = 0;
if (!test_bit(HCI_RAW, &hdev->flags))
ret = __hci_req_sync(hdev, hci_reset_req, 0, HCI_INIT_TIMEOUT); ret = __hci_req_sync(hdev, hci_reset_req, 0, HCI_INIT_TIMEOUT);
done: done:
...@@ -2512,6 +2533,11 @@ int hci_dev_reset_stat(__u16 dev) ...@@ -2512,6 +2533,11 @@ int hci_dev_reset_stat(__u16 dev)
goto done; goto done;
} }
if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks)) {
ret = -EOPNOTSUPP;
goto done;
}
memset(&hdev->stat, 0, sizeof(struct hci_dev_stats)); memset(&hdev->stat, 0, sizeof(struct hci_dev_stats));
done: done:
...@@ -2537,6 +2563,11 @@ int hci_dev_cmd(unsigned int cmd, void __user *arg) ...@@ -2537,6 +2563,11 @@ int hci_dev_cmd(unsigned int cmd, void __user *arg)
goto done; goto done;
} }
if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks)) {
err = -EOPNOTSUPP;
goto done;
}
if (hdev->dev_type != HCI_BREDR) { if (hdev->dev_type != HCI_BREDR) {
err = -EOPNOTSUPP; err = -EOPNOTSUPP;
goto done; goto done;
...@@ -2760,8 +2791,10 @@ static void hci_power_on(struct work_struct *work) ...@@ -2760,8 +2791,10 @@ static void hci_power_on(struct work_struct *work)
HCI_AUTO_OFF_TIMEOUT); HCI_AUTO_OFF_TIMEOUT);
} }
if (test_and_clear_bit(HCI_SETUP, &hdev->dev_flags)) if (test_and_clear_bit(HCI_SETUP, &hdev->dev_flags)) {
if (!test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
mgmt_index_added(hdev); mgmt_index_added(hdev);
}
} }
static void hci_power_off(struct work_struct *work) static void hci_power_off(struct work_struct *work)
...@@ -3887,6 +3920,13 @@ int hci_register_dev(struct hci_dev *hdev) ...@@ -3887,6 +3920,13 @@ int hci_register_dev(struct hci_dev *hdev)
list_add(&hdev->list, &hci_dev_list); list_add(&hdev->list, &hci_dev_list);
write_unlock(&hci_dev_list_lock); write_unlock(&hci_dev_list_lock);
/* Devices that are marked for raw-only usage need to set
* the HCI_RAW flag to indicate that only user channel is
* supported.
*/
if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
set_bit(HCI_RAW, &hdev->flags);
hci_notify(hdev, HCI_DEV_REG); hci_notify(hdev, HCI_DEV_REG);
hci_dev_hold(hdev); hci_dev_hold(hdev);
...@@ -3929,7 +3969,8 @@ void hci_unregister_dev(struct hci_dev *hdev) ...@@ -3929,7 +3969,8 @@ void hci_unregister_dev(struct hci_dev *hdev)
cancel_work_sync(&hdev->power_on); cancel_work_sync(&hdev->power_on);
if (!test_bit(HCI_INIT, &hdev->flags) && if (!test_bit(HCI_INIT, &hdev->flags) &&
!test_bit(HCI_SETUP, &hdev->dev_flags)) { !test_bit(HCI_SETUP, &hdev->dev_flags) &&
!test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks)) {
hci_dev_lock(hdev); hci_dev_lock(hdev);
mgmt_index_removed(hdev); mgmt_index_removed(hdev);
hci_dev_unlock(hdev); hci_dev_unlock(hdev);
...@@ -4694,7 +4735,7 @@ static inline int __get_blocks(struct hci_dev *hdev, struct sk_buff *skb) ...@@ -4694,7 +4735,7 @@ static inline int __get_blocks(struct hci_dev *hdev, struct sk_buff *skb)
static void __check_timeout(struct hci_dev *hdev, unsigned int cnt) static void __check_timeout(struct hci_dev *hdev, unsigned int cnt)
{ {
if (!test_bit(HCI_RAW, &hdev->flags)) { if (!test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks)) {
/* ACL tx timeout must be longer than maximum /* ACL tx timeout must be longer than maximum
* link supervision timeout (40.9 seconds) */ * link supervision timeout (40.9 seconds) */
if (!cnt && time_after(jiffies, hdev->acl_last_tx + if (!cnt && time_after(jiffies, hdev->acl_last_tx +
...@@ -4877,7 +4918,7 @@ static void hci_sched_le(struct hci_dev *hdev) ...@@ -4877,7 +4918,7 @@ static void hci_sched_le(struct hci_dev *hdev)
if (!hci_conn_num(hdev, LE_LINK)) if (!hci_conn_num(hdev, LE_LINK))
return; return;
if (!test_bit(HCI_RAW, &hdev->flags)) { if (!test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks)) {
/* LE tx timeout must be longer than maximum /* LE tx timeout must be longer than maximum
* link supervision timeout (40.9 seconds) */ * link supervision timeout (40.9 seconds) */
if (!hdev->le_cnt && hdev->le_pkts && if (!hdev->le_cnt && hdev->le_pkts &&
...@@ -5122,8 +5163,7 @@ static void hci_rx_work(struct work_struct *work) ...@@ -5122,8 +5163,7 @@ static void hci_rx_work(struct work_struct *work)
hci_send_to_sock(hdev, skb); hci_send_to_sock(hdev, skb);
} }
if (test_bit(HCI_RAW, &hdev->flags) || if (test_bit(HCI_USER_CHANNEL, &hdev->dev_flags)) {
test_bit(HCI_USER_CHANNEL, &hdev->dev_flags)) {
kfree_skb(skb); kfree_skb(skb);
continue; continue;
} }
......
...@@ -453,6 +453,7 @@ static int hci_sock_release(struct socket *sock) ...@@ -453,6 +453,7 @@ static int hci_sock_release(struct socket *sock)
if (hdev) { if (hdev) {
if (hci_pi(sk)->channel == HCI_CHANNEL_USER) { if (hci_pi(sk)->channel == HCI_CHANNEL_USER) {
if (!test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
mgmt_index_added(hdev); mgmt_index_added(hdev);
clear_bit(HCI_USER_CHANNEL, &hdev->dev_flags); clear_bit(HCI_USER_CHANNEL, &hdev->dev_flags);
hci_dev_close(hdev->id); hci_dev_close(hdev->id);
...@@ -517,6 +518,9 @@ static int hci_sock_bound_ioctl(struct sock *sk, unsigned int cmd, ...@@ -517,6 +518,9 @@ static int hci_sock_bound_ioctl(struct sock *sk, unsigned int cmd,
if (test_bit(HCI_USER_CHANNEL, &hdev->dev_flags)) if (test_bit(HCI_USER_CHANNEL, &hdev->dev_flags))
return -EBUSY; return -EBUSY;
if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
return -EOPNOTSUPP;
if (hdev->dev_type != HCI_BREDR) if (hdev->dev_type != HCI_BREDR)
return -EOPNOTSUPP; return -EOPNOTSUPP;
...@@ -702,11 +706,13 @@ static int hci_sock_bind(struct socket *sock, struct sockaddr *addr, ...@@ -702,11 +706,13 @@ static int hci_sock_bind(struct socket *sock, struct sockaddr *addr,
goto done; goto done;
} }
if (!test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
mgmt_index_removed(hdev); mgmt_index_removed(hdev);
err = hci_dev_open(hdev->id); err = hci_dev_open(hdev->id);
if (err) { if (err) {
clear_bit(HCI_USER_CHANNEL, &hdev->dev_flags); clear_bit(HCI_USER_CHANNEL, &hdev->dev_flags);
if (!test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
mgmt_index_added(hdev); mgmt_index_added(hdev);
hci_dev_put(hdev); hci_dev_put(hdev);
goto done; goto done;
...@@ -960,7 +966,7 @@ static int hci_sock_sendmsg(struct kiocb *iocb, struct socket *sock, ...@@ -960,7 +966,7 @@ static int hci_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
goto drop; goto drop;
} }
if (test_bit(HCI_RAW, &hdev->flags) || (ogf == 0x3f)) { if (ogf == 0x3f) {
skb_queue_tail(&hdev->raw_q, skb); skb_queue_tail(&hdev->raw_q, skb);
queue_work(hdev->workqueue, &hdev->tx_work); queue_work(hdev->workqueue, &hdev->tx_work);
} else { } else {
......
...@@ -347,6 +347,9 @@ static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data, ...@@ -347,6 +347,9 @@ static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data,
if (test_bit(HCI_USER_CHANNEL, &d->dev_flags)) if (test_bit(HCI_USER_CHANNEL, &d->dev_flags))
continue; continue;
if (test_bit(HCI_QUIRK_RAW_DEVICE, &d->quirks))
continue;
if (d->dev_type == HCI_BREDR) { if (d->dev_type == HCI_BREDR) {
rp->index[count++] = cpu_to_le16(d->id); rp->index[count++] = cpu_to_le16(d->id);
BT_DBG("Added hci%u", d->id); BT_DBG("Added hci%u", d->id);
...@@ -5066,7 +5069,8 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) ...@@ -5066,7 +5069,8 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
} }
if (test_bit(HCI_SETUP, &hdev->dev_flags) || if (test_bit(HCI_SETUP, &hdev->dev_flags) ||
test_bit(HCI_USER_CHANNEL, &hdev->dev_flags)) { test_bit(HCI_USER_CHANNEL, &hdev->dev_flags) ||
test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks)) {
err = cmd_status(sk, index, opcode, err = cmd_status(sk, index, opcode,
MGMT_STATUS_INVALID_INDEX); MGMT_STATUS_INVALID_INDEX);
goto done; goto done;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment