Merge remote-tracking branch 'linux-2.6.32.y/master' into develop
[firefly-linux-kernel-4.4.55.git] / net / bluetooth / sco.c
index e52443ce4f9c2cc9a1fe3f60eef59be98b9eb2ea..f9d52fae8d192baf8ec26b46402eea27bd15a192 100644 (file)
@@ -176,6 +176,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;
@@ -192,10 +193,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, BT_SECURITY_LOW, HCI_AT_NO_BONDING);
+       hcon = hci_connect(hdev, type, pkt_type, dst,
+                                       BT_SECURITY_LOW, HCI_AT_NO_BONDING);
        if (!hcon)
                goto done;
 
@@ -451,18 +455,22 @@ 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;
-       bdaddr_t *src = &sa->sco_bdaddr;
-       int err = 0;
+       bdaddr_t *src = &sa.sco_bdaddr;
+       int len, err = 0;
 
-       BT_DBG("sk %p %s", sk, batostr(&sa->sco_bdaddr));
+       BT_DBG("sk %p %s", sk, batostr(&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) {
@@ -476,7 +484,8 @@ static int sco_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_le
                err = -EADDRINUSE;
        } else {
                /* Save source address */
-               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;
        }
 
@@ -489,26 +498,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 (addr->sa_family != AF_BLUETOOTH || alen < sizeof(struct sockaddr_sco))
+       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;
 
        if ((err = sco_connect(sk)))
                goto done;
@@ -614,6 +631,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;
 }