diff options
Diffstat (limited to 'net/bluetooth/hci_sock.c')
| -rw-r--r-- | net/bluetooth/hci_sock.c | 92 |
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 | ||
| 168 | struct 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 | |||
| 184 | static 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 | |||
| 209 | int 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 | |||
| 225 | static 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 */ |
| 169 | static inline int hci_sock_bound_ioctl(struct sock *sk, unsigned int cmd, unsigned long arg) | 247 | static 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; |
