mirror of
				git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
				synced 2025-10-31 08:44:41 +00:00 
			
		
		
		
	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>
This commit is contained in:
		
							parent
							
								
									95ffa97827
								
							
						
					
					
						commit
						f03585689f
					
				
					 6 changed files with 108 additions and 1 deletions
				
			
		|  | @ -1328,6 +1328,8 @@ COMPATIBLE_IOCTL(HCISETLINKPOL) | |||
| COMPATIBLE_IOCTL(HCISETLINKMODE) | ||||
| COMPATIBLE_IOCTL(HCISETACLMTU) | ||||
| COMPATIBLE_IOCTL(HCISETSCOMTU) | ||||
| COMPATIBLE_IOCTL(HCIBLOCKADDR) | ||||
| COMPATIBLE_IOCTL(HCIUNBLOCKADDR) | ||||
| COMPATIBLE_IOCTL(HCIINQUIRY) | ||||
| COMPATIBLE_IOCTL(HCIUARTSETPROTO) | ||||
| COMPATIBLE_IOCTL(HCIUARTGETPROTO) | ||||
|  |  | |||
|  | @ -100,6 +100,9 @@ enum { | |||
| #define HCISETACLMTU	_IOW('H', 227, int) | ||||
| #define HCISETSCOMTU	_IOW('H', 228, int) | ||||
| 
 | ||||
| #define HCIBLOCKADDR	_IOW('H', 230, int) | ||||
| #define HCIUNBLOCKADDR	_IOW('H', 231, int) | ||||
| 
 | ||||
| #define HCIINQUIRY	_IOR('H', 240, int) | ||||
| 
 | ||||
| /* HCI timeouts */ | ||||
|  |  | |||
|  | @ -62,6 +62,11 @@ struct hci_conn_hash { | |||
| 	unsigned int     sco_num; | ||||
| }; | ||||
| 
 | ||||
| struct bdaddr_list { | ||||
| 	struct list_head list; | ||||
| 	bdaddr_t bdaddr; | ||||
| }; | ||||
| 
 | ||||
| struct hci_dev { | ||||
| 	struct list_head list; | ||||
| 	spinlock_t	lock; | ||||
|  | @ -127,6 +132,7 @@ struct hci_dev { | |||
| 
 | ||||
| 	struct inquiry_cache	inq_cache; | ||||
| 	struct hci_conn_hash	conn_hash; | ||||
| 	struct bdaddr_list	blacklist; | ||||
| 
 | ||||
| 	struct hci_dev_stats	stat; | ||||
| 
 | ||||
|  | @ -424,6 +430,9 @@ int hci_get_conn_info(struct hci_dev *hdev, void __user *arg); | |||
| int hci_get_auth_info(struct hci_dev *hdev, void __user *arg); | ||||
| int hci_inquiry(void __user *arg); | ||||
| 
 | ||||
| struct bdaddr_list *hci_blacklist_lookup(struct hci_dev *hdev, bdaddr_t *bdaddr); | ||||
| int hci_blacklist_clear(struct hci_dev *hdev); | ||||
| 
 | ||||
| void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb); | ||||
| 
 | ||||
| int hci_recv_frame(struct sk_buff *skb); | ||||
|  |  | |||
|  | @ -562,6 +562,7 @@ static int hci_dev_do_close(struct hci_dev *hdev) | |||
| 	hci_dev_lock_bh(hdev); | ||||
| 	inquiry_cache_flush(hdev); | ||||
| 	hci_conn_hash_flush(hdev); | ||||
| 	hci_blacklist_clear(hdev); | ||||
| 	hci_dev_unlock_bh(hdev); | ||||
| 
 | ||||
| 	hci_notify(hdev, HCI_DEV_DOWN); | ||||
|  | @ -923,6 +924,8 @@ int hci_register_dev(struct hci_dev *hdev) | |||
| 
 | ||||
| 	hci_conn_hash_init(hdev); | ||||
| 
 | ||||
| 	INIT_LIST_HEAD(&hdev->blacklist.list); | ||||
| 
 | ||||
| 	memset(&hdev->stat, 0, sizeof(struct hci_dev_stats)); | ||||
| 
 | ||||
| 	atomic_set(&hdev->promisc, 0); | ||||
|  |  | |||
|  | @ -952,7 +952,7 @@ static inline void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *sk | |||
| 
 | ||||
| 	mask |= hci_proto_connect_ind(hdev, &ev->bdaddr, ev->link_type); | ||||
| 
 | ||||
| 	if (mask & HCI_LM_ACCEPT) { | ||||
| 	if ((mask & HCI_LM_ACCEPT) && !hci_blacklist_lookup(hdev, &ev->bdaddr)) { | ||||
| 		/* Connection accepted */ | ||||
| 		struct inquiry_entry *ie; | ||||
| 		struct hci_conn *conn; | ||||
|  |  | |||
|  | @ -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); | ||||
|  |  | |||
		Loading…
	
	Add table
		
		Reference in a new issue
	
	 Johan Hedberg
						Johan Hedberg