Bluetooth: Add mgmt events for blacklisting
Add management interface events for blocking/unblocking a device. Sender of the block device command gets cmd complete and other mgmt sockets get the event. Event is also sent to mgmt sockets when blocking is done with ioctl, e.g when blocking a device with hciconfig. This makes it possible for bluetoothd to track status of blocked devices when a third party block or unblocks a device. Event sending is handled in mgmt_device_blocked function which gets called from hci_blacklist_add in hci_core.c. A pending command is added in mgmt_block_device, so that it can found when sending the event - the event is not sent to the socket from which the pending command came. Locks were moved out from hci_core.c to hci_sock.c and mgmt.c, because locking is needed also for mgmt_pending_add in mgmt.c. Signed-off-by: Antti Julku <antti.julku@nokia.com> Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi>
This commit is contained in:
parent
c908df362c
commit
5e762444b0
|
@ -873,6 +873,8 @@ int mgmt_device_found(u16 index, bdaddr_t *bdaddr, u8 *dev_class, s8 rssi,
|
||||||
u8 *eir);
|
u8 *eir);
|
||||||
int mgmt_remote_name(u16 index, bdaddr_t *bdaddr, u8 *name);
|
int mgmt_remote_name(u16 index, bdaddr_t *bdaddr, u8 *name);
|
||||||
int mgmt_discovering(u16 index, u8 discovering);
|
int mgmt_discovering(u16 index, u8 discovering);
|
||||||
|
int mgmt_device_blocked(u16 index, bdaddr_t *bdaddr);
|
||||||
|
int mgmt_device_unblocked(u16 index, bdaddr_t *bdaddr);
|
||||||
|
|
||||||
/* HCI info for socket */
|
/* HCI info for socket */
|
||||||
#define hci_pi(sk) ((struct hci_pinfo *) sk)
|
#define hci_pi(sk) ((struct hci_pinfo *) sk)
|
||||||
|
|
|
@ -307,3 +307,13 @@ struct mgmt_ev_remote_name {
|
||||||
} __packed;
|
} __packed;
|
||||||
|
|
||||||
#define MGMT_EV_DISCOVERING 0x0014
|
#define MGMT_EV_DISCOVERING 0x0014
|
||||||
|
|
||||||
|
#define MGMT_EV_DEVICE_BLOCKED 0x0015
|
||||||
|
struct mgmt_ev_device_blocked {
|
||||||
|
bdaddr_t bdaddr;
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
#define MGMT_EV_DEVICE_UNBLOCKED 0x0016
|
||||||
|
struct mgmt_ev_device_unblocked {
|
||||||
|
bdaddr_t bdaddr;
|
||||||
|
} __packed;
|
||||||
|
|
|
@ -1312,59 +1312,41 @@ int hci_blacklist_clear(struct hci_dev *hdev)
|
||||||
int hci_blacklist_add(struct hci_dev *hdev, bdaddr_t *bdaddr)
|
int hci_blacklist_add(struct hci_dev *hdev, bdaddr_t *bdaddr)
|
||||||
{
|
{
|
||||||
struct bdaddr_list *entry;
|
struct bdaddr_list *entry;
|
||||||
int err;
|
|
||||||
|
|
||||||
if (bacmp(bdaddr, BDADDR_ANY) == 0)
|
if (bacmp(bdaddr, BDADDR_ANY) == 0)
|
||||||
return -EBADF;
|
return -EBADF;
|
||||||
|
|
||||||
hci_dev_lock_bh(hdev);
|
if (hci_blacklist_lookup(hdev, bdaddr))
|
||||||
|
return -EEXIST;
|
||||||
if (hci_blacklist_lookup(hdev, bdaddr)) {
|
|
||||||
err = -EEXIST;
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
|
|
||||||
entry = kzalloc(sizeof(struct bdaddr_list), GFP_KERNEL);
|
entry = kzalloc(sizeof(struct bdaddr_list), GFP_KERNEL);
|
||||||
if (!entry) {
|
if (!entry)
|
||||||
err = -ENOMEM;
|
return -ENOMEM;
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
|
|
||||||
bacpy(&entry->bdaddr, bdaddr);
|
bacpy(&entry->bdaddr, bdaddr);
|
||||||
|
|
||||||
list_add(&entry->list, &hdev->blacklist);
|
list_add(&entry->list, &hdev->blacklist);
|
||||||
|
|
||||||
err = 0;
|
return mgmt_device_blocked(hdev->id, bdaddr);
|
||||||
|
|
||||||
err:
|
|
||||||
hci_dev_unlock_bh(hdev);
|
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int hci_blacklist_del(struct hci_dev *hdev, bdaddr_t *bdaddr)
|
int hci_blacklist_del(struct hci_dev *hdev, bdaddr_t *bdaddr)
|
||||||
{
|
{
|
||||||
struct bdaddr_list *entry;
|
struct bdaddr_list *entry;
|
||||||
int err = 0;
|
|
||||||
|
|
||||||
hci_dev_lock_bh(hdev);
|
|
||||||
|
|
||||||
if (bacmp(bdaddr, BDADDR_ANY) == 0) {
|
if (bacmp(bdaddr, BDADDR_ANY) == 0) {
|
||||||
hci_blacklist_clear(hdev);
|
return hci_blacklist_clear(hdev);
|
||||||
goto done;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
entry = hci_blacklist_lookup(hdev, bdaddr);
|
entry = hci_blacklist_lookup(hdev, bdaddr);
|
||||||
if (!entry) {
|
if (!entry) {
|
||||||
err = -ENOENT;
|
return -ENOENT;
|
||||||
goto done;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
list_del(&entry->list);
|
list_del(&entry->list);
|
||||||
kfree(entry);
|
kfree(entry);
|
||||||
|
|
||||||
done:
|
return mgmt_device_unblocked(hdev->id, bdaddr);
|
||||||
hci_dev_unlock_bh(hdev);
|
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void hci_clear_adv_cache(unsigned long arg)
|
static void hci_clear_adv_cache(unsigned long arg)
|
||||||
|
|
|
@ -183,21 +183,35 @@ static int hci_sock_release(struct socket *sock)
|
||||||
static int hci_sock_blacklist_add(struct hci_dev *hdev, void __user *arg)
|
static int hci_sock_blacklist_add(struct hci_dev *hdev, void __user *arg)
|
||||||
{
|
{
|
||||||
bdaddr_t bdaddr;
|
bdaddr_t bdaddr;
|
||||||
|
int err;
|
||||||
|
|
||||||
if (copy_from_user(&bdaddr, arg, sizeof(bdaddr)))
|
if (copy_from_user(&bdaddr, arg, sizeof(bdaddr)))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
|
|
||||||
return hci_blacklist_add(hdev, &bdaddr);
|
hci_dev_lock_bh(hdev);
|
||||||
|
|
||||||
|
err = hci_blacklist_add(hdev, &bdaddr);
|
||||||
|
|
||||||
|
hci_dev_unlock_bh(hdev);
|
||||||
|
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int hci_sock_blacklist_del(struct hci_dev *hdev, void __user *arg)
|
static int hci_sock_blacklist_del(struct hci_dev *hdev, void __user *arg)
|
||||||
{
|
{
|
||||||
bdaddr_t bdaddr;
|
bdaddr_t bdaddr;
|
||||||
|
int err;
|
||||||
|
|
||||||
if (copy_from_user(&bdaddr, arg, sizeof(bdaddr)))
|
if (copy_from_user(&bdaddr, arg, sizeof(bdaddr)))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
|
|
||||||
return hci_blacklist_del(hdev, &bdaddr);
|
hci_dev_lock_bh(hdev);
|
||||||
|
|
||||||
|
err = hci_blacklist_del(hdev, &bdaddr);
|
||||||
|
|
||||||
|
hci_dev_unlock_bh(hdev);
|
||||||
|
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Ioctls that require bound socket */
|
/* Ioctls that require bound socket */
|
||||||
|
|
|
@ -1698,13 +1698,12 @@ static int block_device(struct sock *sk, u16 index, unsigned char *data,
|
||||||
u16 len)
|
u16 len)
|
||||||
{
|
{
|
||||||
struct hci_dev *hdev;
|
struct hci_dev *hdev;
|
||||||
struct mgmt_cp_block_device *cp;
|
struct pending_cmd *cmd;
|
||||||
|
struct mgmt_cp_block_device *cp = (void *) data;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
BT_DBG("hci%u", index);
|
BT_DBG("hci%u", index);
|
||||||
|
|
||||||
cp = (void *) data;
|
|
||||||
|
|
||||||
if (len != sizeof(*cp))
|
if (len != sizeof(*cp))
|
||||||
return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
|
return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
|
||||||
EINVAL);
|
EINVAL);
|
||||||
|
@ -1714,6 +1713,14 @@ static int block_device(struct sock *sk, u16 index, unsigned char *data,
|
||||||
return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
|
return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
|
||||||
ENODEV);
|
ENODEV);
|
||||||
|
|
||||||
|
hci_dev_lock_bh(hdev);
|
||||||
|
|
||||||
|
cmd = mgmt_pending_add(sk, MGMT_OP_BLOCK_DEVICE, index, NULL, 0);
|
||||||
|
if (!cmd) {
|
||||||
|
err = -ENOMEM;
|
||||||
|
goto failed;
|
||||||
|
}
|
||||||
|
|
||||||
err = hci_blacklist_add(hdev, &cp->bdaddr);
|
err = hci_blacklist_add(hdev, &cp->bdaddr);
|
||||||
|
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
|
@ -1721,6 +1728,11 @@ static int block_device(struct sock *sk, u16 index, unsigned char *data,
|
||||||
else
|
else
|
||||||
err = cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE,
|
err = cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE,
|
||||||
NULL, 0);
|
NULL, 0);
|
||||||
|
|
||||||
|
mgmt_pending_remove(cmd);
|
||||||
|
|
||||||
|
failed:
|
||||||
|
hci_dev_unlock_bh(hdev);
|
||||||
hci_dev_put(hdev);
|
hci_dev_put(hdev);
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
|
@ -1730,13 +1742,12 @@ static int unblock_device(struct sock *sk, u16 index, unsigned char *data,
|
||||||
u16 len)
|
u16 len)
|
||||||
{
|
{
|
||||||
struct hci_dev *hdev;
|
struct hci_dev *hdev;
|
||||||
struct mgmt_cp_unblock_device *cp;
|
struct pending_cmd *cmd;
|
||||||
|
struct mgmt_cp_unblock_device *cp = (void *) data;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
BT_DBG("hci%u", index);
|
BT_DBG("hci%u", index);
|
||||||
|
|
||||||
cp = (void *) data;
|
|
||||||
|
|
||||||
if (len != sizeof(*cp))
|
if (len != sizeof(*cp))
|
||||||
return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
|
return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
|
||||||
EINVAL);
|
EINVAL);
|
||||||
|
@ -1746,6 +1757,14 @@ static int unblock_device(struct sock *sk, u16 index, unsigned char *data,
|
||||||
return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
|
return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
|
||||||
ENODEV);
|
ENODEV);
|
||||||
|
|
||||||
|
hci_dev_lock_bh(hdev);
|
||||||
|
|
||||||
|
cmd = mgmt_pending_add(sk, MGMT_OP_UNBLOCK_DEVICE, index, NULL, 0);
|
||||||
|
if (!cmd) {
|
||||||
|
err = -ENOMEM;
|
||||||
|
goto failed;
|
||||||
|
}
|
||||||
|
|
||||||
err = hci_blacklist_del(hdev, &cp->bdaddr);
|
err = hci_blacklist_del(hdev, &cp->bdaddr);
|
||||||
|
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
|
@ -1753,6 +1772,11 @@ static int unblock_device(struct sock *sk, u16 index, unsigned char *data,
|
||||||
else
|
else
|
||||||
err = cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE,
|
err = cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE,
|
||||||
NULL, 0);
|
NULL, 0);
|
||||||
|
|
||||||
|
mgmt_pending_remove(cmd);
|
||||||
|
|
||||||
|
failed:
|
||||||
|
hci_dev_unlock_bh(hdev);
|
||||||
hci_dev_put(hdev);
|
hci_dev_put(hdev);
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
|
@ -2356,3 +2380,29 @@ int mgmt_discovering(u16 index, u8 discovering)
|
||||||
return mgmt_event(MGMT_EV_DISCOVERING, index, &discovering,
|
return mgmt_event(MGMT_EV_DISCOVERING, index, &discovering,
|
||||||
sizeof(discovering), NULL);
|
sizeof(discovering), NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int mgmt_device_blocked(u16 index, bdaddr_t *bdaddr)
|
||||||
|
{
|
||||||
|
struct pending_cmd *cmd;
|
||||||
|
struct mgmt_ev_device_blocked ev;
|
||||||
|
|
||||||
|
cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, index);
|
||||||
|
|
||||||
|
bacpy(&ev.bdaddr, bdaddr);
|
||||||
|
|
||||||
|
return mgmt_event(MGMT_EV_DEVICE_BLOCKED, index, &ev, sizeof(ev),
|
||||||
|
cmd ? cmd->sk : NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
int mgmt_device_unblocked(u16 index, bdaddr_t *bdaddr)
|
||||||
|
{
|
||||||
|
struct pending_cmd *cmd;
|
||||||
|
struct mgmt_ev_device_unblocked ev;
|
||||||
|
|
||||||
|
cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, index);
|
||||||
|
|
||||||
|
bacpy(&ev.bdaddr, bdaddr);
|
||||||
|
|
||||||
|
return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, index, &ev, sizeof(ev),
|
||||||
|
cmd ? cmd->sk : NULL);
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue