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"); | ||