Fedora kernel-2.6.17-1.2142_FC4 patched with stable patch-2.6.17.4-vs2.0.2-rc26.diff
[linux-2.6.git] / net / bluetooth / hci_sock.c
index ceee707..97bdec7 100644 (file)
    SOFTWARE IS DISCLAIMED.
 */
 
-/*
- * Bluetooth HCI socket layer.
- *
- * $Id: hci_sock.c,v 1.4 2002/04/18 22:26:14 maxk Exp $
- */
+/* 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/major.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/poll.h>
@@ -56,7 +52,7 @@
 
 #ifndef CONFIG_BT_HCI_SOCK_DEBUG
 #undef  BT_DBG
-#define BT_DBG( A... )
+#define BT_DBG(D...)
 #endif
 
 /* ----- HCI socket interface ----- */
@@ -71,20 +67,20 @@ static struct hci_sec_filter hci_sec_filter = {
        /* Packet types */
        0x10,
        /* Events */
-       { 0x1000d9fe, 0x0000300c },
+       { 0x1000d9fe, 0x0000b00c },
        /* Commands */
        {
                { 0x0 },
                /* OGF_LINK_CTL */
-               { 0xbe000006, 0x00000001, 0x0000, 0x00 },
+               { 0xbe000006, 0x00000001, 0x000000, 0x00 },
                /* OGF_LINK_POLICY */
-               { 0x00005200, 0x00000000, 0x0000, 0x00 },
+               { 0x00005200, 0x00000000, 0x000000, 0x00 },
                /* OGF_HOST_CTL */
-               { 0xaab00200, 0x2b402aaa, 0x0154, 0x00 },
+               { 0xaab00200, 0x2b402aaa, 0x020154, 0x00 },
                /* OGF_INFO_PARAM */
-               { 0x000002be, 0x00000000, 0x0000, 0x00 },
+               { 0x000002be, 0x00000000, 0x000000, 0x00 },
                /* OGF_STATUS_PARAM */
-               { 0x000000ea, 0x00000000, 0x0000, 0x00 }
+               { 0x000000ea, 0x00000000, 0x000000, 0x00 }
        }
 };
 
@@ -115,10 +111,11 @@ void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb)
                /* Apply filter */
                flt = &hci_pi(sk)->filter;
 
-               if (!test_bit((skb->pkt_type & HCI_FLT_TYPE_BITS), &flt->type_mask))
+               if (!test_bit((bt_cb(skb)->pkt_type == HCI_VENDOR_PKT) ?
+                               0 : (bt_cb(skb)->pkt_type & HCI_FLT_TYPE_BITS), &flt->type_mask))
                        continue;
 
-               if (skb->pkt_type == HCI_EVENT_PKT) {
+               if (bt_cb(skb)->pkt_type == HCI_EVENT_PKT) {
                        register int evt = (*(__u8 *)skb->data & HCI_FLT_EVENT_BITS);
 
                        if (!hci_test_bit(evt, &flt->event_mask))
@@ -135,11 +132,10 @@ void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb)
                        continue;
 
                /* Put type byte before the data */
-               memcpy(skb_push(nskb, 1), &nskb->pkt_type, 1);
+               memcpy(skb_push(nskb, 1), &bt_cb(nskb)->pkt_type, 1);
 
                if (sock_queue_rcv_skb(sk, nskb))
                        kfree_skb(nskb);
-               
        }
        read_unlock(&hci_sk_list.lock);
 }
@@ -147,13 +143,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) {
@@ -183,6 +181,9 @@ static inline int hci_sock_bound_ioctl(struct sock *sk, unsigned int cmd, unsign
                if (!capable(CAP_NET_ADMIN))
                        return -EACCES;
 
+               if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
+                       return -EPERM;
+
                if (arg)
                        set_bit(HCI_RAW, &hdev->flags);
                else
@@ -190,8 +191,19 @@ 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, arg);
+               return hci_get_conn_info(hdev, (void __user *)arg);
 
        default:
                if (hdev->ioctl)
@@ -203,19 +215,20 @@ 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;
        int err;
 
        BT_DBG("cmd %x arg %lx", cmd, arg);
 
        switch (cmd) {
        case HCIGETDEVLIST:
-               return hci_get_dev_list(arg);
+               return hci_get_dev_list(argp);
 
        case HCIGETDEVINFO:
-               return hci_get_dev_info(arg);
+               return hci_get_dev_info(argp);
 
        case HCIGETCONNLIST:
-               return hci_get_conn_list(arg);
+               return hci_get_conn_list(argp);
 
        case HCIDEVUP:
                if (!capable(CAP_NET_ADMIN))
@@ -247,10 +260,10 @@ static int hci_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long a
        case HCISETSCOMTU:
                if (!capable(CAP_NET_ADMIN))
                        return -EACCES;
-               return hci_dev_cmd(cmd, arg);
+               return hci_dev_cmd(cmd, argp);
 
        case HCIINQUIRY:
-               return hci_inquiry(arg);
+               return hci_inquiry(argp);
 
        default:
                lock_sock(sk);
@@ -300,14 +313,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;
@@ -317,15 +334,21 @@ static inline void hci_sock_cmsg(struct sock *sk, struct msghdr *msg, struct sk_
 {
        __u32 mask = hci_pi(sk)->cmsg_mask;
 
-       if (mask & HCI_CMSG_DIR)
-               put_cmsg(msg, SOL_HCI, HCI_CMSG_DIR, sizeof(int), &bt_cb(skb)->incoming);
+       if (mask & HCI_CMSG_DIR) {
+               int incoming = bt_cb(skb)->incoming;
+               put_cmsg(msg, SOL_HCI, HCI_CMSG_DIR, sizeof(incoming), &incoming);
+       }
+
+       if (mask & HCI_CMSG_TSTAMP) {
+               struct timeval tv;
 
-       if (mask & HCI_CMSG_TSTAMP)
-               put_cmsg(msg, SOL_HCI, HCI_CMSG_TSTAMP, sizeof(skb->stamp), &skb->stamp);
+               skb_get_timestamp(skb, &tv);
+               put_cmsg(msg, SOL_HCI, HCI_CMSG_TSTAMP, sizeof(tv), &tv);
+       }
 }
  
 static int hci_sock_recvmsg(struct kiocb *iocb, struct socket *sock, 
-                           struct msghdr *msg, size_t len, int flags)
+                               struct msghdr *msg, size_t len, int flags)
 {
        int noblock = flags & MSG_DONTWAIT;
        struct sock *sk = sock->sk;
@@ -355,7 +378,7 @@ static int hci_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
        err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
 
        hci_sock_cmsg(sk, msg, skb);
-       
+
        skb_free_datagram(sk, skb);
 
        return err ? : copied;
@@ -395,18 +418,18 @@ static int hci_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
                goto drop;
        }
 
-       skb->pkt_type = *((unsigned char *) skb->data);
+       bt_cb(skb)->pkt_type = *((unsigned char *) skb->data);
        skb_pull(skb, 1);
        skb->dev = (void *) hdev;
 
-       if (skb->pkt_type == HCI_COMMAND_PKT) {
-               u16 opcode = __le16_to_cpu(get_unaligned((u16 *)skb->data));
+       if (bt_cb(skb)->pkt_type == HCI_COMMAND_PKT) {
+               u16 opcode = __le16_to_cpu(get_unaligned((__le16 *) skb->data));
                u16 ogf = hci_opcode_ogf(opcode);
                u16 ocf = hci_opcode_ocf(opcode);
 
                if (((ogf > HCI_SFLT_MAX_OGF) ||
                                !hci_test_bit(ocf & HCI_FLT_OCF_BITS, &hci_sec_filter.ocf_mask[ogf])) &&
-                                       !capable(CAP_NET_RAW)) {
+                                       !capable(CAP_NET_RAW)) {
                        err = -EPERM;
                        goto drop;
                }
@@ -439,7 +462,7 @@ drop:
        goto done;
 }
 
-int hci_sock_setsockopt(struct socket *sock, int level, int optname, char *optval, int len)
+static int hci_sock_setsockopt(struct socket *sock, int level, int optname, char __user *optval, int len)
 {
        struct hci_ufilter uf = { .opcode = 0 };
        struct sock *sk = sock->sk;
@@ -451,7 +474,7 @@ int hci_sock_setsockopt(struct socket *sock, int level, int optname, char *optva
 
        switch (optname) {
        case HCI_DATA_DIR:
-               if (get_user(opt, (int *)optval)) {
+               if (get_user(opt, (int __user *)optval)) {
                        err = -EFAULT;
                        break;
                }
@@ -463,7 +486,7 @@ int hci_sock_setsockopt(struct socket *sock, int level, int optname, char *optva
                break;
 
        case HCI_TIME_STAMP:
-               if (get_user(opt, (int *)optval)) {
+               if (get_user(opt, (int __user *)optval)) {
                        err = -EFAULT;
                        break;
                }
@@ -487,9 +510,9 @@ int hci_sock_setsockopt(struct socket *sock, int level, int optname, char *optva
                        uf.event_mask[1] &= *((u32 *) hci_sec_filter.event_mask + 1);
                }
 
-               {       
+               {
                        struct hci_filter *f = &hci_pi(sk)->filter;
-               
+
                        f->type_mask = uf.type_mask;
                        f->opcode    = uf.opcode;
                        *((u32 *) f->event_mask + 0) = uf.event_mask[0];
@@ -501,12 +524,12 @@ int hci_sock_setsockopt(struct socket *sock, int level, int optname, char *optva
                err = -ENOPROTOOPT;
                break;
        }
-       
+
        release_sock(sk);
        return err;
 }
 
-int hci_sock_getsockopt(struct socket *sock, int level, int optname, char *optval, int *optlen)
+static int hci_sock_getsockopt(struct socket *sock, int level, int optname, char __user *optval, int __user *optlen)
 {
        struct hci_ufilter uf;
        struct sock *sk = sock->sk;
@@ -539,7 +562,7 @@ int hci_sock_getsockopt(struct socket *sock, int level, int optname, char *optva
        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);
@@ -559,24 +582,30 @@ int hci_sock_getsockopt(struct socket *sock, int level, int optname, char *optva
        return 0;
 }
 
-struct proto_ops hci_sock_ops = {
-       .family =       PF_BLUETOOTH,
-       .owner =        THIS_MODULE,
-       .release =      hci_sock_release,
-       .bind =         hci_sock_bind,
-       .getname =      hci_sock_getname,
-       .sendmsg =      hci_sock_sendmsg,
-       .recvmsg =      hci_sock_recvmsg,
-       .ioctl =        hci_sock_ioctl,
-       .poll =         datagram_poll,
-       .listen =       sock_no_listen,
-       .shutdown =     sock_no_shutdown,
-       .setsockopt =   hci_sock_setsockopt,
-       .getsockopt =   hci_sock_getsockopt,
-       .connect =      sock_no_connect,
-       .socketpair =   sock_no_socketpair,
-       .accept =       sock_no_accept,
-       .mmap =         sock_no_mmap
+static const struct proto_ops hci_sock_ops = {
+       .family         = PF_BLUETOOTH,
+       .owner          = THIS_MODULE,
+       .release        = hci_sock_release,
+       .bind           = hci_sock_bind,
+       .getname        = hci_sock_getname,
+       .sendmsg        = hci_sock_sendmsg,
+       .recvmsg        = hci_sock_recvmsg,
+       .ioctl          = hci_sock_ioctl,
+       .poll           = datagram_poll,
+       .listen         = sock_no_listen,
+       .shutdown       = sock_no_shutdown,
+       .setsockopt     = hci_sock_setsockopt,
+       .getsockopt     = hci_sock_getsockopt,
+       .connect        = sock_no_connect,
+       .socketpair     = sock_no_socketpair,
+       .accept         = sock_no_accept,
+       .mmap           = sock_no_mmap
+};
+
+static struct proto hci_sk_proto = {
+       .name           = "HCI",
+       .owner          = THIS_MODULE,
+       .obj_size       = sizeof(struct hci_pinfo)
 };
 
 static int hci_sock_create(struct socket *sock, int protocol)
@@ -590,14 +619,18 @@ static int hci_sock_create(struct socket *sock, int protocol)
 
        sock->ops = &hci_sock_ops;
 
-       sk = bt_sock_alloc(sock, protocol, sizeof(struct hci_pinfo), GFP_KERNEL);
+       sk = sk_alloc(PF_BLUETOOTH, GFP_KERNEL, &hci_sk_proto, 1);
        if (!sk)
                return -ENOMEM;
 
-       sk_set_owner(sk, THIS_MODULE);
+       sock_init_data(sock, sk);
+
+       sock_reset_flag(sk, SOCK_ZAPPED);
+
+       sk->sk_protocol = protocol;
 
        sock->state = SS_UNCONNECTED;
-       sk->sk_state   = BT_OPEN;
+       sk->sk_state = BT_OPEN;
 
        bt_sock_link(&hci_sk_list, sk);
        return 0;
@@ -607,14 +640,14 @@ static int hci_sock_dev_event(struct notifier_block *this, unsigned long event,
 {
        struct hci_dev *hdev = (struct hci_dev *) ptr;
        struct hci_ev_si_device ev;
-       
+
        BT_DBG("hdev %s event %ld", hdev->name, event);
 
        /* Send event to sockets */
        ev.event  = event;
        ev.dev_id = hdev->id;
        hci_si_event(NULL, HCI_EV_SI_DEVICE, sizeof(ev), &ev);
-       
+
        if (event == HCI_DEV_UNREG) {
                struct sock *sk;
                struct hlist_node *node;
@@ -639,35 +672,48 @@ static int hci_sock_dev_event(struct notifier_block *this, unsigned long event,
        return NOTIFY_DONE;
 }
 
-struct net_proto_family hci_sock_family_ops = {
-       .family = PF_BLUETOOTH,
+static struct net_proto_family hci_sock_family_ops = {
+       .family = PF_BLUETOOTH,
        .owner  = THIS_MODULE,
-       .create = hci_sock_create,
+       .create = hci_sock_create,
 };
 
-struct notifier_block hci_sock_nblock = {
+static struct notifier_block hci_sock_nblock = {
        .notifier_call = hci_sock_dev_event
 };
 
 int __init hci_sock_init(void)
 {
-       if (bt_sock_register(BTPROTO_HCI, &hci_sock_family_ops)) {
-               BT_ERR("HCI socket registration failed");
-               return -EPROTO;
-       }
+       int err;
+
+       err = proto_register(&hci_sk_proto, 0);
+       if (err < 0)
+               return err;
+
+       err = bt_sock_register(BTPROTO_HCI, &hci_sock_family_ops);
+       if (err < 0)
+               goto error;
 
        hci_register_notifier(&hci_sock_nblock);
 
        BT_INFO("HCI socket layer initialized");
 
        return 0;
+
+error:
+       BT_ERR("HCI socket registration failed");
+       proto_unregister(&hci_sk_proto);
+       return err;
 }
 
 int __exit hci_sock_cleanup(void)
 {
-       if (bt_sock_unregister(BTPROTO_HCI))
+       if (bt_sock_unregister(BTPROTO_HCI) < 0)
                BT_ERR("HCI socket unregistration failed");
 
        hci_unregister_notifier(&hci_sock_nblock);
+
+       proto_unregister(&hci_sk_proto);
+
        return 0;
 }