Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Antti Julku and committed by
Gustavo F. Padovan
5e762444 c908df36

+92 -34
+2
include/net/bluetooth/hci_core.h
··· 873 873 u8 *eir); 874 874 int mgmt_remote_name(u16 index, bdaddr_t *bdaddr, u8 *name); 875 875 int mgmt_discovering(u16 index, u8 discovering); 876 + int mgmt_device_blocked(u16 index, bdaddr_t *bdaddr); 877 + int mgmt_device_unblocked(u16 index, bdaddr_t *bdaddr); 876 878 877 879 /* HCI info for socket */ 878 880 #define hci_pi(sk) ((struct hci_pinfo *) sk)
+10
include/net/bluetooth/mgmt.h
··· 307 307 } __packed; 308 308 309 309 #define MGMT_EV_DISCOVERING 0x0014 310 + 311 + #define MGMT_EV_DEVICE_BLOCKED 0x0015 312 + struct mgmt_ev_device_blocked { 313 + bdaddr_t bdaddr; 314 + } __packed; 315 + 316 + #define MGMT_EV_DEVICE_UNBLOCKED 0x0016 317 + struct mgmt_ev_device_unblocked { 318 + bdaddr_t bdaddr; 319 + } __packed;
+8 -26
net/bluetooth/hci_core.c
··· 1312 1312 int hci_blacklist_add(struct hci_dev *hdev, bdaddr_t *bdaddr) 1313 1313 { 1314 1314 struct bdaddr_list *entry; 1315 - int err; 1316 1315 1317 1316 if (bacmp(bdaddr, BDADDR_ANY) == 0) 1318 1317 return -EBADF; 1319 1318 1320 - hci_dev_lock_bh(hdev); 1321 - 1322 - if (hci_blacklist_lookup(hdev, bdaddr)) { 1323 - err = -EEXIST; 1324 - goto err; 1325 - } 1319 + if (hci_blacklist_lookup(hdev, bdaddr)) 1320 + return -EEXIST; 1326 1321 1327 1322 entry = kzalloc(sizeof(struct bdaddr_list), GFP_KERNEL); 1328 - if (!entry) { 1329 - err = -ENOMEM; 1330 - goto err; 1331 - } 1323 + if (!entry) 1324 + return -ENOMEM; 1332 1325 1333 1326 bacpy(&entry->bdaddr, bdaddr); 1334 1327 1335 1328 list_add(&entry->list, &hdev->blacklist); 1336 1329 1337 - err = 0; 1338 - 1339 - err: 1340 - hci_dev_unlock_bh(hdev); 1341 - return err; 1330 + return mgmt_device_blocked(hdev->id, bdaddr); 1342 1331 } 1343 1332 1344 1333 int hci_blacklist_del(struct hci_dev *hdev, bdaddr_t *bdaddr) 1345 1334 { 1346 1335 struct bdaddr_list *entry; 1347 - int err = 0; 1348 - 1349 - hci_dev_lock_bh(hdev); 1350 1336 1351 1337 if (bacmp(bdaddr, BDADDR_ANY) == 0) { 1352 - hci_blacklist_clear(hdev); 1353 - goto done; 1338 + return hci_blacklist_clear(hdev); 1354 1339 } 1355 1340 1356 1341 entry = hci_blacklist_lookup(hdev, bdaddr); 1357 1342 if (!entry) { 1358 - err = -ENOENT; 1359 - goto done; 1343 + return -ENOENT; 1360 1344 } 1361 1345 1362 1346 list_del(&entry->list); 1363 1347 kfree(entry); 1364 1348 1365 - done: 1366 - hci_dev_unlock_bh(hdev); 1367 - return err; 1349 + return mgmt_device_unblocked(hdev->id, bdaddr); 1368 1350 } 1369 1351 1370 1352 static void hci_clear_adv_cache(unsigned long arg)
+16 -2
net/bluetooth/hci_sock.c
··· 183 183 static int hci_sock_blacklist_add(struct hci_dev *hdev, void __user *arg) 184 184 { 185 185 bdaddr_t bdaddr; 186 + int err; 186 187 187 188 if (copy_from_user(&bdaddr, arg, sizeof(bdaddr))) 188 189 return -EFAULT; 189 190 190 - return hci_blacklist_add(hdev, &bdaddr); 191 + hci_dev_lock_bh(hdev); 192 + 193 + err = hci_blacklist_add(hdev, &bdaddr); 194 + 195 + hci_dev_unlock_bh(hdev); 196 + 197 + return err; 191 198 } 192 199 193 200 static int hci_sock_blacklist_del(struct hci_dev *hdev, void __user *arg) 194 201 { 195 202 bdaddr_t bdaddr; 203 + int err; 196 204 197 205 if (copy_from_user(&bdaddr, arg, sizeof(bdaddr))) 198 206 return -EFAULT; 199 207 200 - return hci_blacklist_del(hdev, &bdaddr); 208 + hci_dev_lock_bh(hdev); 209 + 210 + err = hci_blacklist_del(hdev, &bdaddr); 211 + 212 + hci_dev_unlock_bh(hdev); 213 + 214 + return err; 201 215 } 202 216 203 217 /* Ioctls that require bound socket */
+56 -6
net/bluetooth/mgmt.c
··· 1698 1698 u16 len) 1699 1699 { 1700 1700 struct hci_dev *hdev; 1701 - struct mgmt_cp_block_device *cp; 1701 + struct pending_cmd *cmd; 1702 + struct mgmt_cp_block_device *cp = (void *) data; 1702 1703 int err; 1703 1704 1704 1705 BT_DBG("hci%u", index); 1705 - 1706 - cp = (void *) data; 1707 1706 1708 1707 if (len != sizeof(*cp)) 1709 1708 return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE, ··· 1713 1714 return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE, 1714 1715 ENODEV); 1715 1716 1717 + hci_dev_lock_bh(hdev); 1718 + 1719 + cmd = mgmt_pending_add(sk, MGMT_OP_BLOCK_DEVICE, index, NULL, 0); 1720 + if (!cmd) { 1721 + err = -ENOMEM; 1722 + goto failed; 1723 + } 1724 + 1716 1725 err = hci_blacklist_add(hdev, &cp->bdaddr); 1717 1726 1718 1727 if (err < 0) ··· 1728 1721 else 1729 1722 err = cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE, 1730 1723 NULL, 0); 1724 + 1725 + mgmt_pending_remove(cmd); 1726 + 1727 + failed: 1728 + hci_dev_unlock_bh(hdev); 1731 1729 hci_dev_put(hdev); 1732 1730 1733 1731 return err; ··· 1742 1730 u16 len) 1743 1731 { 1744 1732 struct hci_dev *hdev; 1745 - struct mgmt_cp_unblock_device *cp; 1733 + struct pending_cmd *cmd; 1734 + struct mgmt_cp_unblock_device *cp = (void *) data; 1746 1735 int err; 1747 1736 1748 1737 BT_DBG("hci%u", index); 1749 - 1750 - cp = (void *) data; 1751 1738 1752 1739 if (len != sizeof(*cp)) 1753 1740 return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE, ··· 1757 1746 return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE, 1758 1747 ENODEV); 1759 1748 1749 + hci_dev_lock_bh(hdev); 1750 + 1751 + cmd = mgmt_pending_add(sk, MGMT_OP_UNBLOCK_DEVICE, index, NULL, 0); 1752 + if (!cmd) { 1753 + err = -ENOMEM; 1754 + goto failed; 1755 + } 1756 + 1760 1757 err = hci_blacklist_del(hdev, &cp->bdaddr); 1761 1758 1762 1759 if (err < 0) ··· 1772 1753 else 1773 1754 err = cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE, 1774 1755 NULL, 0); 1756 + 1757 + mgmt_pending_remove(cmd); 1758 + 1759 + failed: 1760 + hci_dev_unlock_bh(hdev); 1775 1761 hci_dev_put(hdev); 1776 1762 1777 1763 return err; ··· 2379 2355 { 2380 2356 return mgmt_event(MGMT_EV_DISCOVERING, index, &discovering, 2381 2357 sizeof(discovering), NULL); 2358 + } 2359 + 2360 + int mgmt_device_blocked(u16 index, bdaddr_t *bdaddr) 2361 + { 2362 + struct pending_cmd *cmd; 2363 + struct mgmt_ev_device_blocked ev; 2364 + 2365 + cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, index); 2366 + 2367 + bacpy(&ev.bdaddr, bdaddr); 2368 + 2369 + return mgmt_event(MGMT_EV_DEVICE_BLOCKED, index, &ev, sizeof(ev), 2370 + cmd ? cmd->sk : NULL); 2371 + } 2372 + 2373 + int mgmt_device_unblocked(u16 index, bdaddr_t *bdaddr) 2374 + { 2375 + struct pending_cmd *cmd; 2376 + struct mgmt_ev_device_unblocked ev; 2377 + 2378 + cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, index); 2379 + 2380 + bacpy(&ev.bdaddr, bdaddr); 2381 + 2382 + return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, index, &ev, sizeof(ev), 2383 + cmd ? cmd->sk : NULL); 2382 2384 }