This commit was manufactured by cvs2svn to create tag
[linux-2.6.git] / net / bluetooth / sco.c
index ab9053b..0c2d13a 100644 (file)
    SOFTWARE IS DISCLAIMED.
 */
 
-/*
- * Bluetooth SCO sockets.
- *
- * $Id: sco.c,v 1.3 2002/04/17 17:37:16 maxk Exp $
- */
-#define VERSION "0.3"
+/* Bluetooth SCO sockets. */
 
 #include <linux/config.h>
 #include <linux/module.h>
@@ -35,7 +30,6 @@
 #include <linux/types.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>
@@ -44,8 +38,7 @@
 #include <linux/interrupt.h>
 #include <linux/socket.h>
 #include <linux/skbuff.h>
-#include <linux/proc_fs.h>
-#include <linux/seq_file.h>
+#include <linux/device.h>
 #include <linux/list.h>
 #include <net/sock.h>
 
 
 #ifndef CONFIG_BT_SCO_DEBUG
 #undef  BT_DBG
-#define BT_DBG( A... )
+#define BT_DBG(D...)
 #endif
 
-static struct proto_ops sco_sock_ops;
+#define VERSION "0.5"
+
+static const struct proto_ops sco_sock_ops;
 
 static struct bt_sock_list sco_sk_list = {
        .lock = RW_LOCK_UNLOCKED
@@ -94,17 +89,13 @@ static void sco_sock_timeout(unsigned long arg)
 static void sco_sock_set_timer(struct sock *sk, long timeout)
 {
        BT_DBG("sock %p state %d timeout %ld", sk, sk->sk_state, timeout);
-
-       if (!mod_timer(&sk->sk_timer, jiffies + timeout))
-               sock_hold(sk);
+       sk_reset_timer(sk, &sk->sk_timer, jiffies + timeout);
 }
 
 static void sco_sock_clear_timer(struct sock *sk)
 {
        BT_DBG("sock %p state %d", sk, sk->sk_state);
-
-       if (timer_pending(&sk->sk_timer) && del_timer(&sk->sk_timer))
-               __sock_put(sk);
+       sk_stop_timer(sk, &sk->sk_timer);
 }
 
 static void sco_sock_init_timer(struct sock *sk)
@@ -137,7 +128,7 @@ static struct sco_conn *sco_conn_add(struct hci_conn *hcon, __u8 status)
 
        conn->src = &hdev->bdaddr;
        conn->dst = &hcon->dst;
-       
+
        if (hdev->sco_mtu > 0)
                conn->mtu = hdev->sco_mtu;
        else
@@ -264,7 +255,7 @@ static inline int sco_send_frame(struct sock *sk, struct msghdr *msg, int len)
        }
 
        if ((err = hci_send_sco(conn->hcon, skb)) < 0)
-               goto fail;
+               return err;
 
        return count;
 
@@ -341,9 +332,6 @@ static void sco_sock_destruct(struct sock *sk)
 
        skb_queue_purge(&sk->sk_receive_queue);
        skb_queue_purge(&sk->sk_write_queue);
-
-       if (sk->sk_protinfo)
-               kfree(sk->sk_protinfo);
 }
 
 static void sco_sock_cleanup_listen(struct sock *parent)
@@ -359,7 +347,7 @@ static void sco_sock_cleanup_listen(struct sock *parent)
        }
 
        parent->sk_state  = BT_CLOSED;
-       parent->sk_zapped = 1;
+       sock_set_flag(parent, SOCK_ZAPPED);
 }
 
 /* Kill socket (only if zapped and orphan)
@@ -367,7 +355,7 @@ static void sco_sock_cleanup_listen(struct sock *parent)
  */
 static void sco_sock_kill(struct sock *sk)
 {
-       if (!sk->sk_zapped || sk->sk_socket)
+       if (!sock_flag(sk, SOCK_ZAPPED) || sk->sk_socket)
                return;
 
        BT_DBG("sk %p state %d", sk, sk->sk_state);
@@ -406,7 +394,7 @@ static void sco_sock_close(struct sock *sk)
                break;
 
        default:
-               sk->sk_zapped = 1;
+               sock_set_flag(sk, SOCK_ZAPPED);
                break;
        };
 
@@ -423,18 +411,29 @@ static void sco_sock_init(struct sock *sk, struct sock *parent)
                sk->sk_type = parent->sk_type;
 }
 
-static struct sock *sco_sock_alloc(struct socket *sock, int proto, int prio)
+static struct proto sco_proto = {
+       .name           = "SCO",
+       .owner          = THIS_MODULE,
+       .obj_size       = sizeof(struct sco_pinfo)
+};
+
+static struct sock *sco_sock_alloc(struct socket *sock, int proto, gfp_t prio)
 {
        struct sock *sk;
 
-       sk = bt_sock_alloc(sock, proto, sizeof(struct sco_pinfo), prio);
+       sk = sk_alloc(PF_BLUETOOTH, prio, &sco_proto, 1);
        if (!sk)
                return NULL;
 
-       sk_set_owner(sk, THIS_MODULE);
+       sock_init_data(sock, sk);
+       INIT_LIST_HEAD(&bt_sk(sk)->accept_q);
 
        sk->sk_destruct = sco_sock_destruct;
        sk->sk_sndtimeo = SCO_CONN_TIMEOUT;
+
+       sock_reset_flag(sk, SOCK_ZAPPED);
+
+       sk->sk_protocol = proto;
        sk->sk_state    = BT_OPEN;
 
        sco_sock_init_timer(sk);
@@ -483,7 +482,7 @@ static int sco_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_le
        }
 
        write_lock_bh(&sco_sk_list.lock);
-       
+
        if (bacmp(src, BDADDR_ANY) && __sco_get_sock_by_addr(src)) {
                err = -EADDRINUSE;
        } else {
@@ -491,7 +490,7 @@ static int sco_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_le
                bacpy(&bt_sk(sk)->src, &sa->sco_bdaddr);
                sk->sk_state = BT_BOUND;
        }
-       
+
        write_unlock_bh(&sco_sk_list.lock);
 
 done:
@@ -638,8 +637,9 @@ static int sco_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
 
        BT_DBG("sock %p, sk %p", sock, sk);
 
-       if (sk->sk_err)
-               return sock_error(sk);
+       err = sock_error(sk);
+       if (err)
+               return err;
 
        if (msg->msg_flags & MSG_OOB)
                return -EOPNOTSUPP;
@@ -655,7 +655,7 @@ static int sco_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
        return err;
 }
 
-static int sco_sock_setsockopt(struct socket *sock, int level, int optname, char *optval, int optlen)
+static int sco_sock_setsockopt(struct socket *sock, int level, int optname, char __user *optval, int optlen)
 {
        struct sock *sk = sock->sk;
        int err = 0;
@@ -674,7 +674,7 @@ static int sco_sock_setsockopt(struct socket *sock, int level, int optname, char
        return err;
 }
 
-static int sco_sock_getsockopt(struct socket *sock, int level, int optname, char *optval, int *optlen)
+static int sco_sock_getsockopt(struct socket *sock, int level, int optname, char __user *optval, int __user *optlen)
 {
        struct sock *sk = sock->sk;
        struct sco_options opts;
@@ -694,7 +694,7 @@ static int sco_sock_getsockopt(struct socket *sock, int level, int optname, char
                        err = -ENOTCONN;
                        break;
                }
-               
+
                opts.mtu = sco_pi(sk)->conn->mtu;
 
                BT_DBG("mtu %d", opts.mtu);
@@ -712,6 +712,7 @@ static int sco_sock_getsockopt(struct socket *sock, int level, int optname, char
                }
 
                cinfo.hci_handle = sco_pi(sk)->conn->hcon->handle;
+               memcpy(cinfo.dev_class, sco_pi(sk)->conn->hcon->dev_class, 3);
 
                len = min_t(unsigned int, len, sizeof(cinfo));
                if (copy_to_user(optval, (char *)&cinfo, len))
@@ -737,7 +738,7 @@ static int sco_sock_release(struct socket *sock)
 
        if (!sk)
                return 0;
-       
+
        sco_sock_close(sk);
 
        if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime) {
@@ -784,7 +785,7 @@ static void sco_chan_del(struct sock *sk, int err)
        sk->sk_err   = err;
        sk->sk_state_change(sk);
 
-       sk->sk_zapped = 1;
+       sock_set_flag(sk, SOCK_ZAPPED);
 }
 
 static void sco_conn_ready(struct sco_conn *conn)
@@ -811,7 +812,7 @@ static void sco_conn_ready(struct sco_conn *conn)
                sk = sco_sock_alloc(NULL, BTPROTO_SCO, GFP_ATOMIC);
                if (!sk) {
                        bh_unlock_sock(parent);
-                       goto done;
+                       goto done;
                }
 
                sco_sock_init(sk, parent);
@@ -820,14 +821,14 @@ static void sco_conn_ready(struct sco_conn *conn)
                bacpy(&bt_sk(sk)->dst, conn->dst);
 
                hci_conn_hold(conn->hcon);
-               __sco_chan_add(conn, sk, parent);
+               __sco_chan_add(conn, sk, parent);
 
-               sk->sk_state = BT_CONNECTED;
+               sk->sk_state = BT_CONNECTED;
 
                /* Wake up parent */
                parent->sk_data_ready(parent, 1);
-       
-               bh_unlock_sock(parent);
+
+               bh_unlock_sock(parent);
        }
 
 done:
@@ -858,7 +859,7 @@ static int sco_connect_cfm(struct hci_conn *hcon, __u8 status)
                        sco_conn_ready(conn);
        } else 
                sco_conn_del(hcon, bt_err(status));
-       
+
        return 0;
 }
 
@@ -892,167 +893,112 @@ drop:
        return 0;
 }
 
-/* ---- Proc fs support ---- */
-#ifdef CONFIG_PROC_FS
-static void *sco_seq_start(struct seq_file *seq, loff_t *pos)
+static ssize_t sco_sysfs_show(struct class *dev, char *buf)
 {
        struct sock *sk;
        struct hlist_node *node;
-       loff_t l = *pos;
+       char *str = buf;
 
        read_lock_bh(&sco_sk_list.lock);
 
-       sk_for_each(sk, node, &sco_sk_list.head)
-               if (!l--)
-                       goto found;
-       sk = NULL;
-found:
-       return sk;
-}
-
-static void *sco_seq_next(struct seq_file *seq, void *e, loff_t *pos)
-{
-       struct sock *sk = e;
-       (*pos)++;
-       return sk_next(sk);
-}
+       sk_for_each(sk, node, &sco_sk_list.head) {
+               str += sprintf(str, "%s %s %d\n",
+                               batostr(&bt_sk(sk)->src), batostr(&bt_sk(sk)->dst),
+                               sk->sk_state);
+       }
 
-static void sco_seq_stop(struct seq_file *seq, void *e)
-{
        read_unlock_bh(&sco_sk_list.lock);
-}
 
-static int  sco_seq_show(struct seq_file *seq, void *e)
-{
-       struct sock *sk = e;
-       seq_printf(seq, "%s %s %d\n",
-                       batostr(&bt_sk(sk)->src), batostr(&bt_sk(sk)->dst), sk->sk_state);
-       return 0;
-}
-
-static struct seq_operations sco_seq_ops = {
-       .start  = sco_seq_start,
-       .next   = sco_seq_next,
-       .stop   = sco_seq_stop,
-       .show   = sco_seq_show 
-};
-
-static int sco_seq_open(struct inode *inode, struct file *file)
-{
-       return seq_open(file, &sco_seq_ops);
-}
-
-static struct file_operations sco_seq_fops = {
-       .owner   = THIS_MODULE,
-       .open    = sco_seq_open,
-       .read    = seq_read,
-       .llseek  = seq_lseek,
-       .release = seq_release,
-};
-
-static int  __init sco_proc_init(void)
-{
-        struct proc_dir_entry *p = create_proc_entry("sco", S_IRUGO, proc_bt);
-        if (!p)
-                return -ENOMEM;
-       p->owner     = THIS_MODULE;
-        p->proc_fops = &sco_seq_fops;
-        return 0;
-}
-
-static void __exit sco_proc_cleanup(void)
-{
-        remove_proc_entry("sco", proc_bt);
-}
-
-#else /* CONFIG_PROC_FS */
-
-static int  __init sco_proc_init(void)
-{
-        return 0;
-}
-
-static void __exit sco_proc_cleanup(void)
-{
-        return;
-}
-#endif /* CONFIG_PROC_FS */
-
-static struct proto_ops sco_sock_ops = {
-       .family  =      PF_BLUETOOTH,
-       .owner   =      THIS_MODULE,
-       .release =      sco_sock_release,
-       .bind    =      sco_sock_bind,
-       .connect =      sco_sock_connect,
-       .listen  =      sco_sock_listen,
-       .accept  =      sco_sock_accept,
-       .getname =      sco_sock_getname,
-       .sendmsg =      sco_sock_sendmsg,
-       .recvmsg =      bt_sock_recvmsg,
-       .poll    =      bt_sock_poll,
-       .ioctl   =      sock_no_ioctl,
-       .mmap    =      sock_no_mmap,
-       .socketpair =   sock_no_socketpair,
-       .shutdown   =   sock_no_shutdown,
-       .setsockopt =   sco_sock_setsockopt,
-       .getsockopt =   sco_sock_getsockopt
+       return (str - buf);
+}
+
+static CLASS_ATTR(sco, S_IRUGO, sco_sysfs_show, NULL);
+
+static const struct proto_ops sco_sock_ops = {
+       .family         = PF_BLUETOOTH,
+       .owner          = THIS_MODULE,
+       .release        = sco_sock_release,
+       .bind           = sco_sock_bind,
+       .connect        = sco_sock_connect,
+       .listen         = sco_sock_listen,
+       .accept         = sco_sock_accept,
+       .getname        = sco_sock_getname,
+       .sendmsg        = sco_sock_sendmsg,
+       .recvmsg        = bt_sock_recvmsg,
+       .poll           = bt_sock_poll,
+       .ioctl          = sock_no_ioctl,
+       .mmap           = sock_no_mmap,
+       .socketpair     = sock_no_socketpair,
+       .shutdown       = sock_no_shutdown,
+       .setsockopt     = sco_sock_setsockopt,
+       .getsockopt     = sco_sock_getsockopt
 };
 
 static struct net_proto_family sco_sock_family_ops = {
-       .family =       PF_BLUETOOTH,
-       .create =       sco_sock_create,
-       .owner  =       THIS_MODULE,
+       .family = PF_BLUETOOTH,
+       .owner  = THIS_MODULE,
+       .create = sco_sock_create,
 };
 
 static struct hci_proto sco_hci_proto = {
-       .name =         "SCO",
-       .id   =         HCI_PROTO_SCO,
-       .connect_ind  sco_connect_ind,
-       .connect_cfm  sco_connect_cfm,
-       .disconn_ind  sco_disconn_ind,
-       .recv_scodata = sco_recv_scodata
+       .name           = "SCO",
+       .id             = HCI_PROTO_SCO,
+       .connect_ind    = sco_connect_ind,
+       .connect_cfm    = sco_connect_cfm,
+       .disconn_ind    = sco_disconn_ind,
+       .recv_scodata   = sco_recv_scodata
 };
 
 static int __init sco_init(void)
 {
        int err;
 
-       if ((err = bt_sock_register(BTPROTO_SCO, &sco_sock_family_ops))) {
-               BT_ERR("SCO socket registration failed");
+       err = proto_register(&sco_proto, 0);
+       if (err < 0)
                return err;
+
+       err = bt_sock_register(BTPROTO_SCO, &sco_sock_family_ops);
+       if (err < 0) {
+               BT_ERR("SCO socket registration failed");
+               goto error;
        }
 
-       if ((err = hci_register_proto(&sco_hci_proto))) {
+       err = hci_register_proto(&sco_hci_proto);
+       if (err < 0) {
                BT_ERR("SCO protocol registration failed");
-               return err;
+               bt_sock_unregister(BTPROTO_SCO);
+               goto error;
        }
 
-       sco_proc_init();
-       
+       class_create_file(&bt_class, &class_attr_sco);
+
        BT_INFO("SCO (Voice Link) ver %s", VERSION);
        BT_INFO("SCO socket layer initialized");
 
        return 0;
+
+error:
+       proto_unregister(&sco_proto);
+       return err;
 }
 
 static void __exit sco_exit(void)
 {
-       int err;
+       class_remove_file(&bt_class, &class_attr_sco);
 
-       sco_proc_cleanup();
+       if (bt_sock_unregister(BTPROTO_SCO) < 0)
+               BT_ERR("SCO socket unregistration failed");
 
-       /* Unregister socket, protocol and notifier */
-       if ((err = bt_sock_unregister(BTPROTO_SCO)))
-               BT_ERR("SCO socket unregistration failed. %d", err);
+       if (hci_unregister_proto(&sco_hci_proto) < 0)
+               BT_ERR("SCO protocol unregistration failed");
 
-       if ((err = hci_unregister_proto(&sco_hci_proto)))
-               BT_ERR("SCO protocol unregistration failed. %d", err);
+       proto_unregister(&sco_proto);
 }
 
 module_init(sco_init);
 module_exit(sco_exit);
 
-MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>");
+MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>, Marcel Holtmann <marcel@holtmann.org>");
 MODULE_DESCRIPTION("Bluetooth SCO ver " VERSION);
 MODULE_VERSION(VERSION);
 MODULE_LICENSE("GPL");