Merge branch 'master' into for-linus
[safe/jmp/linux-2.6] / net / bluetooth / l2cap.c
index b2d279c..bd0a4c1 100644 (file)
 #include <linux/skbuff.h>
 #include <linux/list.h>
 #include <linux/device.h>
+#include <linux/uaccess.h>
 #include <net/sock.h>
 
 #include <asm/system.h>
-#include <asm/uaccess.h>
 #include <asm/unaligned.h>
 
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/hci_core.h>
 #include <net/bluetooth/l2cap.h>
 
-#define VERSION "2.11"
+#define VERSION "2.13"
 
-static u32 l2cap_feat_mask = 0x0000;
+static u32 l2cap_feat_mask = L2CAP_FEAT_FIXED_CHAN;
+static u8 l2cap_fixed_chan[8] = { 0x02, };
 
 static const struct proto_ops l2cap_sock_ops;
 
@@ -133,7 +134,8 @@ static inline struct sock *l2cap_get_chan_by_scid(struct l2cap_chan_list *l, u16
        struct sock *s;
        read_lock(&l->lock);
        s = __l2cap_get_chan_by_scid(l, cid);
-       if (s) bh_lock_sock(s);
+       if (s)
+               bh_lock_sock(s);
        read_unlock(&l->lock);
        return s;
 }
@@ -153,17 +155,18 @@ static inline struct sock *l2cap_get_chan_by_ident(struct l2cap_chan_list *l, u8
        struct sock *s;
        read_lock(&l->lock);
        s = __l2cap_get_chan_by_ident(l, ident);
-       if (s) bh_lock_sock(s);
+       if (s)
+               bh_lock_sock(s);
        read_unlock(&l->lock);
        return s;
 }
 
 static u16 l2cap_alloc_cid(struct l2cap_chan_list *l)
 {
-       u16 cid = 0x0040;
+       u16 cid = L2CAP_CID_DYN_START;
 
-       for (; cid < 0xffff; cid++) {
-               if(!__l2cap_get_chan_by_scid(l, cid))
+       for (; cid < L2CAP_CID_DYN_END; cid++) {
+               if (!__l2cap_get_chan_by_scid(l, cid))
                        return cid;
        }
 
@@ -203,7 +206,10 @@ static void __l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct so
 {
        struct l2cap_chan_list *l = &conn->chan_list;
 
-       BT_DBG("conn %p, psm 0x%2.2x, dcid 0x%4.4x", conn, l2cap_pi(sk)->psm, l2cap_pi(sk)->dcid);
+       BT_DBG("conn %p, psm 0x%2.2x, dcid 0x%4.4x", conn,
+                       l2cap_pi(sk)->psm, l2cap_pi(sk)->dcid);
+
+       conn->disc_reason = 0x13;
 
        l2cap_pi(sk)->conn = conn;
 
@@ -212,13 +218,13 @@ static void __l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct so
                l2cap_pi(sk)->scid = l2cap_alloc_cid(l);
        } else if (sk->sk_type == SOCK_DGRAM) {
                /* Connectionless socket */
-               l2cap_pi(sk)->scid = 0x0002;
-               l2cap_pi(sk)->dcid = 0x0002;
+               l2cap_pi(sk)->scid = L2CAP_CID_CONN_LESS;
+               l2cap_pi(sk)->dcid = L2CAP_CID_CONN_LESS;
                l2cap_pi(sk)->omtu = L2CAP_DEFAULT_MTU;
        } else {
                /* Raw socket can send/recv signalling messages only */
-               l2cap_pi(sk)->scid = 0x0001;
-               l2cap_pi(sk)->dcid = 0x0001;
+               l2cap_pi(sk)->scid = L2CAP_CID_SIGNALING;
+               l2cap_pi(sk)->dcid = L2CAP_CID_SIGNALING;
                l2cap_pi(sk)->omtu = L2CAP_DEFAULT_MTU;
        }
 
@@ -263,8 +269,32 @@ static void l2cap_chan_del(struct sock *sk, int err)
 static inline int l2cap_check_security(struct sock *sk)
 {
        struct l2cap_conn *conn = l2cap_pi(sk)->conn;
+       __u8 auth_type;
+
+       if (l2cap_pi(sk)->psm == cpu_to_le16(0x0001)) {
+               if (l2cap_pi(sk)->sec_level == BT_SECURITY_HIGH)
+                       auth_type = HCI_AT_NO_BONDING_MITM;
+               else
+                       auth_type = HCI_AT_NO_BONDING;
 
-       return hci_conn_security(conn->hcon, l2cap_pi(sk)->sec_level);
+               if (l2cap_pi(sk)->sec_level == BT_SECURITY_LOW)
+                       l2cap_pi(sk)->sec_level = BT_SECURITY_SDP;
+       } else {
+               switch (l2cap_pi(sk)->sec_level) {
+               case BT_SECURITY_HIGH:
+                       auth_type = HCI_AT_GENERAL_BONDING_MITM;
+                       break;
+               case BT_SECURITY_MEDIUM:
+                       auth_type = HCI_AT_GENERAL_BONDING;
+                       break;
+               default:
+                       auth_type = HCI_AT_NO_BONDING;
+                       break;
+               }
+       }
+
+       return hci_conn_security(conn->hcon, l2cap_pi(sk)->sec_level,
+                                                               auth_type);
 }
 
 static inline u8 l2cap_get_ident(struct l2cap_conn *conn)
@@ -306,6 +336,9 @@ static void l2cap_do_start(struct sock *sk)
        struct l2cap_conn *conn = l2cap_pi(sk)->conn;
 
        if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) {
+               if (!(conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE))
+                       return;
+
                if (l2cap_check_security(sk)) {
                        struct l2cap_conn_req req;
                        req.scid = cpu_to_le16(l2cap_pi(sk)->scid);
@@ -439,6 +472,7 @@ static void l2cap_info_timeout(unsigned long arg)
 {
        struct l2cap_conn *conn = (void *) arg;
 
+       conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
        conn->info_ident = 0;
 
        l2cap_conn_start(conn);
@@ -472,6 +506,8 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status)
        spin_lock_init(&conn->lock);
        rwlock_init(&conn->chan_list.lock);
 
+       conn->disc_reason = 0x13;
+
        return conn;
 }
 
@@ -485,8 +521,7 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err)
 
        BT_DBG("hcon %p conn %p, err %d", hcon, conn, err);
 
-       if (conn->rx_skb)
-               kfree_skb(conn->rx_skb);
+       kfree_skb(conn->rx_skb);
 
        /* Kill channels */
        while ((sk = conn->chan_list.head)) {
@@ -556,7 +591,8 @@ static inline struct sock *l2cap_get_sock_by_psm(int state, __le16 psm, bdaddr_t
        struct sock *s;
        read_lock(&l2cap_sk_list.lock);
        s = __l2cap_get_sock_by_psm(state, psm, src);
-       if (s) bh_lock_sock(s);
+       if (s)
+               bh_lock_sock(s);
        read_unlock(&l2cap_sk_list.lock);
        return s;
 }
@@ -751,17 +787,24 @@ static int l2cap_sock_create(struct net *net, struct socket *sock, int protocol)
        return 0;
 }
 
-static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_len)
+static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen)
 {
-       struct sockaddr_l2 *la = (struct sockaddr_l2 *) addr;
        struct sock *sk = sock->sk;
-       int err = 0;
+       struct sockaddr_l2 la;
+       int len, err = 0;
 
-       BT_DBG("sk %p, %s %d", sk, batostr(&la->l2_bdaddr), la->l2_psm);
+       BT_DBG("sk %p", sk);
 
        if (!addr || addr->sa_family != AF_BLUETOOTH)
                return -EINVAL;
 
+       memset(&la, 0, sizeof(la));
+       len = min_t(unsigned int, sizeof(la), alen);
+       memcpy(&la, addr, len);
+
+       if (la.l2_cid)
+               return -EINVAL;
+
        lock_sock(sk);
 
        if (sk->sk_state != BT_OPEN) {
@@ -769,7 +812,7 @@ static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_
                goto done;
        }
 
-       if (la->l2_psm && btohs(la->l2_psm) < 0x1001 &&
+       if (la.l2_psm && __le16_to_cpu(la.l2_psm) < 0x1001 &&
                                !capable(CAP_NET_BIND_SERVICE)) {
                err = -EACCES;
                goto done;
@@ -777,16 +820,17 @@ static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_
 
        write_lock_bh(&l2cap_sk_list.lock);
 
-       if (la->l2_psm && __l2cap_get_sock_by_addr(la->l2_psm, &la->l2_bdaddr)) {
+       if (la.l2_psm && __l2cap_get_sock_by_addr(la.l2_psm, &la.l2_bdaddr)) {
                err = -EADDRINUSE;
        } else {
                /* Save source address */
-               bacpy(&bt_sk(sk)->src, &la->l2_bdaddr);
-               l2cap_pi(sk)->psm   = la->l2_psm;
-               l2cap_pi(sk)->sport = la->l2_psm;
+               bacpy(&bt_sk(sk)->src, &la.l2_bdaddr);
+               l2cap_pi(sk)->psm   = la.l2_psm;
+               l2cap_pi(sk)->sport = la.l2_psm;
                sk->sk_state = BT_BOUND;
 
-               if (btohs(la->l2_psm) == 0x0001)
+               if (__le16_to_cpu(la.l2_psm) == 0x0001 ||
+                                       __le16_to_cpu(la.l2_psm) == 0x0003)
                        l2cap_pi(sk)->sec_level = BT_SECURITY_SDP;
        }
 
@@ -805,11 +849,13 @@ static int l2cap_do_connect(struct sock *sk)
        struct hci_conn *hcon;
        struct hci_dev *hdev;
        __u8 auth_type;
-       int err = 0;
+       int err;
 
-       BT_DBG("%s -> %s psm 0x%2.2x", batostr(src), batostr(dst), l2cap_pi(sk)->psm);
+       BT_DBG("%s -> %s psm 0x%2.2x", batostr(src), batostr(dst),
+                                                       l2cap_pi(sk)->psm);
 
-       if (!(hdev = hci_get_route(dst, src)))
+       hdev = hci_get_route(dst, src);
+       if (!hdev)
                return -EHOSTUNREACH;
 
        hci_dev_lock_bh(hdev);
@@ -833,6 +879,9 @@ static int l2cap_do_connect(struct sock *sk)
                        auth_type = HCI_AT_NO_BONDING_MITM;
                else
                        auth_type = HCI_AT_NO_BONDING;
+
+               if (l2cap_pi(sk)->sec_level == BT_SECURITY_LOW)
+                       l2cap_pi(sk)->sec_level = BT_SECURITY_SDP;
        } else {
                switch (l2cap_pi(sk)->sec_level) {
                case BT_SECURITY_HIGH:
@@ -884,25 +933,30 @@ done:
 
 static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int alen, int flags)
 {
-       struct sockaddr_l2 *la = (struct sockaddr_l2 *) addr;
        struct sock *sk = sock->sk;
-       int err = 0;
-
-       lock_sock(sk);
+       struct sockaddr_l2 la;
+       int len, err = 0;
 
        BT_DBG("sk %p", sk);
 
-       if (addr->sa_family != AF_BLUETOOTH || alen < sizeof(struct sockaddr_l2)) {
-               err = -EINVAL;
-               goto done;
-       }
+       if (!addr || addr->sa_family != AF_BLUETOOTH)
+               return -EINVAL;
+
+       memset(&la, 0, sizeof(la));
+       len = min_t(unsigned int, sizeof(la), alen);
+       memcpy(&la, addr, len);
+
+       if (la.l2_cid)
+               return -EINVAL;
+
+       lock_sock(sk);
 
-       if (sk->sk_type == SOCK_SEQPACKET && !la->l2_psm) {
+       if (sk->sk_type == SOCK_SEQPACKET && !la.l2_psm) {
                err = -EINVAL;
                goto done;
        }
 
-       switch(sk->sk_state) {
+       switch (sk->sk_state) {
        case BT_CONNECT:
        case BT_CONNECT2:
        case BT_CONFIG:
@@ -924,10 +978,11 @@ static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int al
        }
 
        /* Set destination address and psm */
-       bacpy(&bt_sk(sk)->dst, &la->l2_bdaddr);
-       l2cap_pi(sk)->psm = la->l2_psm;
+       bacpy(&bt_sk(sk)->dst, &la.l2_bdaddr);
+       l2cap_pi(sk)->psm = la.l2_psm;
 
-       if ((err = l2cap_do_connect(sk)))
+       err = l2cap_do_connect(sk);
+       if (err)
                goto done;
 
 wait:
@@ -961,9 +1016,9 @@ static int l2cap_sock_listen(struct socket *sock, int backlog)
                write_lock_bh(&l2cap_sk_list.lock);
 
                for (psm = 0x1001; psm < 0x1100; psm += 2)
-                       if (!__l2cap_get_sock_by_addr(htobs(psm), src)) {
-                               l2cap_pi(sk)->psm   = htobs(psm);
-                               l2cap_pi(sk)->sport = htobs(psm);
+                       if (!__l2cap_get_sock_by_addr(cpu_to_le16(psm), src)) {
+                               l2cap_pi(sk)->psm   = cpu_to_le16(psm);
+                               l2cap_pi(sk)->sport = cpu_to_le16(psm);
                                err = 0;
                                break;
                        }
@@ -1049,12 +1104,16 @@ static int l2cap_sock_getname(struct socket *sock, struct sockaddr *addr, int *l
        addr->sa_family = AF_BLUETOOTH;
        *len = sizeof(struct sockaddr_l2);
 
-       if (peer)
+       if (peer) {
+               la->l2_psm = l2cap_pi(sk)->psm;
                bacpy(&la->l2_bdaddr, &bt_sk(sk)->dst);
-       else
+               la->l2_cid = cpu_to_le16(l2cap_pi(sk)->dcid);
+       } else {
+               la->l2_psm = l2cap_pi(sk)->sport;
                bacpy(&la->l2_bdaddr, &bt_sk(sk)->src);
+               la->l2_cid = cpu_to_le16(l2cap_pi(sk)->scid);
+       }
 
-       la->l2_psm = l2cap_pi(sk)->psm;
        return 0;
 }
 
@@ -1062,7 +1121,7 @@ static inline int l2cap_do_send(struct sock *sk, struct msghdr *msg, int len)
 {
        struct l2cap_conn *conn = l2cap_pi(sk)->conn;
        struct sk_buff *skb, **frag;
-       int err, hlen, count, sent=0;
+       int err, hlen, count, sent = 0;
        struct l2cap_hdr *lh;
 
        BT_DBG("sk %p len %d", sk, len);
@@ -1115,8 +1174,8 @@ static inline int l2cap_do_send(struct sock *sk, struct msghdr *msg, int len)
 
                frag = &(*frag)->next;
        }
-
-       if ((err = hci_send_acl(conn->hcon, skb, 0)) < 0)
+       err = hci_send_acl(conn->hcon, skb, 0);
+       if (err < 0)
                goto fail;
 
        return sent;
@@ -1186,7 +1245,7 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __us
 {
        struct sock *sk = sock->sk;
        struct l2cap_options opts;
-       int err = 0, len;
+       int len, err = 0;
        u32 opt;
 
        BT_DBG("sk %p", sk);
@@ -1248,10 +1307,18 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch
        if (level == SOL_L2CAP)
                return l2cap_sock_setsockopt_old(sock, optname, optval, optlen);
 
+       if (level != SOL_BLUETOOTH)
+               return -ENOPROTOOPT;
+
        lock_sock(sk);
 
        switch (optname) {
        case BT_SECURITY:
+               if (sk->sk_type != SOCK_SEQPACKET && sk->sk_type != SOCK_RAW) {
+                       err = -EINVAL;
+                       break;
+               }
+
                sec.level = BT_SECURITY_LOW;
 
                len = min_t(unsigned int, sizeof(sec), optlen);
@@ -1384,6 +1451,9 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, ch
        if (level == SOL_L2CAP)
                return l2cap_sock_getsockopt_old(sock, optname, optval, optlen);
 
+       if (level != SOL_BLUETOOTH)
+               return -ENOPROTOOPT;
+
        if (get_user(len, optlen))
                return -EFAULT;
 
@@ -1391,6 +1461,11 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, ch
 
        switch (optname) {
        case BT_SECURITY:
+               if (sk->sk_type != SOCK_SEQPACKET && sk->sk_type != SOCK_RAW) {
+                       err = -EINVAL;
+                       break;
+               }
+
                sec.level = l2cap_pi(sk)->sec_level;
 
                len = min_t(unsigned int, len, sizeof(sec));
@@ -1488,7 +1563,7 @@ static void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb)
 {
        struct l2cap_chan_list *l = &conn->chan_list;
        struct sk_buff *nskb;
-       struct sock * sk;
+       struct sock *sk;
 
        BT_DBG("conn %p", conn);
 
@@ -1500,8 +1575,8 @@ static void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb)
                /* Don't send frame to the socket it came from */
                if (skb->sk == sk)
                        continue;
-
-               if (!(nskb = skb_clone(skb, GFP_ATOMIC)))
+               nskb = skb_clone(skb, GFP_ATOMIC);
+               if (!nskb)
                        continue;
 
                if (sock_queue_rcv_skb(sk, nskb))
@@ -1519,7 +1594,8 @@ static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn,
        struct l2cap_hdr *lh;
        int len, count;
 
-       BT_DBG("conn %p, code 0x%2.2x, ident 0x%2.2x, len %d", conn, code, ident, dlen);
+       BT_DBG("conn %p, code 0x%2.2x, ident 0x%2.2x, len %d",
+                       conn, code, ident, dlen);
 
        len = L2CAP_HDR_SIZE + L2CAP_CMD_HDR_SIZE + dlen;
        count = min_t(unsigned int, conn->mtu, len);
@@ -1530,7 +1606,7 @@ static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn,
 
        lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
        lh->len = cpu_to_le16(L2CAP_CMD_HDR_SIZE + dlen);
-       lh->cid = cpu_to_le16(0x0001);
+       lh->cid = cpu_to_le16(L2CAP_CID_SIGNALING);
 
        cmd = (struct l2cap_cmd_hdr *) skb_put(skb, L2CAP_CMD_HDR_SIZE);
        cmd->code  = code;
@@ -1671,8 +1747,8 @@ static int l2cap_parse_conf_req(struct sock *sk, void *data)
        while (len >= L2CAP_CONF_OPT_SIZE) {
                len -= l2cap_get_conf_opt(&req, &type, &olen, &val);
 
-               hint  = type & 0x80;
-               type &= 0x7f;
+               hint  = type & L2CAP_CONF_HINT;
+               type &= L2CAP_CONF_MASK;
 
                switch (type) {
                case L2CAP_CONF_MTU:
@@ -1755,8 +1831,11 @@ static inline int l2cap_command_rej(struct l2cap_conn *conn, struct l2cap_cmd_hd
 
        if ((conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) &&
                                        cmd->ident == conn->info_ident) {
-               conn->info_ident = 0;
                del_timer(&conn->info_timer);
+
+               conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
+               conn->info_ident = 0;
+
                l2cap_conn_start(conn);
        }
 
@@ -1786,6 +1865,7 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd
        /* Check if the ACL is secure enough (if not SDP) */
        if (psm != cpu_to_le16(0x0001) &&
                                !hci_conn_check_link_mode(conn->hcon)) {
+               conn->disc_reason = 0x05;
                result = L2CAP_CR_SEC_BLOCK;
                goto response;
        }
@@ -1827,7 +1907,7 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd
 
        l2cap_pi(sk)->ident = cmd->ident;
 
-       if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) {
+       if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE) {
                if (l2cap_check_security(sk)) {
                        if (bt_sk(sk)->defer_setup) {
                                sk->sk_state = BT_CONNECT2;
@@ -1894,10 +1974,12 @@ static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hd
        BT_DBG("dcid 0x%4.4x scid 0x%4.4x result 0x%2.2x status 0x%2.2x", dcid, scid, result, status);
 
        if (scid) {
-               if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, scid)))
+               sk = l2cap_get_chan_by_scid(&conn->chan_list, scid);
+               if (!sk)
                        return 0;
        } else {
-               if (!(sk = l2cap_get_chan_by_ident(&conn->chan_list, cmd->ident)))
+               sk = l2cap_get_chan_by_ident(&conn->chan_list, cmd->ident);
+               if (!sk)
                        return 0;
        }
 
@@ -1908,11 +1990,14 @@ static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hd
                l2cap_pi(sk)->dcid = dcid;
                l2cap_pi(sk)->conf_state |= L2CAP_CONF_REQ_SENT;
 
+               l2cap_pi(sk)->conf_state &= ~L2CAP_CONF_CONNECT_PEND;
+
                l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
                                        l2cap_build_conf_req(sk, req), req);
                break;
 
        case L2CAP_CR_PEND:
+               l2cap_pi(sk)->conf_state |= L2CAP_CONF_CONNECT_PEND;
                break;
 
        default:
@@ -1937,7 +2022,8 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr
 
        BT_DBG("dcid 0x%4.4x flags 0x%2.2x", dcid, flags);
 
-       if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, dcid)))
+       sk = l2cap_get_chan_by_scid(&conn->chan_list, dcid);
+       if (!sk)
                return -ENOENT;
 
        if (sk->sk_state == BT_DISCONN)
@@ -2004,9 +2090,11 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr
        flags  = __le16_to_cpu(rsp->flags);
        result = __le16_to_cpu(rsp->result);
 
-       BT_DBG("scid 0x%4.4x flags 0x%2.2x result 0x%2.2x", scid, flags, result);
+       BT_DBG("scid 0x%4.4x flags 0x%2.2x result 0x%2.2x",
+                       scid, flags, result);
 
-       if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, scid)))
+       sk = l2cap_get_chan_by_scid(&conn->chan_list, scid);
+       if (!sk)
                return 0;
 
        switch (result) {
@@ -2067,7 +2155,8 @@ static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd
 
        BT_DBG("scid 0x%4.4x dcid 0x%4.4x", scid, dcid);
 
-       if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, dcid)))
+       sk = l2cap_get_chan_by_scid(&conn->chan_list, dcid);
+       if (!sk)
                return 0;
 
        rsp.dcid = cpu_to_le16(l2cap_pi(sk)->scid);
@@ -2094,7 +2183,8 @@ static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, struct l2cap_cmd
 
        BT_DBG("dcid 0x%4.4x scid 0x%4.4x", dcid, scid);
 
-       if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, scid)))
+       sk = l2cap_get_chan_by_scid(&conn->chan_list, scid);
+       if (!sk)
                return 0;
 
        l2cap_chan_del(sk, 0);
@@ -2121,6 +2211,14 @@ static inline int l2cap_information_req(struct l2cap_conn *conn, struct l2cap_cm
                put_unaligned(cpu_to_le32(l2cap_feat_mask), (__le32 *) rsp->data);
                l2cap_send_cmd(conn, cmd->ident,
                                        L2CAP_INFO_RSP, sizeof(buf), buf);
+       } else if (type == L2CAP_IT_FIXED_CHAN) {
+               u8 buf[12];
+               struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) buf;
+               rsp->type   = cpu_to_le16(L2CAP_IT_FIXED_CHAN);
+               rsp->result = cpu_to_le16(L2CAP_IR_SUCCESS);
+               memcpy(buf + 4, l2cap_fixed_chan, 8);
+               l2cap_send_cmd(conn, cmd->ident,
+                                       L2CAP_INFO_RSP, sizeof(buf), buf);
        } else {
                struct l2cap_info_rsp rsp;
                rsp.type   = cpu_to_le16(type);
@@ -2142,14 +2240,31 @@ static inline int l2cap_information_rsp(struct l2cap_conn *conn, struct l2cap_cm
 
        BT_DBG("type 0x%4.4x result 0x%2.2x", type, result);
 
-       conn->info_ident = 0;
-
        del_timer(&conn->info_timer);
 
-       if (type == L2CAP_IT_FEAT_MASK)
+       if (type == L2CAP_IT_FEAT_MASK) {
                conn->feat_mask = get_unaligned_le32(rsp->data);
 
-       l2cap_conn_start(conn);
+               if (conn->feat_mask & L2CAP_FEAT_FIXED_CHAN) {
+                       struct l2cap_info_req req;
+                       req.type = cpu_to_le16(L2CAP_IT_FIXED_CHAN);
+
+                       conn->info_ident = l2cap_get_ident(conn);
+
+                       l2cap_send_cmd(conn, conn->info_ident,
+                                       L2CAP_INFO_REQ, sizeof(req), &req);
+               } else {
+                       conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
+                       conn->info_ident = 0;
+
+                       l2cap_conn_start(conn);
+               }
+       } else if (type == L2CAP_IT_FIXED_CHAN) {
+               conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
+               conn->info_ident = 0;
+
+               l2cap_conn_start(conn);
+       }
 
        return 0;
 }
@@ -2303,7 +2418,8 @@ drop:
        kfree_skb(skb);
 
 done:
-       if (sk) bh_unlock_sock(sk);
+       if (sk)
+               bh_unlock_sock(sk);
        return 0;
 }
 
@@ -2320,11 +2436,11 @@ static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb)
        BT_DBG("len %d, cid 0x%4.4x", len, cid);
 
        switch (cid) {
-       case 0x0001:
+       case L2CAP_CID_SIGNALING:
                l2cap_sig_channel(conn, skb);
                break;
 
-       case 0x0002:
+       case L2CAP_CID_CONN_LESS:
                psm = get_unaligned((__le16 *) skb->data);
                skb_pull(skb, 2);
                l2cap_conless_channel(conn, psm, skb);
@@ -2390,7 +2506,19 @@ static int l2cap_connect_cfm(struct hci_conn *hcon, u8 status)
        return 0;
 }
 
-static int l2cap_disconn_ind(struct hci_conn *hcon, u8 reason)
+static int l2cap_disconn_ind(struct hci_conn *hcon)
+{
+       struct l2cap_conn *conn = hcon->l2cap_data;
+
+       BT_DBG("hcon %p", hcon);
+
+       if (hcon->type != ACL_LINK || !conn)
+               return 0x13;
+
+       return conn->disc_reason;
+}
+
+static int l2cap_disconn_cfm(struct hci_conn *hcon, u8 reason)
 {
        BT_DBG("hcon %p reason %d", hcon, reason);
 
@@ -2404,6 +2532,9 @@ static int l2cap_disconn_ind(struct hci_conn *hcon, u8 reason)
 
 static inline void l2cap_check_encryption(struct sock *sk, u8 encrypt)
 {
+       if (sk->sk_type != SOCK_SEQPACKET)
+               return;
+
        if (encrypt == 0x00) {
                if (l2cap_pi(sk)->sec_level == BT_SECURITY_MEDIUM) {
                        l2cap_sock_clear_timer(sk);
@@ -2434,6 +2565,11 @@ static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
        for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) {
                bh_lock_sock(sk);
 
+               if (l2cap_pi(sk)->conf_state & L2CAP_CONF_CONNECT_PEND) {
+                       bh_unlock_sock(sk);
+                       continue;
+               }
+
                if (!status && (sk->sk_state == BT_CONNECTED ||
                                                sk->sk_state == BT_CONFIG)) {
                        l2cap_check_encryption(sk, encrypt);
@@ -2530,11 +2666,12 @@ static int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 fl
                }
 
                /* Allocate skb for the complete frame (with header) */
-               if (!(conn->rx_skb = bt_skb_alloc(len, GFP_ATOMIC)))
+               conn->rx_skb = bt_skb_alloc(len, GFP_ATOMIC);
+               if (!conn->rx_skb)
                        goto drop;
 
                skb_copy_from_linear_data(skb, skb_put(conn->rx_skb, skb->len),
-                             skb->len);
+                                                               skb->len);
                conn->rx_len = len - skb->len;
        } else {
                BT_DBG("Cont: frag len %d (expecting %d)", skb->len, conn->rx_len);
@@ -2556,7 +2693,7 @@ static int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 fl
                }
 
                skb_copy_from_linear_data(skb, skb_put(conn->rx_skb, skb->len),
-                             skb->len);
+                                                               skb->len);
                conn->rx_len -= skb->len;
 
                if (!conn->rx_len) {
@@ -2584,13 +2721,13 @@ static ssize_t l2cap_sysfs_show(struct class *dev, char *buf)
 
                str += sprintf(str, "%s %s %d %d 0x%4.4x 0x%4.4x %d %d %d\n",
                                batostr(&bt_sk(sk)->src), batostr(&bt_sk(sk)->dst),
-                               sk->sk_state, btohs(pi->psm), pi->scid, pi->dcid,
-                               pi->imtu, pi->omtu, pi->sec_level);
+                               sk->sk_state, __le16_to_cpu(pi->psm), pi->scid,
+                               pi->dcid, pi->imtu, pi->omtu, pi->sec_level);
        }
 
        read_unlock_bh(&l2cap_sk_list.lock);
 
-       return (str - buf);
+       return str - buf;
 }
 
 static CLASS_ATTR(l2cap, S_IRUGO, l2cap_sysfs_show, NULL);
@@ -2627,6 +2764,7 @@ static struct hci_proto l2cap_hci_proto = {
        .connect_ind    = l2cap_connect_ind,
        .connect_cfm    = l2cap_connect_cfm,
        .disconn_ind    = l2cap_disconn_ind,
+       .disconn_cfm    = l2cap_disconn_cfm,
        .security_cfm   = l2cap_security_cfm,
        .recv_acldata   = l2cap_recv_acldata
 };