]> Pileus Git - ~andy/linux/blobdiff - net/bluetooth/sco.c
Merge branch 'for-john' of git://git.kernel.org/pub/scm/linux/kernel/git/iwlwifi...
[~andy/linux] / net / bluetooth / sco.c
index f6ab12907963fac3d5e3ed6bae46d10b28ee52db..40bbe25dcff7f97c9a279c6d087eaed078563364 100644 (file)
 /* Bluetooth SCO sockets. */
 
 #include <linux/module.h>
-
-#include <linux/types.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>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#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 <linux/security.h>
-#include <net/sock.h>
-
-#include <linux/uaccess.h>
 
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/hci_core.h>
@@ -61,8 +43,6 @@ static struct bt_sock_list sco_sk_list = {
 static void __sco_chan_add(struct sco_conn *conn, struct sock *sk, struct sock *parent);
 static void sco_chan_del(struct sock *sk, int err);
 
-static int  sco_conn_del(struct hci_conn *conn, int err);
-
 static void sco_sock_close(struct sock *sk);
 static void sco_sock_kill(struct sock *sk);
 
@@ -95,12 +75,12 @@ static void sco_sock_clear_timer(struct sock *sk)
 }
 
 /* ---- SCO connections ---- */
-static struct sco_conn *sco_conn_add(struct hci_conn *hcon, __u8 status)
+static struct sco_conn *sco_conn_add(struct hci_conn *hcon)
 {
        struct hci_dev *hdev = hcon->hdev;
        struct sco_conn *conn = hcon->sco_data;
 
-       if (conn || status)
+       if (conn)
                return conn;
 
        conn = kzalloc(sizeof(struct sco_conn), GFP_ATOMIC);
@@ -125,7 +105,7 @@ static struct sco_conn *sco_conn_add(struct hci_conn *hcon, __u8 status)
        return conn;
 }
 
-static inline struct sock *sco_chan_get(struct sco_conn *conn)
+static struct sock *sco_chan_get(struct sco_conn *conn)
 {
        struct sock *sk = NULL;
        sco_conn_lock(conn);
@@ -159,7 +139,8 @@ static int sco_conn_del(struct hci_conn *hcon, int err)
        return 0;
 }
 
-static inline int sco_chan_add(struct sco_conn *conn, struct sock *sk, struct sock *parent)
+static int sco_chan_add(struct sco_conn *conn, struct sock *sk,
+                       struct sock *parent)
 {
        int err = 0;
 
@@ -195,13 +176,14 @@ static int sco_connect(struct sock *sk)
        else
                type = SCO_LINK;
 
-       hcon = hci_connect(hdev, type, dst, BT_SECURITY_LOW, HCI_AT_NO_BONDING);
+       hcon = hci_connect(hdev, type, dst, BDADDR_BREDR, BT_SECURITY_LOW,
+                          HCI_AT_NO_BONDING);
        if (IS_ERR(hcon)) {
                err = PTR_ERR(hcon);
                goto done;
        }
 
-       conn = sco_conn_add(hcon, 0);
+       conn = sco_conn_add(hcon);
        if (!conn) {
                hci_conn_put(hcon);
                err = -ENOMEM;
@@ -229,11 +211,11 @@ done:
        return err;
 }
 
-static inline int sco_send_frame(struct sock *sk, struct msghdr *msg, int len)
+static int sco_send_frame(struct sock *sk, struct msghdr *msg, int len)
 {
        struct sco_conn *conn = sco_pi(sk)->conn;
        struct sk_buff *skb;
-       int err, count;
+       int err;
 
        /* Check outgoing MTU */
        if (len > conn->mtu)
@@ -241,23 +223,21 @@ 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);
-       skb = bt_skb_send_alloc(sk, count,
-                       msg->msg_flags & MSG_DONTWAIT, &err);
+       skb = bt_skb_send_alloc(sk, len, msg->msg_flags & MSG_DONTWAIT, &err);
        if (!skb)
                return err;
 
-       if (memcpy_fromiovec(skb_put(skb, count), msg->msg_iov, count)) {
+       if (memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len)) {
                kfree_skb(skb);
                return -EFAULT;
        }
 
        hci_send_sco(conn->hcon, skb);
 
-       return count;
+       return len;
 }
 
-static inline void sco_recv_frame(struct sco_conn *conn, struct sk_buff *skb)
+static void sco_recv_frame(struct sco_conn *conn, struct sk_buff *skb)
 {
        struct sock *sk = sco_chan_get(conn);
 
@@ -277,17 +257,20 @@ drop:
 }
 
 /* -------- Socket interface ---------- */
-static struct sock *__sco_get_sock_by_addr(bdaddr_t *ba)
+static struct sock *__sco_get_sock_listen_by_addr(bdaddr_t *ba)
 {
-       struct sock *sk;
        struct hlist_node *node;
+       struct sock *sk;
+
+       sk_for_each(sk, node, &sco_sk_list.head) {
+               if (sk->sk_state != BT_LISTEN)
+                       continue;
 
-       sk_for_each(sk, node, &sco_sk_list.head)
                if (!bacmp(&bt_sk(sk)->src, ba))
-                       goto found;
-       sk = NULL;
-found:
-       return sk;
+                       return sk;
+       }
+
+       return NULL;
 }
 
 /* Find socket listening on source bdaddr.
@@ -466,7 +449,6 @@ static int sco_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_le
 {
        struct sockaddr_sco *sa = (struct sockaddr_sco *) addr;
        struct sock *sk = sock->sk;
-       bdaddr_t *src = &sa->sco_bdaddr;
        int err = 0;
 
        BT_DBG("sk %p %s", sk, batostr(&sa->sco_bdaddr));
@@ -481,17 +463,14 @@ static int sco_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_le
                goto done;
        }
 
-       write_lock(&sco_sk_list.lock);
-
-       if (bacmp(src, BDADDR_ANY) && __sco_get_sock_by_addr(src)) {
-               err = -EADDRINUSE;
-       } else {
-               /* Save source address */
-               bacpy(&bt_sk(sk)->src, &sa->sco_bdaddr);
-               sk->sk_state = BT_BOUND;
+       if (sk->sk_type != SOCK_SEQPACKET) {
+               err = -EINVAL;
+               goto done;
        }
 
-       write_unlock(&sco_sk_list.lock);
+       bacpy(&bt_sk(sk)->src, &sa->sco_bdaddr);
+
+       sk->sk_state = BT_BOUND;
 
 done:
        release_sock(sk);
@@ -527,7 +506,7 @@ static int sco_sock_connect(struct socket *sock, struct sockaddr *addr, int alen
                goto done;
 
        err = bt_sock_wait_state(sk, BT_CONNECTED,
-                       sock_sndtimeo(sk, flags & O_NONBLOCK));
+                                sock_sndtimeo(sk, flags & O_NONBLOCK));
 
 done:
        release_sock(sk);
@@ -537,21 +516,38 @@ done:
 static int sco_sock_listen(struct socket *sock, int backlog)
 {
        struct sock *sk = sock->sk;
+       bdaddr_t *src = &bt_sk(sk)->src;
        int err = 0;
 
        BT_DBG("sk %p backlog %d", sk, backlog);
 
        lock_sock(sk);
 
-       if (sk->sk_state != BT_BOUND || sock->type != SOCK_SEQPACKET) {
+       if (sk->sk_state != BT_BOUND) {
                err = -EBADFD;
                goto done;
        }
 
+       if (sk->sk_type != SOCK_SEQPACKET) {
+               err = -EINVAL;
+               goto done;
+       }
+
+       write_lock(&sco_sk_list.lock);
+
+       if (__sco_get_sock_listen_by_addr(src)) {
+               err = -EADDRINUSE;
+               goto unlock;
+       }
+
        sk->sk_max_ack_backlog = backlog;
        sk->sk_ack_backlog = 0;
+
        sk->sk_state = BT_LISTEN;
 
+unlock:
+       write_unlock(&sco_sk_list.lock);
+
 done:
        release_sock(sk);
        return err;
@@ -775,7 +771,7 @@ static int sco_sock_shutdown(struct socket *sock, int how)
 
                if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime)
                        err = bt_sock_wait_state(sk, BT_CLOSED,
-                                                       sk->sk_lingertime);
+                                                sk->sk_lingertime);
        }
        release_sock(sk);
        return err;
@@ -865,7 +861,7 @@ 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);
+                                   BTPROTO_SCO, GFP_ATOMIC);
                if (!sk) {
                        bh_unlock_sock(parent);
                        goto done;
@@ -894,7 +890,7 @@ done:
 /* ----- SCO interface with lower layer (HCI) ----- */
 int sco_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr)
 {
-       register struct sock *sk;
+       struct sock *sk;
        struct hlist_node *node;
        int lm = 0;
 
@@ -907,7 +903,7 @@ int sco_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr)
                        continue;
 
                if (!bacmp(&bt_sk(sk)->src, &hdev->bdaddr) ||
-                               !bacmp(&bt_sk(sk)->src, BDADDR_ANY)) {
+                   !bacmp(&bt_sk(sk)->src, BDADDR_ANY)) {
                        lm |= HCI_LM_ACCEPT;
                        break;
                }
@@ -923,7 +919,7 @@ int sco_connect_cfm(struct hci_conn *hcon, __u8 status)
        if (!status) {
                struct sco_conn *conn;
 
-               conn = sco_conn_add(hcon, status);
+               conn = sco_conn_add(hcon);
                if (conn)
                        sco_conn_ready(conn);
        } else
@@ -968,7 +964,7 @@ static int sco_debugfs_show(struct seq_file *f, void *p)
 
        sk_for_each(sk, node, &sco_sk_list.head) {
                seq_printf(f, "%s %s %d\n", batostr(&bt_sk(sk)->src),
-                               batostr(&bt_sk(sk)->dst), sk->sk_state);
+                          batostr(&bt_sk(sk)->dst), sk->sk_state);
        }
 
        read_unlock(&sco_sk_list.lock);
@@ -1031,8 +1027,8 @@ int __init sco_init(void)
        }
 
        if (bt_debugfs) {
-               sco_debugfs = debugfs_create_file("sco", 0444,
-                                       bt_debugfs, NULL, &sco_debugfs_fops);
+               sco_debugfs = debugfs_create_file("sco", 0444, bt_debugfs,
+                                                 NULL, &sco_debugfs_fops);
                if (!sco_debugfs)
                        BT_ERR("Failed to create SCO debug file");
        }