Bluetooth: Add module parameter for txWindow size on L2CAP
[safe/jmp/linux-2.6] / net / bluetooth / sco.c
index 71df982..4767928 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>
 
@@ -163,11 +165,11 @@ static inline int sco_chan_add(struct sco_conn *conn, struct sock *sk, struct so
        int err = 0;
 
        sco_conn_lock(conn);
-       if (conn->sk) {
+       if (conn->sk)
                err = -EBUSY;
-       } else {
+       else
                __sco_chan_add(conn, sk, parent);
-       }
+
        sco_conn_unlock(conn);
        return err;
 }
@@ -195,7 +197,7 @@ static int sco_connect(struct sock *sk)
        else
                type = SCO_LINK;
 
-       hcon = hci_connect(hdev, type, dst, HCI_AT_NO_BONDING);
+       hcon = hci_connect(hdev, type, dst, BT_SECURITY_LOW, HCI_AT_NO_BONDING);
        if (!hcon)
                goto done;
 
@@ -239,22 +241,19 @@ static inline int sco_send_frame(struct sock *sk, struct msghdr *msg, int len)
        BT_DBG("sk %p len %d", sk, len);
 
        count = min_t(unsigned int, conn->mtu, len);
-       if (!(skb = bt_skb_send_alloc(sk, count, msg->msg_flags & MSG_DONTWAIT, &err)))
+       skb = bt_skb_send_alloc(sk, count,
+                       msg->msg_flags & MSG_DONTWAIT, &err);
+       if (!skb)
                return err;
 
        if (memcpy_fromiovec(skb_put(skb, count), msg->msg_iov, count)) {
-               err = -EFAULT;
-               goto fail;
+               kfree_skb(skb);
+               return -EFAULT;
        }
 
-       if ((err = hci_send_sco(conn->hcon, skb)) < 0)
-               return err;
+       hci_send_sco(conn->hcon, skb);
 
        return count;
-
-fail:
-       kfree_skb(skb);
-       return err;
 }
 
 static inline void sco_recv_frame(struct sco_conn *conn, struct sk_buff *skb)
@@ -359,20 +358,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:
@@ -390,9 +378,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);
 }
 
@@ -435,7 +429,8 @@ static struct sock *sco_sock_alloc(struct net *net, struct socket *sock, int pro
        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;
 
@@ -501,7 +496,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)
@@ -568,7 +564,7 @@ static int sco_sock_accept(struct socket *sock, struct socket *newsock, int flag
        BT_DBG("sk %p timeo %ld", sk, timeo);
 
        /* Wait for an incoming connection. (wake-one). */
-       add_wait_queue_exclusive(sk->sk_sleep, &wait);
+       add_wait_queue_exclusive(sk_sleep(sk), &wait);
        while (!(ch = bt_accept_dequeue(sk, newsock))) {
                set_current_state(TASK_INTERRUPTIBLE);
                if (!timeo) {
@@ -591,7 +587,7 @@ static int sco_sock_accept(struct socket *sock, struct socket *newsock, int flag
                }
        }
        set_current_state(TASK_RUNNING);
-       remove_wait_queue(sk->sk_sleep, &wait);
+       remove_wait_queue(sk_sleep(sk), &wait);
 
        if (err)
                goto done;
@@ -627,7 +623,7 @@ static int sco_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
                            struct msghdr *msg, size_t len)
 {
        struct sock *sk = sock->sk;
-       int err = 0;
+       int err;
 
        BT_DBG("sock %p, sk %p", sock, sk);
 
@@ -649,7 +645,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;
@@ -748,6 +744,30 @@ static int sco_sock_getsockopt(struct socket *sock, int level, int optname, char
        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;
@@ -828,7 +848,8 @@ static void sco_conn_ready(struct sco_conn *conn)
 
                bh_lock_sock(parent);
 
-               sk = sco_sock_alloc(sock_net(parent), 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;
@@ -902,7 +923,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);
 
@@ -933,26 +954,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 CLASS_ATTR(sco, S_IRUGO, sco_sysfs_show, NULL);
+static int sco_debugfs_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, sco_debugfs_show, inode->i_private);
+}
+
+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,
@@ -969,12 +1000,12 @@ static const struct proto_ops sco_sock_ops = {
        .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,
@@ -985,7 +1016,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
 };
 
@@ -1010,8 +1041,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");
@@ -1025,7 +1060,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");