diff options
Diffstat (limited to 'net/bluetooth/hci_sock.c')
-rw-r--r-- | net/bluetooth/hci_sock.c | 67 |
1 files changed, 55 insertions, 12 deletions
diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c index 83acd164d39e..29827c77f6ce 100644 --- a/net/bluetooth/hci_sock.c +++ b/net/bluetooth/hci_sock.c | |||
@@ -43,12 +43,14 @@ | |||
43 | #include <net/sock.h> | 43 | #include <net/sock.h> |
44 | 44 | ||
45 | #include <asm/system.h> | 45 | #include <asm/system.h> |
46 | #include <asm/uaccess.h> | 46 | #include <linux/uaccess.h> |
47 | #include <asm/unaligned.h> | 47 | #include <asm/unaligned.h> |
48 | 48 | ||
49 | #include <net/bluetooth/bluetooth.h> | 49 | #include <net/bluetooth/bluetooth.h> |
50 | #include <net/bluetooth/hci_core.h> | 50 | #include <net/bluetooth/hci_core.h> |
51 | 51 | ||
52 | static int enable_mgmt; | ||
53 | |||
52 | /* ----- HCI socket interface ----- */ | 54 | /* ----- HCI socket interface ----- */ |
53 | 55 | ||
54 | static inline int hci_test_bit(int nr, void *addr) | 56 | static inline int hci_test_bit(int nr, void *addr) |
@@ -102,6 +104,12 @@ void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb) | |||
102 | if (skb->sk == sk) | 104 | if (skb->sk == sk) |
103 | continue; | 105 | continue; |
104 | 106 | ||
107 | if (bt_cb(skb)->channel != hci_pi(sk)->channel) | ||
108 | continue; | ||
109 | |||
110 | if (bt_cb(skb)->channel == HCI_CHANNEL_CONTROL) | ||
111 | goto clone; | ||
112 | |||
105 | /* Apply filter */ | 113 | /* Apply filter */ |
106 | flt = &hci_pi(sk)->filter; | 114 | flt = &hci_pi(sk)->filter; |
107 | 115 | ||
@@ -125,11 +133,14 @@ void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb) | |||
125 | continue; | 133 | continue; |
126 | } | 134 | } |
127 | 135 | ||
128 | if (!(nskb = skb_clone(skb, GFP_ATOMIC))) | 136 | clone: |
137 | nskb = skb_clone(skb, GFP_ATOMIC); | ||
138 | if (!nskb) | ||
129 | continue; | 139 | continue; |
130 | 140 | ||
131 | /* Put type byte before the data */ | 141 | /* Put type byte before the data */ |
132 | memcpy(skb_push(nskb, 1), &bt_cb(nskb)->pkt_type, 1); | 142 | if (bt_cb(skb)->channel == HCI_CHANNEL_RAW) |
143 | memcpy(skb_push(nskb, 1), &bt_cb(nskb)->pkt_type, 1); | ||
133 | 144 | ||
134 | if (sock_queue_rcv_skb(sk, nskb)) | 145 | if (sock_queue_rcv_skb(sk, nskb)) |
135 | kfree_skb(nskb); | 146 | kfree_skb(nskb); |
@@ -352,25 +363,39 @@ static int hci_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long a | |||
352 | 363 | ||
353 | static int hci_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_len) | 364 | static int hci_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_len) |
354 | { | 365 | { |
355 | struct sockaddr_hci *haddr = (struct sockaddr_hci *) addr; | 366 | struct sockaddr_hci haddr; |
356 | struct sock *sk = sock->sk; | 367 | struct sock *sk = sock->sk; |
357 | struct hci_dev *hdev = NULL; | 368 | struct hci_dev *hdev = NULL; |
358 | int err = 0; | 369 | int len, err = 0; |
359 | 370 | ||
360 | BT_DBG("sock %p sk %p", sock, sk); | 371 | BT_DBG("sock %p sk %p", sock, sk); |
361 | 372 | ||
362 | if (!haddr || haddr->hci_family != AF_BLUETOOTH) | 373 | if (!addr) |
374 | return -EINVAL; | ||
375 | |||
376 | memset(&haddr, 0, sizeof(haddr)); | ||
377 | len = min_t(unsigned int, sizeof(haddr), addr_len); | ||
378 | memcpy(&haddr, addr, len); | ||
379 | |||
380 | if (haddr.hci_family != AF_BLUETOOTH) | ||
381 | return -EINVAL; | ||
382 | |||
383 | if (haddr.hci_channel > HCI_CHANNEL_CONTROL) | ||
384 | return -EINVAL; | ||
385 | |||
386 | if (haddr.hci_channel == HCI_CHANNEL_CONTROL && !enable_mgmt) | ||
363 | return -EINVAL; | 387 | return -EINVAL; |
364 | 388 | ||
365 | lock_sock(sk); | 389 | lock_sock(sk); |
366 | 390 | ||
367 | if (hci_pi(sk)->hdev) { | 391 | if (sk->sk_state == BT_BOUND || hci_pi(sk)->hdev) { |
368 | err = -EALREADY; | 392 | err = -EALREADY; |
369 | goto done; | 393 | goto done; |
370 | } | 394 | } |
371 | 395 | ||
372 | if (haddr->hci_dev != HCI_DEV_NONE) { | 396 | if (haddr.hci_dev != HCI_DEV_NONE) { |
373 | if (!(hdev = hci_dev_get(haddr->hci_dev))) { | 397 | hdev = hci_dev_get(haddr.hci_dev); |
398 | if (!hdev) { | ||
374 | err = -ENODEV; | 399 | err = -ENODEV; |
375 | goto done; | 400 | goto done; |
376 | } | 401 | } |
@@ -378,6 +403,7 @@ static int hci_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_le | |||
378 | atomic_inc(&hdev->promisc); | 403 | atomic_inc(&hdev->promisc); |
379 | } | 404 | } |
380 | 405 | ||
406 | hci_pi(sk)->channel = haddr.hci_channel; | ||
381 | hci_pi(sk)->hdev = hdev; | 407 | hci_pi(sk)->hdev = hdev; |
382 | sk->sk_state = BT_BOUND; | 408 | sk->sk_state = BT_BOUND; |
383 | 409 | ||
@@ -457,7 +483,8 @@ static int hci_sock_recvmsg(struct kiocb *iocb, struct socket *sock, | |||
457 | if (sk->sk_state == BT_CLOSED) | 483 | if (sk->sk_state == BT_CLOSED) |
458 | return 0; | 484 | return 0; |
459 | 485 | ||
460 | if (!(skb = skb_recv_datagram(sk, flags, noblock, &err))) | 486 | skb = skb_recv_datagram(sk, flags, noblock, &err); |
487 | if (!skb) | ||
461 | return err; | 488 | return err; |
462 | 489 | ||
463 | msg->msg_namelen = 0; | 490 | msg->msg_namelen = 0; |
@@ -499,7 +526,19 @@ static int hci_sock_sendmsg(struct kiocb *iocb, struct socket *sock, | |||
499 | 526 | ||
500 | lock_sock(sk); | 527 | lock_sock(sk); |
501 | 528 | ||
502 | if (!(hdev = hci_pi(sk)->hdev)) { | 529 | switch (hci_pi(sk)->channel) { |
530 | case HCI_CHANNEL_RAW: | ||
531 | break; | ||
532 | case HCI_CHANNEL_CONTROL: | ||
533 | err = mgmt_control(sk, msg, len); | ||
534 | goto done; | ||
535 | default: | ||
536 | err = -EINVAL; | ||
537 | goto done; | ||
538 | } | ||
539 | |||
540 | hdev = hci_pi(sk)->hdev; | ||
541 | if (!hdev) { | ||
503 | err = -EBADFD; | 542 | err = -EBADFD; |
504 | goto done; | 543 | goto done; |
505 | } | 544 | } |
@@ -509,7 +548,8 @@ static int hci_sock_sendmsg(struct kiocb *iocb, struct socket *sock, | |||
509 | goto done; | 548 | goto done; |
510 | } | 549 | } |
511 | 550 | ||
512 | if (!(skb = bt_skb_send_alloc(sk, len, msg->msg_flags & MSG_DONTWAIT, &err))) | 551 | skb = bt_skb_send_alloc(sk, len, msg->msg_flags & MSG_DONTWAIT, &err); |
552 | if (!skb) | ||
513 | goto done; | 553 | goto done; |
514 | 554 | ||
515 | if (memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len)) { | 555 | if (memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len)) { |
@@ -826,3 +866,6 @@ void __exit hci_sock_cleanup(void) | |||
826 | 866 | ||
827 | proto_unregister(&hci_sk_proto); | 867 | proto_unregister(&hci_sk_proto); |
828 | } | 868 | } |
869 | |||
870 | module_param(enable_mgmt, bool, 0644); | ||
871 | MODULE_PARM_DESC(enable_mgmt, "Enable Management interface"); | ||