]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - android-sdk/kernel-video.git/blobdiff - net/bluetooth/sco.c
Merge branch 'p-ti-linux-3.8.y' into p-ti-android-3.8.y
[android-sdk/kernel-video.git] / net / bluetooth / sco.c
index 57f250c20e399851ca6998d9813dc60e3ffa3455..2ea5b06cb794abba9410123eaccd82178a5be094 100644 (file)
@@ -158,6 +158,7 @@ static int sco_connect(struct sock *sk)
 {
        bdaddr_t *src = &bt_sk(sk)->src;
        bdaddr_t *dst = &bt_sk(sk)->dst;
+       __u16 pkt_type = sco_pi(sk)->pkt_type;
        struct sco_conn *conn;
        struct hci_conn *hcon;
        struct hci_dev  *hdev;
@@ -173,11 +174,13 @@ static int sco_connect(struct sock *sk)
 
        if (lmp_esco_capable(hdev) && !disable_esco)
                type = ESCO_LINK;
-       else
+       else {
                type = SCO_LINK;
+               pkt_type &= SCO_ESCO_MASK;
+       }
 
-       hcon = hci_connect(hdev, type, dst, BDADDR_BREDR, BT_SECURITY_LOW,
-                          HCI_AT_NO_BONDING);
+       hcon = hci_connect(hdev, type, pkt_type, dst, BDADDR_BREDR,
+                          BT_SECURITY_LOW, HCI_AT_NO_BONDING);
        if (IS_ERR(hcon)) {
                err = PTR_ERR(hcon);
                goto done;
@@ -361,6 +364,7 @@ static void __sco_sock_close(struct sock *sk)
                        sco_chan_del(sk, ECONNRESET);
                break;
 
+       case BT_CONNECT2:
        case BT_CONNECT:
        case BT_DISCONN:
                sco_chan_del(sk, ECONNRESET);
@@ -446,17 +450,21 @@ static int sco_sock_create(struct net *net, struct socket *sock, int protocol,
        return 0;
 }
 
-static int sco_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_len)
+static int sco_sock_bind(struct socket *sock, struct sockaddr *addr, int alen)
 {
-       struct sockaddr_sco *sa = (struct sockaddr_sco *) addr;
+       struct sockaddr_sco sa;
        struct sock *sk = sock->sk;
-       int err = 0;
+       int len, err = 0;
 
-       BT_DBG("sk %p %pMR", sk, &sa->sco_bdaddr);
+       BT_DBG("sk %p %pMR", sk, &sa.sco_bdaddr);
 
        if (!addr || addr->sa_family != AF_BLUETOOTH)
                return -EINVAL;
 
+       memset(&sa, 0, sizeof(sa));
+       len = min_t(unsigned int, sizeof(sa), alen);
+       memcpy(&sa, addr, len);
+
        lock_sock(sk);
 
        if (sk->sk_state != BT_OPEN) {
@@ -469,7 +477,8 @@ static int sco_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_le
                goto done;
        }
 
-       bacpy(&bt_sk(sk)->src, &sa->sco_bdaddr);
+       bacpy(&bt_sk(sk)->src, &sa.sco_bdaddr);
+       sco_pi(sk)->pkt_type = sa.sco_pkt_type;
 
        sk->sk_state = BT_BOUND;
 
@@ -480,27 +489,34 @@ done:
 
 static int sco_sock_connect(struct socket *sock, struct sockaddr *addr, int alen, int flags)
 {
-       struct sockaddr_sco *sa = (struct sockaddr_sco *) addr;
        struct sock *sk = sock->sk;
-       int err = 0;
-
+       struct sockaddr_sco sa;
+       int len, err = 0;
 
        BT_DBG("sk %p", sk);
 
-       if (alen < sizeof(struct sockaddr_sco) ||
-           addr->sa_family != AF_BLUETOOTH)
+       if (!addr || addr->sa_family != AF_BLUETOOTH)
                return -EINVAL;
 
-       if (sk->sk_state != BT_OPEN && sk->sk_state != BT_BOUND)
-               return -EBADFD;
-
-       if (sk->sk_type != SOCK_SEQPACKET)
-               return -EINVAL;
+       memset(&sa, 0, sizeof(sa));
+       len = min_t(unsigned int, sizeof(sa), alen);
+       memcpy(&sa, addr, len);
 
        lock_sock(sk);
 
+       if (sk->sk_type != SOCK_SEQPACKET) {
+               err = -EINVAL;
+               goto done;
+       }
+
+       if (sk->sk_state != BT_OPEN && sk->sk_state != BT_BOUND) {
+               err = -EBADFD;
+               goto done;
+       }
+
        /* Set destination address and psm */
-       bacpy(&bt_sk(sk)->dst, &sa->sco_bdaddr);
+       bacpy(&bt_sk(sk)->dst, &sa.sco_bdaddr);
+       sco_pi(sk)->pkt_type = sa.sco_pkt_type;
 
        err = sco_connect(sk);
        if (err)
@@ -624,6 +640,7 @@ static int sco_sock_getname(struct socket *sock, struct sockaddr *addr, int *len
                bacpy(&sa->sco_bdaddr, &bt_sk(sk)->dst);
        else
                bacpy(&sa->sco_bdaddr, &bt_sk(sk)->src);
+       sa->sco_pkt_type = sco_pi(sk)->pkt_type;
 
        return 0;
 }
@@ -666,6 +683,7 @@ static int sco_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
            test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags)) {
                hci_conn_accept(pi->conn->hcon, 0);
                sk->sk_state = BT_CONFIG;
+               msg->msg_namelen = 0;
 
                release_sock(sk);
                return 0;
@@ -900,8 +918,6 @@ static void sco_conn_ready(struct sco_conn *conn)
 
        BT_DBG("conn %p", conn);
 
-       sco_conn_lock(conn);
-
        if (sk) {
                sco_sock_clear_timer(sk);
                bh_lock_sock(sk);
@@ -909,9 +925,13 @@ static void sco_conn_ready(struct sco_conn *conn)
                sk->sk_state_change(sk);
                bh_unlock_sock(sk);
        } else {
+               sco_conn_lock(conn);
+
                parent = sco_get_sock_listen(conn->src);
-               if (!parent)
-                       goto done;
+               if (!parent) {
+                       sco_conn_unlock(conn);
+                       return;
+               }
 
                bh_lock_sock(parent);
 
@@ -919,7 +939,8 @@ static void sco_conn_ready(struct sco_conn *conn)
                                    BTPROTO_SCO, GFP_ATOMIC);
                if (!sk) {
                        bh_unlock_sock(parent);
-                       goto done;
+                       sco_conn_unlock(conn);
+                       return;
                }
 
                sco_sock_init(sk, parent);
@@ -939,10 +960,9 @@ static void sco_conn_ready(struct sco_conn *conn)
                parent->sk_data_ready(parent, 1);
 
                bh_unlock_sock(parent);
-       }
 
-done:
-       sco_conn_unlock(conn);
+               sco_conn_unlock(conn);
+       }
 }
 
 /* ----- SCO interface with lower layer (HCI) ----- */