nfsd: simplify fh_verify access checks
[safe/jmp/linux-2.6] / net / bluetooth / hci_sock.c
index bdb6458..75302a9 100644 (file)
@@ -1,4 +1,4 @@
-/* 
+/*
    BlueZ - Bluetooth protocol stack for Linux
    Copyright (C) 2000-2001 Qualcomm Incorporated
 
    OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
    IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
-   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
-   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
-   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
+   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
+   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
-   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
-   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
+   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
+   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
    SOFTWARE IS DISCLAIMED.
 */
 
 /* Bluetooth HCI sockets. */
 
-#include <linux/config.h>
 #include <linux/module.h>
 
 #include <linux/types.h>
 #include <linux/capability.h>
 #include <linux/errno.h>
 #include <linux/kernel.h>
-#include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/poll.h>
 #include <linux/fcntl.h>
@@ -39,6 +37,7 @@
 #include <linux/skbuff.h>
 #include <linux/workqueue.h>
 #include <linux/interrupt.h>
+#include <linux/compat.h>
 #include <linux/socket.h>
 #include <linux/ioctl.h>
 #include <net/sock.h>
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/hci_core.h>
 
-#ifndef CONFIG_BT_HCI_SOCK_DEBUG
-#undef  BT_DBG
-#define BT_DBG(D...)
-#endif
-
 /* ----- HCI socket interface ----- */
 
 static inline int hci_test_bit(int nr, void *addr)
@@ -72,20 +66,20 @@ static struct hci_sec_filter hci_sec_filter = {
        {
                { 0x0 },
                /* OGF_LINK_CTL */
-               { 0xbe000006, 0x00000001, 0x000000, 0x00 },
+               { 0xbe000006, 0x00000001, 0x00000000, 0x00 },
                /* OGF_LINK_POLICY */
-               { 0x00005200, 0x00000000, 0x000000, 0x00 },
+               { 0x00005200, 0x00000000, 0x00000000, 0x00 },
                /* OGF_HOST_CTL */
-               { 0xaab00200, 0x2b402aaa, 0x020154, 0x00 },
+               { 0xaab00200, 0x2b402aaa, 0x05220154, 0x00 },
                /* OGF_INFO_PARAM */
-               { 0x000002be, 0x00000000, 0x000000, 0x00 },
+               { 0x000002be, 0x00000000, 0x00000000, 0x00 },
                /* OGF_STATUS_PARAM */
-               { 0x000000ea, 0x00000000, 0x000000, 0x00 }
+               { 0x000000ea, 0x00000000, 0x00000000, 0x00 }
        }
 };
 
 static struct bt_sock_list hci_sk_list = {
-       .lock = RW_LOCK_UNLOCKED
+       .lock = __RW_LOCK_UNLOCKED(hci_sk_list.lock)
 };
 
 /* Send frame to RAW socket */
@@ -121,10 +115,13 @@ void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb)
                        if (!hci_test_bit(evt, &flt->event_mask))
                                continue;
 
-                       if (flt->opcode && ((evt == HCI_EV_CMD_COMPLETE && 
-                                       flt->opcode != *(__u16 *)(skb->data + 3)) ||
-                                       (evt == HCI_EV_CMD_STATUS && 
-                                       flt->opcode != *(__u16 *)(skb->data + 4))))
+                       if (flt->opcode &&
+                           ((evt == HCI_EV_CMD_COMPLETE &&
+                             flt->opcode !=
+                             get_unaligned((__le16 *)(skb->data + 3))) ||
+                            (evt == HCI_EV_CMD_STATUS &&
+                             flt->opcode !=
+                             get_unaligned((__le16 *)(skb->data + 4)))))
                                continue;
                }
 
@@ -143,13 +140,15 @@ void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb)
 static int hci_sock_release(struct socket *sock)
 {
        struct sock *sk = sock->sk;
-       struct hci_dev *hdev = hci_pi(sk)->hdev;
+       struct hci_dev *hdev;
 
        BT_DBG("sock %p sk %p", sock, sk);
 
        if (!sk)
                return 0;
 
+       hdev = hci_pi(sk)->hdev;
+
        bt_sock_unlink(&hci_sk_list, sk);
 
        if (hdev) {
@@ -166,7 +165,7 @@ static int hci_sock_release(struct socket *sock)
        return 0;
 }
 
-/* Ioctls that require bound socket */ 
+/* Ioctls that require bound socket */
 static inline int hci_sock_bound_ioctl(struct sock *sk, unsigned int cmd, unsigned long arg)
 {
        struct hci_dev *hdev = hci_pi(sk)->hdev;
@@ -189,19 +188,11 @@ static inline int hci_sock_bound_ioctl(struct sock *sk, unsigned int cmd, unsign
 
                return 0;
 
-       case HCISETSECMGR:
-               if (!capable(CAP_NET_ADMIN))
-                       return -EACCES;
-
-               if (arg)
-                       set_bit(HCI_SECMGR, &hdev->flags);
-               else
-                       clear_bit(HCI_SECMGR, &hdev->flags);
-
-               return 0;
-
        case HCIGETCONNINFO:
-               return hci_get_conn_info(hdev, (void __user *)arg);
+               return hci_get_conn_info(hdev, (void __user *) arg);
+
+       case HCIGETAUTHINFO:
+               return hci_get_auth_info(hdev, (void __user *) arg);
 
        default:
                if (hdev->ioctl)
@@ -213,7 +204,7 @@ static inline int hci_sock_bound_ioctl(struct sock *sk, unsigned int cmd, unsign
 static int hci_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
 {
        struct sock *sk = sock->sk;
-       void __user *argp = (void __user *)arg;
+       void __user *argp = (void __user *) arg;
        int err;
 
        BT_DBG("cmd %x arg %lx", cmd, arg);
@@ -311,14 +302,18 @@ static int hci_sock_getname(struct socket *sock, struct sockaddr *addr, int *add
 {
        struct sockaddr_hci *haddr = (struct sockaddr_hci *) addr;
        struct sock *sk = sock->sk;
+       struct hci_dev *hdev = hci_pi(sk)->hdev;
 
        BT_DBG("sock %p sk %p", sock, sk);
 
+       if (!hdev)
+               return -EBADFD;
+
        lock_sock(sk);
 
        *addr_len = sizeof(*haddr);
        haddr->hci_family = AF_BLUETOOTH;
-       haddr->hci_dev    = hci_pi(sk)->hdev->id;
+       haddr->hci_dev    = hdev->id;
 
        release_sock(sk);
        return 0;
@@ -335,13 +330,28 @@ static inline void hci_sock_cmsg(struct sock *sk, struct msghdr *msg, struct sk_
 
        if (mask & HCI_CMSG_TSTAMP) {
                struct timeval tv;
+               void *data;
+               int len;
 
                skb_get_timestamp(skb, &tv);
-               put_cmsg(msg, SOL_HCI, HCI_CMSG_TSTAMP, sizeof(tv), &tv);
+
+               data = &tv;
+               len = sizeof(tv);
+#ifdef CONFIG_COMPAT
+               if (msg->msg_flags & MSG_CMSG_COMPAT) {
+                       struct compat_timeval ctv;
+                       ctv.tv_sec = tv.tv_sec;
+                       ctv.tv_usec = tv.tv_usec;
+                       data = &ctv;
+                       len = sizeof(ctv);
+               }
+#endif
+
+               put_cmsg(msg, SOL_HCI, HCI_CMSG_TSTAMP, len, data);
        }
 }
-static int hci_sock_recvmsg(struct kiocb *iocb, struct socket *sock, 
+
+static int hci_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
                                struct msghdr *msg, size_t len, int flags)
 {
        int noblock = flags & MSG_DONTWAIT;
@@ -368,7 +378,7 @@ static int hci_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
                copied = len;
        }
 
-       skb->h.raw = skb->data;
+       skb_reset_transport_header(skb);
        err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
 
        hci_sock_cmsg(sk, msg, skb);
@@ -378,7 +388,7 @@ static int hci_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
        return err ? : copied;
 }
 
-static int hci_sock_sendmsg(struct kiocb *iocb, struct socket *sock, 
+static int hci_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
                            struct msghdr *msg, size_t len)
 {
        struct sock *sk = sock->sk;
@@ -417,7 +427,7 @@ static int hci_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
        skb->dev = (void *) hdev;
 
        if (bt_cb(skb)->pkt_type == HCI_COMMAND_PKT) {
-               u16 opcode = __le16_to_cpu(get_unaligned((__le16 *) skb->data));
+               u16 opcode = get_unaligned_le16(skb->data);
                u16 ogf = hci_opcode_ogf(opcode);
                u16 ocf = hci_opcode_ocf(opcode);
 
@@ -428,7 +438,7 @@ static int hci_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
                        goto drop;
                }
 
-               if (test_bit(HCI_RAW, &hdev->flags) || (ogf == OGF_VENDOR_CMD)) {
+               if (test_bit(HCI_RAW, &hdev->flags) || (ogf == 0x3f)) {
                        skb_queue_tail(&hdev->raw_q, skb);
                        hci_sched_tx(hdev);
                } else {
@@ -456,7 +466,7 @@ drop:
        goto done;
 }
 
-static int hci_sock_setsockopt(struct socket *sock, int level, int optname, char __user *optval, int len)
+static int hci_sock_setsockopt(struct socket *sock, int level, int optname, char __user *optval, unsigned int len)
 {
        struct hci_ufilter uf = { .opcode = 0 };
        struct sock *sk = sock->sk;
@@ -492,6 +502,15 @@ static int hci_sock_setsockopt(struct socket *sock, int level, int optname, char
                break;
 
        case HCI_FILTER:
+               {
+                       struct hci_filter *f = &hci_pi(sk)->filter;
+
+                       uf.type_mask = f->type_mask;
+                       uf.opcode    = f->opcode;
+                       uf.event_mask[0] = *((u32 *) f->event_mask + 0);
+                       uf.event_mask[1] = *((u32 *) f->event_mask + 1);
+               }
+
                len = min_t(unsigned int, len, sizeof(uf));
                if (copy_from_user(&uf, optval, len)) {
                        err = -EFAULT;
@@ -512,7 +531,7 @@ static int hci_sock_setsockopt(struct socket *sock, int level, int optname, char
                        *((u32 *) f->event_mask + 0) = uf.event_mask[0];
                        *((u32 *) f->event_mask + 1) = uf.event_mask[1];
                }
-               break; 
+               break;
 
        default:
                err = -ENOPROTOOPT;
@@ -527,7 +546,7 @@ static int hci_sock_getsockopt(struct socket *sock, int level, int optname, char
 {
        struct hci_ufilter uf;
        struct sock *sk = sock->sk;
-       int len, opt; 
+       int len, opt;
 
        if (get_user(len, optlen))
                return -EFAULT;
@@ -536,7 +555,7 @@ static int hci_sock_getsockopt(struct socket *sock, int level, int optname, char
        case HCI_DATA_DIR:
                if (hci_pi(sk)->cmsg_mask & HCI_CMSG_DIR)
                        opt = 1;
-               else 
+               else
                        opt = 0;
 
                if (put_user(opt, optval))
@@ -546,7 +565,7 @@ static int hci_sock_getsockopt(struct socket *sock, int level, int optname, char
        case HCI_TIME_STAMP:
                if (hci_pi(sk)->cmsg_mask & HCI_CMSG_TSTAMP)
                        opt = 1;
-               else 
+               else
                        opt = 0;
 
                if (put_user(opt, optval))
@@ -602,7 +621,7 @@ static struct proto hci_sk_proto = {
        .obj_size       = sizeof(struct hci_pinfo)
 };
 
-static int hci_sock_create(struct socket *sock, int protocol)
+static int hci_sock_create(struct net *net, struct socket *sock, int protocol)
 {
        struct sock *sk;
 
@@ -613,7 +632,7 @@ static int hci_sock_create(struct socket *sock, int protocol)
 
        sock->ops = &hci_sock_ops;
 
-       sk = sk_alloc(PF_BLUETOOTH, GFP_KERNEL, &hci_sk_proto, 1);
+       sk = sk_alloc(net, PF_BLUETOOTH, GFP_ATOMIC, &hci_sk_proto);
        if (!sk)
                return -ENOMEM;
 
@@ -649,7 +668,8 @@ static int hci_sock_dev_event(struct notifier_block *this, unsigned long event,
                /* Detach sockets from device */
                read_lock(&hci_sk_list.lock);
                sk_for_each(sk, node, &hci_sk_list.head) {
-                       bh_lock_sock(sk);
+                       local_bh_disable();
+                       bh_lock_sock_nested(sk);
                        if (hci_pi(sk)->hdev == hdev) {
                                hci_pi(sk)->hdev = NULL;
                                sk->sk_err = EPIPE;
@@ -659,6 +679,7 @@ static int hci_sock_dev_event(struct notifier_block *this, unsigned long event,
                                hci_dev_put(hdev);
                        }
                        bh_unlock_sock(sk);
+                       local_bh_enable();
                }
                read_unlock(&hci_sk_list.lock);
        }
@@ -700,7 +721,7 @@ error:
        return err;
 }
 
-int __exit hci_sock_cleanup(void)
+void __exit hci_sock_cleanup(void)
 {
        if (bt_sock_unregister(BTPROTO_HCI) < 0)
                BT_ERR("HCI socket unregistration failed");
@@ -708,6 +729,4 @@ int __exit hci_sock_cleanup(void)
        hci_unregister_notifier(&hci_sock_nblock);
 
        proto_unregister(&hci_sk_proto);
-
-       return 0;
 }