diff options
Diffstat (limited to 'net/bluetooth/hci_sock.c')
| -rw-r--r-- | net/bluetooth/hci_sock.c | 52 |
1 files changed, 45 insertions, 7 deletions
diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c index b3753bad2a55..29827c77f6ce 100644 --- a/net/bluetooth/hci_sock.c +++ b/net/bluetooth/hci_sock.c | |||
| @@ -49,6 +49,8 @@ | |||
| 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,12 +133,14 @@ void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb) | |||
| 125 | continue; | 133 | continue; |
| 126 | } | 134 | } |
| 127 | 135 | ||
| 136 | clone: | ||
| 128 | nskb = skb_clone(skb, GFP_ATOMIC); | 137 | nskb = skb_clone(skb, GFP_ATOMIC); |
| 129 | if (!nskb) | 138 | if (!nskb) |
| 130 | continue; | 139 | continue; |
| 131 | 140 | ||
| 132 | /* Put type byte before the data */ | 141 | /* Put type byte before the data */ |
| 133 | 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); | ||
| 134 | 144 | ||
| 135 | if (sock_queue_rcv_skb(sk, nskb)) | 145 | if (sock_queue_rcv_skb(sk, nskb)) |
| 136 | kfree_skb(nskb); | 146 | kfree_skb(nskb); |
| @@ -353,25 +363,38 @@ static int hci_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long a | |||
| 353 | 363 | ||
| 354 | 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) |
| 355 | { | 365 | { |
| 356 | struct sockaddr_hci *haddr = (struct sockaddr_hci *) addr; | 366 | struct sockaddr_hci haddr; |
| 357 | struct sock *sk = sock->sk; | 367 | struct sock *sk = sock->sk; |
| 358 | struct hci_dev *hdev = NULL; | 368 | struct hci_dev *hdev = NULL; |
| 359 | int err = 0; | 369 | int len, err = 0; |
| 360 | 370 | ||
| 361 | BT_DBG("sock %p sk %p", sock, sk); | 371 | BT_DBG("sock %p sk %p", sock, sk); |
| 362 | 372 | ||
| 363 | 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) | ||
| 364 | return -EINVAL; | 387 | return -EINVAL; |
| 365 | 388 | ||
| 366 | lock_sock(sk); | 389 | lock_sock(sk); |
| 367 | 390 | ||
| 368 | if (hci_pi(sk)->hdev) { | 391 | if (sk->sk_state == BT_BOUND || hci_pi(sk)->hdev) { |
| 369 | err = -EALREADY; | 392 | err = -EALREADY; |
| 370 | goto done; | 393 | goto done; |
| 371 | } | 394 | } |
| 372 | 395 | ||
| 373 | if (haddr->hci_dev != HCI_DEV_NONE) { | 396 | if (haddr.hci_dev != HCI_DEV_NONE) { |
| 374 | hdev = hci_dev_get(haddr->hci_dev); | 397 | hdev = hci_dev_get(haddr.hci_dev); |
| 375 | if (!hdev) { | 398 | if (!hdev) { |
| 376 | err = -ENODEV; | 399 | err = -ENODEV; |
| 377 | goto done; | 400 | goto done; |
| @@ -380,6 +403,7 @@ static int hci_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_le | |||
| 380 | atomic_inc(&hdev->promisc); | 403 | atomic_inc(&hdev->promisc); |
| 381 | } | 404 | } |
| 382 | 405 | ||
| 406 | hci_pi(sk)->channel = haddr.hci_channel; | ||
| 383 | hci_pi(sk)->hdev = hdev; | 407 | hci_pi(sk)->hdev = hdev; |
| 384 | sk->sk_state = BT_BOUND; | 408 | sk->sk_state = BT_BOUND; |
| 385 | 409 | ||
| @@ -502,6 +526,17 @@ static int hci_sock_sendmsg(struct kiocb *iocb, struct socket *sock, | |||
| 502 | 526 | ||
| 503 | lock_sock(sk); | 527 | lock_sock(sk); |
| 504 | 528 | ||
| 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 | |||
| 505 | hdev = hci_pi(sk)->hdev; | 540 | hdev = hci_pi(sk)->hdev; |
| 506 | if (!hdev) { | 541 | if (!hdev) { |
| 507 | err = -EBADFD; | 542 | err = -EBADFD; |
| @@ -831,3 +866,6 @@ void __exit hci_sock_cleanup(void) | |||
| 831 | 866 | ||
| 832 | proto_unregister(&hci_sk_proto); | 867 | proto_unregister(&hci_sk_proto); |
| 833 | } | 868 | } |
| 869 | |||
| 870 | module_param(enable_mgmt, bool, 0644); | ||
| 871 | MODULE_PARM_DESC(enable_mgmt, "Enable Management interface"); | ||
