diff options
| author | Johan Hedberg <johan.hedberg@nokia.com> | 2010-05-18 13:20:32 +0200 | 
|---|---|---|
| committer | Marcel Holtmann <marcel@holtmann.org> | 2010-07-21 10:39:05 -0700 | 
| commit | f03585689fdff4ae256edd45a35bc2dd83d3684a (patch) | |
| tree | be1516aa354aa742f2d5b69a91de0561febaffc4 /net/bluetooth/hci_sock.c | |
| parent | 95ffa97827371ede501615d9bd048eb5b49e8fe1 (diff) | |
| download | olio-linux-3.10-f03585689fdff4ae256edd45a35bc2dd83d3684a.tar.xz olio-linux-3.10-f03585689fdff4ae256edd45a35bc2dd83d3684a.zip  | |
Bluetooth: Add blacklist support for incoming connections
In some circumstances it could be desirable to reject incoming
connections on the baseband level. This patch adds this feature through
two new ioctl's: HCIBLOCKADDR and HCIUNBLOCKADDR. Both take a simple
Bluetooth address as a parameter. BDADDR_ANY can be used with
HCIUNBLOCKADDR to remove all devices from the blacklist.
Signed-off-by: Johan Hedberg <johan.hedberg@nokia.com>
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
Diffstat (limited to 'net/bluetooth/hci_sock.c')
| -rw-r--r-- | net/bluetooth/hci_sock.c | 90 | 
1 files changed, 90 insertions, 0 deletions
diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c index 38f08f6b86f..4f170a59593 100644 --- a/net/bluetooth/hci_sock.c +++ b/net/bluetooth/hci_sock.c @@ -165,6 +165,86 @@ static int hci_sock_release(struct socket *sock)  	return 0;  } +struct bdaddr_list *hci_blacklist_lookup(struct hci_dev *hdev, bdaddr_t *bdaddr) +{ +	struct list_head *p; +	struct bdaddr_list *blacklist = &hdev->blacklist; + +	list_for_each(p, &blacklist->list) { +		struct bdaddr_list *b; + +		b = list_entry(p, struct bdaddr_list, list); + +		if (bacmp(bdaddr, &b->bdaddr) == 0) +			return b; +	} + +	return NULL; +} + +static int hci_blacklist_add(struct hci_dev *hdev, void __user *arg) +{ +	bdaddr_t bdaddr; +	struct bdaddr_list *entry; + +	if (copy_from_user(&bdaddr, arg, sizeof(bdaddr))) +		return -EFAULT; + +	if (bacmp(&bdaddr, BDADDR_ANY) == 0) +		return -EBADF; + +	if (hci_blacklist_lookup(hdev, &bdaddr)) +		return -EEXIST; + +	entry = kzalloc(sizeof(struct bdaddr_list), GFP_KERNEL); +	if (!entry) +		return -ENOMEM; + +	bacpy(&entry->bdaddr, &bdaddr); + +	list_add(&entry->list, &hdev->blacklist.list); + +	return 0; +} + +int hci_blacklist_clear(struct hci_dev *hdev) +{ +	struct list_head *p, *n; +	struct bdaddr_list *blacklist = &hdev->blacklist; + +	list_for_each_safe(p, n, &blacklist->list) { +		struct bdaddr_list *b; + +		b = list_entry(p, struct bdaddr_list, list); + +		list_del(p); +		kfree(b); +	} + +	return 0; +} + +static int hci_blacklist_del(struct hci_dev *hdev, void __user *arg) +{ +	bdaddr_t bdaddr; +	struct bdaddr_list *entry; + +	if (copy_from_user(&bdaddr, arg, sizeof(bdaddr))) +		return -EFAULT; + +	if (bacmp(&bdaddr, BDADDR_ANY) == 0) +		return hci_blacklist_clear(hdev); + +	entry = hci_blacklist_lookup(hdev, &bdaddr); +	if (!entry) +		return -ENOENT; + +	list_del(&entry->list); +	kfree(entry); + +	return 0; +} +  /* Ioctls that require bound socket */  static inline int hci_sock_bound_ioctl(struct sock *sk, unsigned int cmd, unsigned long arg)  { @@ -194,6 +274,16 @@ static inline int hci_sock_bound_ioctl(struct sock *sk, unsigned int cmd, unsign  	case HCIGETAUTHINFO:  		return hci_get_auth_info(hdev, (void __user *) arg); +	case HCIBLOCKADDR: +		if (!capable(CAP_NET_ADMIN)) +			return -EACCES; +		return hci_blacklist_add(hdev, (void __user *) arg); + +	case HCIUNBLOCKADDR: +		if (!capable(CAP_NET_ADMIN)) +			return -EACCES; +		return hci_blacklist_del(hdev, (void __user *) arg); +  	default:  		if (hdev->ioctl)  			return hdev->ioctl(hdev, cmd, arg);  |