aboutsummaryrefslogtreecommitdiffstats
path: root/net/bluetooth/hci_sock.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/bluetooth/hci_sock.c')
-rw-r--r--net/bluetooth/hci_sock.c92
1 files changed, 91 insertions, 1 deletions
diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c
index 688cfebfbee0..83acd164d39e 100644
--- a/net/bluetooth/hci_sock.c
+++ b/net/bluetooth/hci_sock.c
@@ -165,6 +165,84 @@ 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
172 list_for_each(p, &hdev->blacklist) {
173 struct bdaddr_list *b;
174
175 b = list_entry(p, struct bdaddr_list, list);
176
177 if (bacmp(bdaddr, &b->bdaddr) == 0)
178 return b;
179 }
180
181 return NULL;
182}
183
184static int hci_blacklist_add(struct hci_dev *hdev, void __user *arg)
185{
186 bdaddr_t bdaddr;
187 struct bdaddr_list *entry;
188
189 if (copy_from_user(&bdaddr, arg, sizeof(bdaddr)))
190 return -EFAULT;
191
192 if (bacmp(&bdaddr, BDADDR_ANY) == 0)
193 return -EBADF;
194
195 if (hci_blacklist_lookup(hdev, &bdaddr))
196 return -EEXIST;
197
198 entry = kzalloc(sizeof(struct bdaddr_list), GFP_KERNEL);
199 if (!entry)
200 return -ENOMEM;
201
202 bacpy(&entry->bdaddr, &bdaddr);
203
204 list_add(&entry->list, &hdev->blacklist);
205
206 return 0;
207}
208
209int hci_blacklist_clear(struct hci_dev *hdev)
210{
211 struct list_head *p, *n;
212
213 list_for_each_safe(p, n, &hdev->blacklist) {
214 struct bdaddr_list *b;
215
216 b = list_entry(p, struct bdaddr_list, list);
217
218 list_del(p);
219 kfree(b);
220 }
221
222 return 0;
223}
224
225static int hci_blacklist_del(struct hci_dev *hdev, void __user *arg)
226{
227 bdaddr_t bdaddr;
228 struct bdaddr_list *entry;
229
230 if (copy_from_user(&bdaddr, arg, sizeof(bdaddr)))
231 return -EFAULT;
232
233 if (bacmp(&bdaddr, BDADDR_ANY) == 0)
234 return hci_blacklist_clear(hdev);
235
236 entry = hci_blacklist_lookup(hdev, &bdaddr);
237 if (!entry)
238 return -ENOENT;
239
240 list_del(&entry->list);
241 kfree(entry);
242
243 return 0;
244}
245
168/* Ioctls that require bound socket */ 246/* Ioctls that require bound socket */
169static inline int hci_sock_bound_ioctl(struct sock *sk, unsigned int cmd, unsigned long arg) 247static inline int hci_sock_bound_ioctl(struct sock *sk, unsigned int cmd, unsigned long arg)
170{ 248{
@@ -194,6 +272,16 @@ static inline int hci_sock_bound_ioctl(struct sock *sk, unsigned int cmd, unsign
194 case HCIGETAUTHINFO: 272 case HCIGETAUTHINFO:
195 return hci_get_auth_info(hdev, (void __user *) arg); 273 return hci_get_auth_info(hdev, (void __user *) arg);
196 274
275 case HCIBLOCKADDR:
276 if (!capable(CAP_NET_ADMIN))
277 return -EACCES;
278 return hci_blacklist_add(hdev, (void __user *) arg);
279
280 case HCIUNBLOCKADDR:
281 if (!capable(CAP_NET_ADMIN))
282 return -EACCES;
283 return hci_blacklist_del(hdev, (void __user *) arg);
284
197 default: 285 default:
198 if (hdev->ioctl) 286 if (hdev->ioctl)
199 return hdev->ioctl(hdev, cmd, arg); 287 return hdev->ioctl(hdev, cmd, arg);
@@ -329,6 +417,9 @@ static inline void hci_sock_cmsg(struct sock *sk, struct msghdr *msg, struct sk_
329 } 417 }
330 418
331 if (mask & HCI_CMSG_TSTAMP) { 419 if (mask & HCI_CMSG_TSTAMP) {
420#ifdef CONFIG_COMPAT
421 struct compat_timeval ctv;
422#endif
332 struct timeval tv; 423 struct timeval tv;
333 void *data; 424 void *data;
334 int len; 425 int len;
@@ -339,7 +430,6 @@ static inline void hci_sock_cmsg(struct sock *sk, struct msghdr *msg, struct sk_
339 len = sizeof(tv); 430 len = sizeof(tv);
340#ifdef CONFIG_COMPAT 431#ifdef CONFIG_COMPAT
341 if (msg->msg_flags & MSG_CMSG_COMPAT) { 432 if (msg->msg_flags & MSG_CMSG_COMPAT) {
342 struct compat_timeval ctv;
343 ctv.tv_sec = tv.tv_sec; 433 ctv.tv_sec = tv.tv_sec;
344 ctv.tv_usec = tv.tv_usec; 434 ctv.tv_usec = tv.tv_usec;
345 data = &ctv; 435 data = &ctv;