SUNRPC: Fix xs_setup_bc_tcp()
[safe/jmp/linux-2.6] / net / bluetooth / sco.c
index 93ad1aa..ca6b2ad 100644 (file)
@@ -38,6 +38,8 @@
 #include <linux/socket.h>
 #include <linux/skbuff.h>
 #include <linux/device.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
 #include <linux/list.h>
 #include <net/sock.h>
 
 #include <net/bluetooth/hci_core.h>
 #include <net/bluetooth/sco.h>
 
-#ifndef CONFIG_BT_SCO_DEBUG
-#undef  BT_DBG
-#define BT_DBG(D...)
-#endif
+#define VERSION "0.6"
 
-#define VERSION "0.5"
+static int disable_esco = 0;
 
 static const struct proto_ops sco_sock_ops;
 
 static struct bt_sock_list sco_sk_list = {
-       .lock = RW_LOCK_UNLOCKED
+       .lock = __RW_LOCK_UNLOCKED(sco_sk_list.lock)
 };
 
 static void __sco_chan_add(struct sco_conn *conn, struct sock *sk, struct sock *parent);
@@ -97,13 +96,6 @@ static void sco_sock_clear_timer(struct sock *sk)
        sk_stop_timer(sk, &sk->sk_timer);
 }
 
-static void sco_sock_init_timer(struct sock *sk)
-{
-       init_timer(&sk->sk_timer);
-       sk->sk_timer.function = sco_sock_timeout;
-       sk->sk_timer.data = (unsigned long)sk;
-}
-
 /* ---- SCO connections ---- */
 static struct sco_conn *sco_conn_add(struct hci_conn *hcon, __u8 status)
 {
@@ -200,9 +192,12 @@ static int sco_connect(struct sock *sk)
 
        err = -ENOMEM;
 
-       type = lmp_esco_capable(hdev) ? ESCO_LINK : SCO_LINK;
+       if (lmp_esco_capable(hdev) && !disable_esco)
+               type = ESCO_LINK;
+       else
+               type = SCO_LINK;
 
-       hcon = hci_connect(hdev, type, dst);
+       hcon = hci_connect(hdev, type, dst, BT_SECURITY_LOW, HCI_AT_NO_BONDING);
        if (!hcon)
                goto done;
 
@@ -366,20 +361,9 @@ static void sco_sock_kill(struct sock *sk)
        sock_put(sk);
 }
 
-/* Close socket.
- * Must be called on unlocked socket.
- */
-static void sco_sock_close(struct sock *sk)
+static void __sco_sock_close(struct sock *sk)
 {
-       struct sco_conn *conn;
-
-       sco_sock_clear_timer(sk);
-
-       lock_sock(sk);
-
-       conn = sco_pi(sk)->conn;
-
-       BT_DBG("sk %p state %d conn %p socket %p", sk, sk->sk_state, conn, sk->sk_socket);
+       BT_DBG("sk %p state %d socket %p", sk, sk->sk_state, sk->sk_socket);
 
        switch (sk->sk_state) {
        case BT_LISTEN:
@@ -397,9 +381,15 @@ static void sco_sock_close(struct sock *sk)
                sock_set_flag(sk, SOCK_ZAPPED);
                break;
        }
+}
 
+/* Must be called on unlocked socket. */
+static void sco_sock_close(struct sock *sk)
+{
+       sco_sock_clear_timer(sk);
+       lock_sock(sk);
+       __sco_sock_close(sk);
        release_sock(sk);
-
        sco_sock_kill(sk);
 }
 
@@ -436,13 +426,14 @@ static struct sock *sco_sock_alloc(struct net *net, struct socket *sock, int pro
        sk->sk_protocol = proto;
        sk->sk_state    = BT_OPEN;
 
-       sco_sock_init_timer(sk);
+       setup_timer(&sk->sk_timer, sco_sock_timeout, (unsigned long)sk);
 
        bt_sock_link(&sco_sk_list, sk);
        return sk;
 }
 
-static int sco_sock_create(struct net *net, struct socket *sock, int protocol)
+static int sco_sock_create(struct net *net, struct socket *sock, int protocol,
+                          int kern)
 {
        struct sock *sk;
 
@@ -508,7 +499,8 @@ static int sco_sock_connect(struct socket *sock, struct sockaddr *addr, int alen
 
        BT_DBG("sk %p", sk);
 
-       if (addr->sa_family != AF_BLUETOOTH || alen < sizeof(struct sockaddr_sco))
+       if (alen < sizeof(struct sockaddr_sco) ||
+           addr->sa_family != AF_BLUETOOTH)
                return -EINVAL;
 
        if (sk->sk_state != BT_OPEN && sk->sk_state != BT_BOUND)
@@ -656,7 +648,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 __user *optval, int optlen)
+static int sco_sock_setsockopt(struct socket *sock, int level, int optname, char __user *optval, unsigned int optlen)
 {
        struct sock *sk = sock->sk;
        int err = 0;
@@ -675,7 +667,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 __user *optval, int __user *optlen)
+static int sco_sock_getsockopt_old(struct socket *sock, int optname, char __user *optval, int __user *optlen)
 {
        struct sock *sk = sock->sk;
        struct sco_options opts;
@@ -730,6 +722,55 @@ static int sco_sock_getsockopt(struct socket *sock, int level, int optname, char
        return err;
 }
 
+static int sco_sock_getsockopt(struct socket *sock, int level, int optname, char __user *optval, int __user *optlen)
+{
+       struct sock *sk = sock->sk;
+       int len, err = 0;
+
+       BT_DBG("sk %p", sk);
+
+       if (level == SOL_SCO)
+               return sco_sock_getsockopt_old(sock, optname, optval, optlen);
+
+       if (get_user(len, optlen))
+               return -EFAULT;
+
+       lock_sock(sk);
+
+       switch (optname) {
+       default:
+               err = -ENOPROTOOPT;
+               break;
+       }
+
+       release_sock(sk);
+       return err;
+}
+
+static int sco_sock_shutdown(struct socket *sock, int how)
+{
+       struct sock *sk = sock->sk;
+       int err = 0;
+
+       BT_DBG("sock %p, sk %p", sock, sk);
+
+       if (!sk)
+               return 0;
+
+       lock_sock(sk);
+       if (!sk->sk_shutdown) {
+               sk->sk_shutdown = SHUTDOWN_MASK;
+               sco_sock_clear_timer(sk);
+               __sco_sock_close(sk);
+
+               if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime)
+                       err = bt_sock_wait_state(sk, BT_CLOSED,
+                                                       sk->sk_lingertime);
+       }
+       release_sock(sk);
+       return err;
+}
+
 static int sco_sock_release(struct socket *sock)
 {
        struct sock *sk = sock->sk;
@@ -810,7 +851,7 @@ static void sco_conn_ready(struct sco_conn *conn)
 
                bh_lock_sock(parent);
 
-               sk = sco_sock_alloc(parent->sk_net, NULL, BTPROTO_SCO, GFP_ATOMIC);
+               sk = sco_sock_alloc(sock_net(parent), NULL, BTPROTO_SCO, GFP_ATOMIC);
                if (!sk) {
                        bh_unlock_sock(parent);
                        goto done;
@@ -839,10 +880,30 @@ done:
 /* ----- SCO interface with lower layer (HCI) ----- */
 static int sco_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 type)
 {
+       register struct sock *sk;
+       struct hlist_node *node;
+       int lm = 0;
+
+       if (type != SCO_LINK && type != ESCO_LINK)
+               return 0;
+
        BT_DBG("hdev %s, bdaddr %s", hdev->name, batostr(bdaddr));
 
-       /* Always accept connection */
-       return HCI_LM_ACCEPT;
+       /* Find listening sockets */
+       read_lock(&sco_sk_list.lock);
+       sk_for_each(sk, node, &sco_sk_list.head) {
+               if (sk->sk_state != BT_LISTEN)
+                       continue;
+
+               if (!bacmp(&bt_sk(sk)->src, &hdev->bdaddr) ||
+                               !bacmp(&bt_sk(sk)->src, BDADDR_ANY)) {
+                       lm |= HCI_LM_ACCEPT;
+                       break;
+               }
+       }
+       read_unlock(&sco_sk_list.lock);
+
+       return lm;
 }
 
 static int sco_connect_cfm(struct hci_conn *hcon, __u8 status)
@@ -864,7 +925,7 @@ static int sco_connect_cfm(struct hci_conn *hcon, __u8 status)
        return 0;
 }
 
-static int sco_disconn_ind(struct hci_conn *hcon, __u8 reason)
+static int sco_disconn_cfm(struct hci_conn *hcon, __u8 reason)
 {
        BT_DBG("hcon %p reason %d", hcon, reason);
 
@@ -895,26 +956,36 @@ drop:
        return 0;
 }
 
-static ssize_t sco_sysfs_show(struct class *dev, char *buf)
+static int sco_debugfs_show(struct seq_file *f, void *p)
 {
        struct sock *sk;
        struct hlist_node *node;
-       char *str = buf;
 
        read_lock_bh(&sco_sk_list.lock);
 
        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);
+               seq_printf(f, "%s %s %d\n", batostr(&bt_sk(sk)->src),
+                               batostr(&bt_sk(sk)->dst), sk->sk_state);
        }
 
        read_unlock_bh(&sco_sk_list.lock);
 
-       return (str - buf);
+       return 0;
+}
+
+static int sco_debugfs_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, sco_debugfs_show, inode->i_private);
 }
 
-static CLASS_ATTR(sco, S_IRUGO, sco_sysfs_show, NULL);
+static const struct file_operations sco_debugfs_fops = {
+       .open           = sco_debugfs_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
+static struct dentry *sco_debugfs;
 
 static const struct proto_ops sco_sock_ops = {
        .family         = PF_BLUETOOTH,
@@ -928,15 +999,15 @@ static const struct proto_ops sco_sock_ops = {
        .sendmsg        = sco_sock_sendmsg,
        .recvmsg        = bt_sock_recvmsg,
        .poll           = bt_sock_poll,
-       .ioctl          = sock_no_ioctl,
+       .ioctl          = bt_sock_ioctl,
        .mmap           = sock_no_mmap,
        .socketpair     = sock_no_socketpair,
-       .shutdown       = sock_no_shutdown,
+       .shutdown       = sco_sock_shutdown,
        .setsockopt     = sco_sock_setsockopt,
        .getsockopt     = sco_sock_getsockopt
 };
 
-static struct net_proto_family sco_sock_family_ops = {
+static const struct net_proto_family sco_sock_family_ops = {
        .family = PF_BLUETOOTH,
        .owner  = THIS_MODULE,
        .create = sco_sock_create,
@@ -947,7 +1018,7 @@ static struct hci_proto sco_hci_proto = {
        .id             = HCI_PROTO_SCO,
        .connect_ind    = sco_connect_ind,
        .connect_cfm    = sco_connect_cfm,
-       .disconn_ind    = sco_disconn_ind,
+       .disconn_cfm    = sco_disconn_cfm,
        .recv_scodata   = sco_recv_scodata
 };
 
@@ -972,8 +1043,12 @@ static int __init sco_init(void)
                goto error;
        }
 
-       if (class_create_file(bt_class, &class_attr_sco) < 0)
-               BT_ERR("Failed to create SCO info file");
+       if (bt_debugfs) {
+               sco_debugfs = debugfs_create_file("sco", 0444,
+                                       bt_debugfs, NULL, &sco_debugfs_fops);
+               if (!sco_debugfs)
+                       BT_ERR("Failed to create SCO debug file");
+       }
 
        BT_INFO("SCO (Voice Link) ver %s", VERSION);
        BT_INFO("SCO socket layer initialized");
@@ -987,7 +1062,7 @@ error:
 
 static void __exit sco_exit(void)
 {
-       class_remove_file(bt_class, &class_attr_sco);
+       debugfs_remove(sco_debugfs);
 
        if (bt_sock_unregister(BTPROTO_SCO) < 0)
                BT_ERR("SCO socket unregistration failed");
@@ -1001,7 +1076,10 @@ static void __exit sco_exit(void)
 module_init(sco_init);
 module_exit(sco_exit);
 
-MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>, Marcel Holtmann <marcel@holtmann.org>");
+module_param(disable_esco, bool, 0644);
+MODULE_PARM_DESC(disable_esco, "Disable eSCO connection creation");
+
+MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
 MODULE_DESCRIPTION("Bluetooth SCO ver " VERSION);
 MODULE_VERSION(VERSION);
 MODULE_LICENSE("GPL");