diff options
author | Johan Hedberg <johan.hedberg@intel.com> | 2014-07-09 05:59:14 -0400 |
---|---|---|
committer | Marcel Holtmann <marcel@holtmann.org> | 2014-07-09 06:25:27 -0400 |
commit | 6659358efe617bb46237e62f7303c76e10568d70 (patch) | |
tree | cc4f21038000dd5a617580a7adc542a91c1c592c /net | |
parent | dcc36c16c2f1c9800146c8416ee5a4c3dc974623 (diff) |
Bluetooth: Introduce a whitelist for BR/EDR devices
This patch extends the Add/Remove device commands by letting user space
pass BR/EDR addresses to them. The resulting entries get stored in a new
hdev->whitelist list. The idea is that we can now selectively accept
connections from devices in the list even though HCI_CONNECTABLE is not
set (the actual implementation of this is coming in a subsequent patch).
Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
Diffstat (limited to 'net')
-rw-r--r-- | net/bluetooth/hci_core.c | 29 | ||||
-rw-r--r-- | net/bluetooth/mgmt.c | 46 |
2 files changed, 73 insertions, 2 deletions
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 705f8df7af96..728a6ee471ea 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c | |||
@@ -191,6 +191,31 @@ static const struct file_operations blacklist_fops = { | |||
191 | .release = single_release, | 191 | .release = single_release, |
192 | }; | 192 | }; |
193 | 193 | ||
194 | static int whitelist_show(struct seq_file *f, void *p) | ||
195 | { | ||
196 | struct hci_dev *hdev = f->private; | ||
197 | struct bdaddr_list *b; | ||
198 | |||
199 | hci_dev_lock(hdev); | ||
200 | list_for_each_entry(b, &hdev->whitelist, list) | ||
201 | seq_printf(f, "%pMR (type %u)\n", &b->bdaddr, b->bdaddr_type); | ||
202 | hci_dev_unlock(hdev); | ||
203 | |||
204 | return 0; | ||
205 | } | ||
206 | |||
207 | static int whitelist_open(struct inode *inode, struct file *file) | ||
208 | { | ||
209 | return single_open(file, whitelist_show, inode->i_private); | ||
210 | } | ||
211 | |||
212 | static const struct file_operations whitelist_fops = { | ||
213 | .open = whitelist_open, | ||
214 | .read = seq_read, | ||
215 | .llseek = seq_lseek, | ||
216 | .release = single_release, | ||
217 | }; | ||
218 | |||
194 | static int uuids_show(struct seq_file *f, void *p) | 219 | static int uuids_show(struct seq_file *f, void *p) |
195 | { | 220 | { |
196 | struct hci_dev *hdev = f->private; | 221 | struct hci_dev *hdev = f->private; |
@@ -1707,6 +1732,8 @@ static int __hci_init(struct hci_dev *hdev) | |||
1707 | debugfs_create_u16("hci_revision", 0444, hdev->debugfs, &hdev->hci_rev); | 1732 | debugfs_create_u16("hci_revision", 0444, hdev->debugfs, &hdev->hci_rev); |
1708 | debugfs_create_file("blacklist", 0444, hdev->debugfs, hdev, | 1733 | debugfs_create_file("blacklist", 0444, hdev->debugfs, hdev, |
1709 | &blacklist_fops); | 1734 | &blacklist_fops); |
1735 | debugfs_create_file("whitelist", 0444, hdev->debugfs, hdev, | ||
1736 | &whitelist_fops); | ||
1710 | debugfs_create_file("uuids", 0444, hdev->debugfs, hdev, &uuids_fops); | 1737 | debugfs_create_file("uuids", 0444, hdev->debugfs, hdev, &uuids_fops); |
1711 | 1738 | ||
1712 | debugfs_create_file("conn_info_min_age", 0644, hdev->debugfs, hdev, | 1739 | debugfs_create_file("conn_info_min_age", 0644, hdev->debugfs, hdev, |
@@ -3825,6 +3852,7 @@ struct hci_dev *hci_alloc_dev(void) | |||
3825 | 3852 | ||
3826 | INIT_LIST_HEAD(&hdev->mgmt_pending); | 3853 | INIT_LIST_HEAD(&hdev->mgmt_pending); |
3827 | INIT_LIST_HEAD(&hdev->blacklist); | 3854 | INIT_LIST_HEAD(&hdev->blacklist); |
3855 | INIT_LIST_HEAD(&hdev->whitelist); | ||
3828 | INIT_LIST_HEAD(&hdev->uuids); | 3856 | INIT_LIST_HEAD(&hdev->uuids); |
3829 | INIT_LIST_HEAD(&hdev->link_keys); | 3857 | INIT_LIST_HEAD(&hdev->link_keys); |
3830 | INIT_LIST_HEAD(&hdev->long_term_keys); | 3858 | INIT_LIST_HEAD(&hdev->long_term_keys); |
@@ -4036,6 +4064,7 @@ void hci_unregister_dev(struct hci_dev *hdev) | |||
4036 | 4064 | ||
4037 | hci_dev_lock(hdev); | 4065 | hci_dev_lock(hdev); |
4038 | hci_bdaddr_list_clear(&hdev->blacklist); | 4066 | hci_bdaddr_list_clear(&hdev->blacklist); |
4067 | hci_bdaddr_list_clear(&hdev->whitelist); | ||
4039 | hci_uuids_clear(hdev); | 4068 | hci_uuids_clear(hdev); |
4040 | hci_link_keys_clear(hdev); | 4069 | hci_link_keys_clear(hdev); |
4041 | hci_smp_ltks_clear(hdev); | 4070 | hci_smp_ltks_clear(hdev); |
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 592e73eea76d..49581e99685c 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c | |||
@@ -5219,7 +5219,7 @@ static int add_device(struct sock *sk, struct hci_dev *hdev, | |||
5219 | 5219 | ||
5220 | BT_DBG("%s", hdev->name); | 5220 | BT_DBG("%s", hdev->name); |
5221 | 5221 | ||
5222 | if (!bdaddr_type_is_le(cp->addr.type) || | 5222 | if (!bdaddr_type_is_valid(cp->addr.type) || |
5223 | !bacmp(&cp->addr.bdaddr, BDADDR_ANY)) | 5223 | !bacmp(&cp->addr.bdaddr, BDADDR_ANY)) |
5224 | return cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE, | 5224 | return cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE, |
5225 | MGMT_STATUS_INVALID_PARAMS, | 5225 | MGMT_STATUS_INVALID_PARAMS, |
@@ -5232,6 +5232,22 @@ static int add_device(struct sock *sk, struct hci_dev *hdev, | |||
5232 | 5232 | ||
5233 | hci_dev_lock(hdev); | 5233 | hci_dev_lock(hdev); |
5234 | 5234 | ||
5235 | if (cp->addr.type == BDADDR_BREDR) { | ||
5236 | /* Only "connect" action supported for now */ | ||
5237 | if (cp->action != 0x01) { | ||
5238 | err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE, | ||
5239 | MGMT_STATUS_INVALID_PARAMS, | ||
5240 | &cp->addr, sizeof(cp->addr)); | ||
5241 | goto unlock; | ||
5242 | } | ||
5243 | |||
5244 | err = hci_bdaddr_list_add(&hdev->whitelist, &cp->addr.bdaddr, | ||
5245 | cp->addr.type); | ||
5246 | if (err) | ||
5247 | goto unlock; | ||
5248 | goto added; | ||
5249 | } | ||
5250 | |||
5235 | if (cp->addr.type == BDADDR_LE_PUBLIC) | 5251 | if (cp->addr.type == BDADDR_LE_PUBLIC) |
5236 | addr_type = ADDR_LE_DEV_PUBLIC; | 5252 | addr_type = ADDR_LE_DEV_PUBLIC; |
5237 | else | 5253 | else |
@@ -5253,6 +5269,7 @@ static int add_device(struct sock *sk, struct hci_dev *hdev, | |||
5253 | goto unlock; | 5269 | goto unlock; |
5254 | } | 5270 | } |
5255 | 5271 | ||
5272 | added: | ||
5256 | device_added(sk, hdev, &cp->addr.bdaddr, cp->addr.type, cp->action); | 5273 | device_added(sk, hdev, &cp->addr.bdaddr, cp->addr.type, cp->action); |
5257 | 5274 | ||
5258 | err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE, | 5275 | err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE, |
@@ -5288,13 +5305,30 @@ static int remove_device(struct sock *sk, struct hci_dev *hdev, | |||
5288 | struct hci_conn_params *params; | 5305 | struct hci_conn_params *params; |
5289 | u8 addr_type; | 5306 | u8 addr_type; |
5290 | 5307 | ||
5291 | if (!bdaddr_type_is_le(cp->addr.type)) { | 5308 | if (!bdaddr_type_is_valid(cp->addr.type)) { |
5292 | err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_DEVICE, | 5309 | err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_DEVICE, |
5293 | MGMT_STATUS_INVALID_PARAMS, | 5310 | MGMT_STATUS_INVALID_PARAMS, |
5294 | &cp->addr, sizeof(cp->addr)); | 5311 | &cp->addr, sizeof(cp->addr)); |
5295 | goto unlock; | 5312 | goto unlock; |
5296 | } | 5313 | } |
5297 | 5314 | ||
5315 | if (cp->addr.type == BDADDR_BREDR) { | ||
5316 | err = hci_bdaddr_list_del(&hdev->whitelist, | ||
5317 | &cp->addr.bdaddr, | ||
5318 | cp->addr.type); | ||
5319 | if (err) { | ||
5320 | err = cmd_complete(sk, hdev->id, | ||
5321 | MGMT_OP_REMOVE_DEVICE, | ||
5322 | MGMT_STATUS_INVALID_PARAMS, | ||
5323 | &cp->addr, sizeof(cp->addr)); | ||
5324 | goto unlock; | ||
5325 | } | ||
5326 | |||
5327 | device_removed(sk, hdev, &cp->addr.bdaddr, | ||
5328 | cp->addr.type); | ||
5329 | goto complete; | ||
5330 | } | ||
5331 | |||
5298 | if (cp->addr.type == BDADDR_LE_PUBLIC) | 5332 | if (cp->addr.type == BDADDR_LE_PUBLIC) |
5299 | addr_type = ADDR_LE_DEV_PUBLIC; | 5333 | addr_type = ADDR_LE_DEV_PUBLIC; |
5300 | else | 5334 | else |
@@ -5324,6 +5358,7 @@ static int remove_device(struct sock *sk, struct hci_dev *hdev, | |||
5324 | device_removed(sk, hdev, &cp->addr.bdaddr, cp->addr.type); | 5358 | device_removed(sk, hdev, &cp->addr.bdaddr, cp->addr.type); |
5325 | } else { | 5359 | } else { |
5326 | struct hci_conn_params *p, *tmp; | 5360 | struct hci_conn_params *p, *tmp; |
5361 | struct bdaddr_list *b, *btmp; | ||
5327 | 5362 | ||
5328 | if (cp->addr.type) { | 5363 | if (cp->addr.type) { |
5329 | err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_DEVICE, | 5364 | err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_DEVICE, |
@@ -5332,6 +5367,12 @@ static int remove_device(struct sock *sk, struct hci_dev *hdev, | |||
5332 | goto unlock; | 5367 | goto unlock; |
5333 | } | 5368 | } |
5334 | 5369 | ||
5370 | list_for_each_entry_safe(b, btmp, &hdev->whitelist, list) { | ||
5371 | device_removed(sk, hdev, &b->bdaddr, b->bdaddr_type); | ||
5372 | list_del(&b->list); | ||
5373 | kfree(b); | ||
5374 | } | ||
5375 | |||
5335 | list_for_each_entry_safe(p, tmp, &hdev->le_conn_params, list) { | 5376 | list_for_each_entry_safe(p, tmp, &hdev->le_conn_params, list) { |
5336 | if (p->auto_connect == HCI_AUTO_CONN_DISABLED) | 5377 | if (p->auto_connect == HCI_AUTO_CONN_DISABLED) |
5337 | continue; | 5378 | continue; |
@@ -5346,6 +5387,7 @@ static int remove_device(struct sock *sk, struct hci_dev *hdev, | |||
5346 | hci_update_background_scan(hdev); | 5387 | hci_update_background_scan(hdev); |
5347 | } | 5388 | } |
5348 | 5389 | ||
5390 | complete: | ||
5349 | err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_DEVICE, | 5391 | err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_DEVICE, |
5350 | MGMT_STATUS_SUCCESS, &cp->addr, sizeof(cp->addr)); | 5392 | MGMT_STATUS_SUCCESS, &cp->addr, sizeof(cp->addr)); |
5351 | 5393 | ||