aboutsummaryrefslogtreecommitdiffstats
path: root/net/bluetooth
diff options
context:
space:
mode:
authorJohan Hedberg <johan.hedberg@nokia.com>2010-05-18 07:20:32 -0400
committerMarcel Holtmann <marcel@holtmann.org>2010-07-21 13:39:05 -0400
commitf03585689fdff4ae256edd45a35bc2dd83d3684a (patch)
treebe1516aa354aa742f2d5b69a91de0561febaffc4 /net/bluetooth
parent95ffa97827371ede501615d9bd048eb5b49e8fe1 (diff)
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')
-rw-r--r--net/bluetooth/hci_core.c3
-rw-r--r--net/bluetooth/hci_event.c2
-rw-r--r--net/bluetooth/hci_sock.c90
3 files changed, 94 insertions, 1 deletions
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 2f768de87011..aeb2982310a0 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -562,6 +562,7 @@ static int hci_dev_do_close(struct hci_dev *hdev)
562 hci_dev_lock_bh(hdev); 562 hci_dev_lock_bh(hdev);
563 inquiry_cache_flush(hdev); 563 inquiry_cache_flush(hdev);
564 hci_conn_hash_flush(hdev); 564 hci_conn_hash_flush(hdev);
565 hci_blacklist_clear(hdev);
565 hci_dev_unlock_bh(hdev); 566 hci_dev_unlock_bh(hdev);
566 567
567 hci_notify(hdev, HCI_DEV_DOWN); 568 hci_notify(hdev, HCI_DEV_DOWN);
@@ -923,6 +924,8 @@ int hci_register_dev(struct hci_dev *hdev)
923 924
924 hci_conn_hash_init(hdev); 925 hci_conn_hash_init(hdev);
925 926
927 INIT_LIST_HEAD(&hdev->blacklist.list);
928
926 memset(&hdev->stat, 0, sizeof(struct hci_dev_stats)); 929 memset(&hdev->stat, 0, sizeof(struct hci_dev_stats));
927 930
928 atomic_set(&hdev->promisc, 0); 931 atomic_set(&hdev->promisc, 0);
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 786b5de0bac4..43feeef3c498 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -952,7 +952,7 @@ static inline void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *sk
952 952
953 mask |= hci_proto_connect_ind(hdev, &ev->bdaddr, ev->link_type); 953 mask |= hci_proto_connect_ind(hdev, &ev->bdaddr, ev->link_type);
954 954
955 if (mask & HCI_LM_ACCEPT) { 955 if ((mask & HCI_LM_ACCEPT) && !hci_blacklist_lookup(hdev, &ev->bdaddr)) {
956 /* Connection accepted */ 956 /* Connection accepted */
957 struct inquiry_entry *ie; 957 struct inquiry_entry *ie;
958 struct hci_conn *conn; 958 struct hci_conn *conn;
diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c
index 38f08f6b86f6..4f170a595934 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)
165 return 0; 165 return 0;
166} 166}
167 167
168struct bdaddr_list *hci_blacklist_lookup(struct hci_dev *hdev, bdaddr_t *bdaddr)
169{
170 struct list_head *p;
171 struct bdaddr_list *blacklist = &hdev->blacklist;
172
173 list_for_each(p, &blacklist->list) {
174 struct bdaddr_list *b;
175
176 b = list_entry(p, struct bdaddr_list, list);
177
178 if (bacmp(bdaddr, &b->bdaddr) == 0)
179 return b;
180 }
181
182 return NULL;
183}
184
185static int hci_blacklist_add(struct hci_dev *hdev, void __user *arg)
186{
187 bdaddr_t bdaddr;
188 struct bdaddr_list *entry;
189
190 if (copy_from_user(&bdaddr, arg, sizeof(bdaddr)))
191 return -EFAULT;
192
193 if (bacmp(&bdaddr, BDADDR_ANY) == 0)
194 return -EBADF;
195
196 if (hci_blacklist_lookup(hdev, &bdaddr))
197 return -EEXIST;
198
199 entry = kzalloc(sizeof(struct bdaddr_list), GFP_KERNEL);
200 if (!entry)
201 return -ENOMEM;
202
203 bacpy(&entry->bdaddr, &bdaddr);
204
205 list_add(&entry->list, &hdev->blacklist.list);
206
207 return 0;
208}
209
210int hci_blacklist_clear(struct hci_dev *hdev)
211{
212 struct list_head *p, *n;
213 struct bdaddr_list *blacklist = &hdev->blacklist;
214
215 list_for_each_safe(p, n, &blacklist->list) {
216 struct bdaddr_list *b;
217
218 b = list_entry(p, struct bdaddr_list, list);
219
220 list_del(p);
221 kfree(b);
222 }
223
224 return 0;
225}
226
227static int hci_blacklist_del(struct hci_dev *hdev, void __user *arg)
228{
229 bdaddr_t bdaddr;
230 struct bdaddr_list *entry;
231
232 if (copy_from_user(&bdaddr, arg, sizeof(bdaddr)))
233 return -EFAULT;
234
235 if (bacmp(&bdaddr, BDADDR_ANY) == 0)
236 return hci_blacklist_clear(hdev);
237
238 entry = hci_blacklist_lookup(hdev, &bdaddr);
239 if (!entry)
240 return -ENOENT;
241
242 list_del(&entry->list);
243 kfree(entry);
244
245 return 0;
246}
247
168/* Ioctls that require bound socket */ 248/* Ioctls that require bound socket */
169static inline int hci_sock_bound_ioctl(struct sock *sk, unsigned int cmd, unsigned long arg) 249static inline int hci_sock_bound_ioctl(struct sock *sk, unsigned int cmd, unsigned long arg)
170{ 250{
@@ -194,6 +274,16 @@ static inline int hci_sock_bound_ioctl(struct sock *sk, unsigned int cmd, unsign
194 case HCIGETAUTHINFO: 274 case HCIGETAUTHINFO:
195 return hci_get_auth_info(hdev, (void __user *) arg); 275 return hci_get_auth_info(hdev, (void __user *) arg);
196 276
277 case HCIBLOCKADDR:
278 if (!capable(CAP_NET_ADMIN))
279 return -EACCES;
280 return hci_blacklist_add(hdev, (void __user *) arg);
281
282 case HCIUNBLOCKADDR:
283 if (!capable(CAP_NET_ADMIN))
284 return -EACCES;
285 return hci_blacklist_del(hdev, (void __user *) arg);
286
197 default: 287 default:
198 if (hdev->ioctl) 288 if (hdev->ioctl)
199 return hdev->ioctl(hdev, cmd, arg); 289 return hdev->ioctl(hdev, cmd, arg);