Bluetooth: Ask upper layers for HCI disconnect reason
[safe/jmp/linux-2.6] / net / bluetooth / l2cap.c
index 34f8bf9..d563f2e 100644 (file)
 #include <net/bluetooth/hci_core.h>
 #include <net/bluetooth/l2cap.h>
 
-#ifndef CONFIG_BT_L2CAP_DEBUG
-#undef  BT_DBG
-#define BT_DBG(D...)
-#endif
+#define VERSION "2.13"
 
-#define VERSION "2.9"
-
-static u32 l2cap_feat_mask = 0x0000;
+static u32 l2cap_feat_mask = 0x0080;
+static u8 l2cap_fixed_chan[8] = { 0x02, };
 
 static const struct proto_ops l2cap_sock_ops;
 
 static struct bt_sock_list l2cap_sk_list = {
-       .lock = RW_LOCK_UNLOCKED
+       .lock = __RW_LOCK_UNLOCKED(l2cap_sk_list.lock)
 };
 
 static void __l2cap_sock_close(struct sock *sk, int reason);
@@ -76,11 +72,22 @@ static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn,
 static void l2cap_sock_timeout(unsigned long arg)
 {
        struct sock *sk = (struct sock *) arg;
+       int reason;
 
        BT_DBG("sock %p state %d", sk, sk->sk_state);
 
        bh_lock_sock(sk);
-       __l2cap_sock_close(sk, ETIMEDOUT);
+
+       if (sk->sk_state == BT_CONNECTED || sk->sk_state == BT_CONFIG)
+               reason = ECONNREFUSED;
+       else if (sk->sk_state == BT_CONNECT &&
+                               l2cap_pi(sk)->sec_level != BT_SECURITY_SDP)
+               reason = ECONNREFUSED;
+       else
+               reason = ETIMEDOUT;
+
+       __l2cap_sock_close(sk, reason);
+
        bh_unlock_sock(sk);
 
        l2cap_sock_kill(sk);
@@ -199,6 +206,8 @@ static void __l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct so
 
        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;
 
        if (sk->sk_type == SOCK_SEQPACKET) {
@@ -240,7 +249,7 @@ static void l2cap_chan_del(struct sock *sk, int err)
                hci_conn_put(conn->hcon);
        }
 
-       sk->sk_state  = BT_CLOSED;
+       sk->sk_state = BT_CLOSED;
        sock_set_flag(sk, SOCK_ZAPPED);
 
        if (err)
@@ -253,6 +262,28 @@ static void l2cap_chan_del(struct sock *sk, int err)
                sk->sk_state_change(sk);
 }
 
+/* Service level security */
+static inline int l2cap_check_security(struct sock *sk)
+{
+       struct l2cap_conn *conn = l2cap_pi(sk)->conn;
+       __u8 auth_type;
+
+       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)
 {
        u8 id;
@@ -287,6 +318,39 @@ static inline int l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16
        return hci_send_acl(conn->hcon, skb, 0);
 }
 
+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);
+                       req.psm  = l2cap_pi(sk)->psm;
+
+                       l2cap_pi(sk)->ident = l2cap_get_ident(conn);
+
+                       l2cap_send_cmd(conn, l2cap_pi(sk)->ident,
+                                       L2CAP_CONN_REQ, sizeof(req), &req);
+               }
+       } else {
+               struct l2cap_info_req req;
+               req.type = cpu_to_le16(L2CAP_IT_FEAT_MASK);
+
+               conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_SENT;
+               conn->info_ident = l2cap_get_ident(conn);
+
+               mod_timer(&conn->info_timer, jiffies +
+                                       msecs_to_jiffies(L2CAP_INFO_TIMEOUT));
+
+               l2cap_send_cmd(conn, conn->info_ident,
+                                       L2CAP_INFO_REQ, sizeof(req), &req);
+       }
+}
+
 /* ---- L2CAP connections ---- */
 static void l2cap_conn_start(struct l2cap_conn *conn)
 {
@@ -301,16 +365,45 @@ static void l2cap_conn_start(struct l2cap_conn *conn)
                bh_lock_sock(sk);
 
                if (sk->sk_type != SOCK_SEQPACKET) {
-                       l2cap_sock_clear_timer(sk);
-                       sk->sk_state = BT_CONNECTED;
-                       sk->sk_state_change(sk);
-               } else if (sk->sk_state == BT_CONNECT) {
-                       struct l2cap_conn_req req;
-                       l2cap_pi(sk)->ident = l2cap_get_ident(conn);
-                       req.scid = cpu_to_le16(l2cap_pi(sk)->scid);
-                       req.psm  = l2cap_pi(sk)->psm;
-                       l2cap_send_cmd(conn, l2cap_pi(sk)->ident,
+                       bh_unlock_sock(sk);
+                       continue;
+               }
+
+               if (sk->sk_state == BT_CONNECT) {
+                       if (l2cap_check_security(sk)) {
+                               struct l2cap_conn_req req;
+                               req.scid = cpu_to_le16(l2cap_pi(sk)->scid);
+                               req.psm  = l2cap_pi(sk)->psm;
+
+                               l2cap_pi(sk)->ident = l2cap_get_ident(conn);
+
+                               l2cap_send_cmd(conn, l2cap_pi(sk)->ident,
                                        L2CAP_CONN_REQ, sizeof(req), &req);
+                       }
+               } else if (sk->sk_state == BT_CONNECT2) {
+                       struct l2cap_conn_rsp rsp;
+                       rsp.scid = cpu_to_le16(l2cap_pi(sk)->dcid);
+                       rsp.dcid = cpu_to_le16(l2cap_pi(sk)->scid);
+
+                       if (l2cap_check_security(sk)) {
+                               if (bt_sk(sk)->defer_setup) {
+                                       struct sock *parent = bt_sk(sk)->parent;
+                                       rsp.result = cpu_to_le16(L2CAP_CR_PEND);
+                                       rsp.status = cpu_to_le16(L2CAP_CS_AUTHOR_PEND);
+                                       parent->sk_data_ready(parent, 0);
+
+                               } else {
+                                       sk->sk_state = BT_CONFIG;
+                                       rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS);
+                                       rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
+                               }
+                       } else {
+                               rsp.result = cpu_to_le16(L2CAP_CR_PEND);
+                               rsp.status = cpu_to_le16(L2CAP_CS_AUTHEN_PEND);
+                       }
+
+                       l2cap_send_cmd(conn, l2cap_pi(sk)->ident,
+                                       L2CAP_CONN_RSP, sizeof(rsp), &rsp);
                }
 
                bh_unlock_sock(sk);
@@ -321,22 +414,27 @@ static void l2cap_conn_start(struct l2cap_conn *conn)
 
 static void l2cap_conn_ready(struct l2cap_conn *conn)
 {
-       BT_DBG("conn %p", conn);
+       struct l2cap_chan_list *l = &conn->chan_list;
+       struct sock *sk;
 
-       if (conn->chan_list.head || !hlist_empty(&l2cap_sk_list.head)) {
-               struct l2cap_info_req req;
+       BT_DBG("conn %p", conn);
 
-               req.type = cpu_to_le16(L2CAP_IT_FEAT_MASK);
+       read_lock(&l->lock);
 
-               conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_SENT;
-               conn->info_ident = l2cap_get_ident(conn);
+       for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) {
+               bh_lock_sock(sk);
 
-               mod_timer(&conn->info_timer,
-                       jiffies + msecs_to_jiffies(L2CAP_INFO_TIMEOUT));
+               if (sk->sk_type != SOCK_SEQPACKET) {
+                       l2cap_sock_clear_timer(sk);
+                       sk->sk_state = BT_CONNECTED;
+                       sk->sk_state_change(sk);
+               } else if (sk->sk_state == BT_CONNECT)
+                       l2cap_do_start(sk);
 
-               l2cap_send_cmd(conn, conn->info_ident,
-                                       L2CAP_INFO_REQ, sizeof(req), &req);
+               bh_unlock_sock(sk);
        }
+
+       read_unlock(&l->lock);
 }
 
 /* Notify sockets that we cannot guaranty reliability anymore */
@@ -350,7 +448,7 @@ static void l2cap_conn_unreliable(struct l2cap_conn *conn, int err)
        read_lock(&l->lock);
 
        for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) {
-               if (l2cap_pi(sk)->link_mode & L2CAP_LM_RELIABLE)
+               if (l2cap_pi(sk)->force_reliable)
                        sk->sk_err = err;
        }
 
@@ -361,6 +459,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);
@@ -388,11 +487,14 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status)
 
        conn->feat_mask = 0;
 
-       setup_timer(&conn->info_timer, l2cap_info_timeout, (unsigned long)conn);
+       setup_timer(&conn->info_timer, l2cap_info_timeout,
+                                               (unsigned long) conn);
 
        spin_lock_init(&conn->lock);
        rwlock_init(&conn->chan_list.lock);
 
+       conn->disc_reason = 0x13;
+
        return conn;
 }
 
@@ -500,7 +602,7 @@ static void l2cap_sock_cleanup_listen(struct sock *parent)
        while ((sk = bt_accept_dequeue(parent, NULL)))
                l2cap_sock_close(sk);
 
-       parent->sk_state  = BT_CLOSED;
+       parent->sk_state = BT_CLOSED;
        sock_set_flag(parent, SOCK_ZAPPED);
 }
 
@@ -531,7 +633,6 @@ static void __l2cap_sock_close(struct sock *sk, int reason)
 
        case BT_CONNECTED:
        case BT_CONFIG:
-       case BT_CONNECT2:
                if (sk->sk_type == SOCK_SEQPACKET) {
                        struct l2cap_conn *conn = l2cap_pi(sk)->conn;
                        struct l2cap_disconn_req req;
@@ -543,9 +644,29 @@ static void __l2cap_sock_close(struct sock *sk, int reason)
                        req.scid = cpu_to_le16(l2cap_pi(sk)->scid);
                        l2cap_send_cmd(conn, l2cap_get_ident(conn),
                                        L2CAP_DISCONN_REQ, sizeof(req), &req);
-               } else {
+               } else
+                       l2cap_chan_del(sk, reason);
+               break;
+
+       case BT_CONNECT2:
+               if (sk->sk_type == SOCK_SEQPACKET) {
+                       struct l2cap_conn *conn = l2cap_pi(sk)->conn;
+                       struct l2cap_conn_rsp rsp;
+                       __u16 result;
+
+                       if (bt_sk(sk)->defer_setup)
+                               result = L2CAP_CR_SEC_BLOCK;
+                       else
+                               result = L2CAP_CR_BAD_PSM;
+
+                       rsp.scid   = cpu_to_le16(l2cap_pi(sk)->dcid);
+                       rsp.dcid   = cpu_to_le16(l2cap_pi(sk)->scid);
+                       rsp.result = cpu_to_le16(result);
+                       rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
+                       l2cap_send_cmd(conn, l2cap_pi(sk)->ident,
+                                       L2CAP_CONN_RSP, sizeof(rsp), &rsp);
+               } else
                        l2cap_chan_del(sk, reason);
-               }
                break;
 
        case BT_CONNECT:
@@ -577,13 +698,19 @@ static void l2cap_sock_init(struct sock *sk, struct sock *parent)
 
        if (parent) {
                sk->sk_type = parent->sk_type;
+               bt_sk(sk)->defer_setup = bt_sk(parent)->defer_setup;
+
                pi->imtu = l2cap_pi(parent)->imtu;
                pi->omtu = l2cap_pi(parent)->omtu;
-               pi->link_mode = l2cap_pi(parent)->link_mode;
+               pi->sec_level = l2cap_pi(parent)->sec_level;
+               pi->role_switch = l2cap_pi(parent)->role_switch;
+               pi->force_reliable = l2cap_pi(parent)->force_reliable;
        } else {
                pi->imtu = L2CAP_DEFAULT_MTU;
                pi->omtu = 0;
-               pi->link_mode = 0;
+               pi->sec_level = BT_SECURITY_LOW;
+               pi->role_switch = 0;
+               pi->force_reliable = 0;
        }
 
        /* Default config options */
@@ -614,9 +741,9 @@ static struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock, int p
        sock_reset_flag(sk, SOCK_ZAPPED);
 
        sk->sk_protocol = proto;
-       sk->sk_state    = BT_OPEN;
+       sk->sk_state = BT_OPEN;
 
-       setup_timer(&sk->sk_timer, l2cap_sock_timeout, (unsigned long)sk);
+       setup_timer(&sk->sk_timer, l2cap_sock_timeout, (unsigned long) sk);
 
        bt_sock_link(&l2cap_sk_list, sk);
        return sk;
@@ -647,17 +774,21 @@ 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);
+
        lock_sock(sk);
 
        if (sk->sk_state != BT_OPEN) {
@@ -665,7 +796,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 && btohs(la.l2_psm) < 0x1001 &&
                                !capable(CAP_NET_BIND_SERVICE)) {
                err = -EACCES;
                goto done;
@@ -673,14 +804,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 || btohs(la.l2_psm) == 0x0003)
+                       l2cap_pi(sk)->sec_level = BT_SECURITY_SDP;
        }
 
        write_unlock_bh(&l2cap_sk_list.lock);
@@ -697,9 +831,11 @@ static int l2cap_do_connect(struct sock *sk)
        struct l2cap_conn *conn;
        struct hci_conn *hcon;
        struct hci_dev *hdev;
+       __u8 auth_type;
        int err = 0;
 
-       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)))
                return -EHOSTUNREACH;
@@ -708,7 +844,42 @@ static int l2cap_do_connect(struct sock *sk)
 
        err = -ENOMEM;
 
-       hcon = hci_connect(hdev, ACL_LINK, dst);
+       if (sk->sk_type == SOCK_RAW) {
+               switch (l2cap_pi(sk)->sec_level) {
+               case BT_SECURITY_HIGH:
+                       auth_type = HCI_AT_DEDICATED_BONDING_MITM;
+                       break;
+               case BT_SECURITY_MEDIUM:
+                       auth_type = HCI_AT_DEDICATED_BONDING;
+                       break;
+               default:
+                       auth_type = HCI_AT_NO_BONDING;
+                       break;
+               }
+       } else 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;
+
+               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;
+               }
+       }
+
+       hcon = hci_connect(hdev, ACL_LINK, dst,
+                                       l2cap_pi(sk)->sec_level, auth_type);
        if (!hcon)
                goto done;
 
@@ -729,22 +900,11 @@ static int l2cap_do_connect(struct sock *sk)
        l2cap_sock_set_timer(sk, sk->sk_sndtimeo);
 
        if (hcon->state == BT_CONNECTED) {
-               if (!(conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT)) {
-                       l2cap_conn_ready(conn);
-                       goto done;
-               }
-
-               if (sk->sk_type == SOCK_SEQPACKET) {
-                       struct l2cap_conn_req req;
-                       l2cap_pi(sk)->ident = l2cap_get_ident(conn);
-                       req.scid = cpu_to_le16(l2cap_pi(sk)->scid);
-                       req.psm  = l2cap_pi(sk)->psm;
-                       l2cap_send_cmd(conn, l2cap_pi(sk)->ident,
-                                       L2CAP_CONN_REQ, sizeof(req), &req);
-               } else {
+               if (sk->sk_type != SOCK_SEQPACKET) {
                        l2cap_sock_clear_timer(sk);
                        sk->sk_state = BT_CONNECTED;
-               }
+               } else
+                       l2cap_do_start(sk);
        }
 
 done:
@@ -755,20 +915,24 @@ 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;
+       struct sockaddr_l2 la;
+       int len, err = 0;
 
        lock_sock(sk);
 
        BT_DBG("sk %p", sk);
 
-       if (addr->sa_family != AF_BLUETOOTH || alen < sizeof(struct sockaddr_l2)) {
+       if (!addr || addr->sa_family != AF_BLUETOOTH) {
                err = -EINVAL;
                goto done;
        }
 
-       if (sk->sk_type == SOCK_SEQPACKET && !la->l2_psm) {
+       memset(&la, 0, sizeof(la));
+       len = min_t(unsigned int, sizeof(la), alen);
+       memcpy(&la, addr, len);
+
+       if (sk->sk_type == SOCK_SEQPACKET && !la.l2_psm) {
                err = -EINVAL;
                goto done;
        }
@@ -795,8 +959,8 @@ 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)))
                goto done;
@@ -920,12 +1084,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 = htobs(l2cap_pi(sk)->dcid);
+       } else {
+               la->l2_psm = l2cap_pi(sk)->sport;
                bacpy(&la->l2_bdaddr, &bt_sk(sk)->src);
+               la->l2_cid = htobs(l2cap_pi(sk)->scid);
+       }
 
-       la->l2_psm = l2cap_pi(sk)->psm;
        return 0;
 }
 
@@ -1026,11 +1194,38 @@ static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct ms
        return err;
 }
 
-static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, char __user *optval, int optlen)
+static int l2cap_sock_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, size_t len, int flags)
+{
+       struct sock *sk = sock->sk;
+
+       lock_sock(sk);
+
+       if (sk->sk_state == BT_CONNECT2 && bt_sk(sk)->defer_setup) {
+               struct l2cap_conn_rsp rsp;
+
+               sk->sk_state = BT_CONFIG;
+
+               rsp.scid   = cpu_to_le16(l2cap_pi(sk)->dcid);
+               rsp.dcid   = cpu_to_le16(l2cap_pi(sk)->scid);
+               rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS);
+               rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
+               l2cap_send_cmd(l2cap_pi(sk)->conn, l2cap_pi(sk)->ident,
+                                       L2CAP_CONN_RSP, sizeof(rsp), &rsp);
+
+               release_sock(sk);
+               return 0;
+       }
+
+       release_sock(sk);
+
+       return bt_sock_recvmsg(iocb, sock, msg, len, flags);
+}
+
+static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __user *optval, int optlen)
 {
        struct sock *sk = sock->sk;
        struct l2cap_options opts;
-       int err = 0, len;
+       int len, err = 0;
        u32 opt;
 
        BT_DBG("sk %p", sk);
@@ -1060,7 +1255,15 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch
                        break;
                }
 
-               l2cap_pi(sk)->link_mode = opt;
+               if (opt & L2CAP_LM_AUTH)
+                       l2cap_pi(sk)->sec_level = BT_SECURITY_LOW;
+               if (opt & L2CAP_LM_ENCRYPT)
+                       l2cap_pi(sk)->sec_level = BT_SECURITY_MEDIUM;
+               if (opt & L2CAP_LM_SECURE)
+                       l2cap_pi(sk)->sec_level = BT_SECURITY_HIGH;
+
+               l2cap_pi(sk)->role_switch    = (opt & L2CAP_LM_MASTER);
+               l2cap_pi(sk)->force_reliable = (opt & L2CAP_LM_RELIABLE);
                break;
 
        default:
@@ -1072,12 +1275,77 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch
        return err;
 }
 
-static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, char __user *optval, int __user *optlen)
+static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, char __user *optval, int optlen)
+{
+       struct sock *sk = sock->sk;
+       struct bt_security sec;
+       int len, err = 0;
+       u32 opt;
+
+       BT_DBG("sk %p", sk);
+
+       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) {
+                       err = -EINVAL;
+                       break;
+               }
+
+               sec.level = BT_SECURITY_LOW;
+
+               len = min_t(unsigned int, sizeof(sec), optlen);
+               if (copy_from_user((char *) &sec, optval, len)) {
+                       err = -EFAULT;
+                       break;
+               }
+
+               if (sec.level < BT_SECURITY_LOW ||
+                                       sec.level > BT_SECURITY_HIGH) {
+                       err = -EINVAL;
+                       break;
+               }
+
+               l2cap_pi(sk)->sec_level = sec.level;
+               break;
+
+       case BT_DEFER_SETUP:
+               if (sk->sk_state != BT_BOUND && sk->sk_state != BT_LISTEN) {
+                       err = -EINVAL;
+                       break;
+               }
+
+               if (get_user(opt, (u32 __user *) optval)) {
+                       err = -EFAULT;
+                       break;
+               }
+
+               bt_sk(sk)->defer_setup = opt;
+               break;
+
+       default:
+               err = -ENOPROTOOPT;
+               break;
+       }
+
+       release_sock(sk);
+       return err;
+}
+
+static int l2cap_sock_getsockopt_old(struct socket *sock, int optname, char __user *optval, int __user *optlen)
 {
        struct sock *sk = sock->sk;
        struct l2cap_options opts;
        struct l2cap_conninfo cinfo;
        int len, err = 0;
+       u32 opt;
 
        BT_DBG("sk %p", sk);
 
@@ -1100,12 +1368,36 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, ch
                break;
 
        case L2CAP_LM:
-               if (put_user(l2cap_pi(sk)->link_mode, (u32 __user *) optval))
+               switch (l2cap_pi(sk)->sec_level) {
+               case BT_SECURITY_LOW:
+                       opt = L2CAP_LM_AUTH;
+                       break;
+               case BT_SECURITY_MEDIUM:
+                       opt = L2CAP_LM_AUTH | L2CAP_LM_ENCRYPT;
+                       break;
+               case BT_SECURITY_HIGH:
+                       opt = L2CAP_LM_AUTH | L2CAP_LM_ENCRYPT |
+                                                       L2CAP_LM_SECURE;
+                       break;
+               default:
+                       opt = 0;
+                       break;
+               }
+
+               if (l2cap_pi(sk)->role_switch)
+                       opt |= L2CAP_LM_MASTER;
+
+               if (l2cap_pi(sk)->force_reliable)
+                       opt |= L2CAP_LM_RELIABLE;
+
+               if (put_user(opt, (u32 __user *) optval))
                        err = -EFAULT;
                break;
 
        case L2CAP_CONNINFO:
-               if (sk->sk_state != BT_CONNECTED) {
+               if (sk->sk_state != BT_CONNECTED &&
+                                       !(sk->sk_state == BT_CONNECT2 &&
+                                               bt_sk(sk)->defer_setup)) {
                        err = -ENOTCONN;
                        break;
                }
@@ -1128,6 +1420,60 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, ch
        return err;
 }
 
+static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, char __user *optval, int __user *optlen)
+{
+       struct sock *sk = sock->sk;
+       struct bt_security sec;
+       int len, err = 0;
+
+       BT_DBG("sk %p", sk);
+
+       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;
+
+       lock_sock(sk);
+
+       switch (optname) {
+       case BT_SECURITY:
+               if (sk->sk_type != SOCK_SEQPACKET) {
+                       err = -EINVAL;
+                       break;
+               }
+
+               sec.level = l2cap_pi(sk)->sec_level;
+
+               len = min_t(unsigned int, len, sizeof(sec));
+               if (copy_to_user(optval, (char *) &sec, len))
+                       err = -EFAULT;
+
+               break;
+
+       case BT_DEFER_SETUP:
+               if (sk->sk_state != BT_BOUND && sk->sk_state != BT_LISTEN) {
+                       err = -EINVAL;
+                       break;
+               }
+
+               if (put_user(bt_sk(sk)->defer_setup, (u32 __user *) optval))
+                       err = -EFAULT;
+
+               break;
+
+       default:
+               err = -ENOPROTOOPT;
+               break;
+       }
+
+       release_sock(sk);
+       return err;
+}
+
 static int l2cap_sock_shutdown(struct socket *sock, int how)
 {
        struct sock *sk = sock->sk;
@@ -1145,7 +1491,8 @@ static int l2cap_sock_shutdown(struct socket *sock, int how)
                __l2cap_sock_close(sk, 0);
 
                if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime)
-                       err = bt_sock_wait_state(sk, BT_CLOSED, sk->sk_lingertime);
+                       err = bt_sock_wait_state(sk, BT_CLOSED,
+                                                       sk->sk_lingertime);
        }
        release_sock(sk);
        return err;
@@ -1463,8 +1810,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);
        }
 
@@ -1477,10 +1827,10 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd
        struct l2cap_conn_req *req = (struct l2cap_conn_req *) data;
        struct l2cap_conn_rsp rsp;
        struct sock *sk, *parent;
-       int result = 0, status = 0;
+       int result, status = L2CAP_CS_NO_INFO;
 
        u16 dcid = 0, scid = __le16_to_cpu(req->scid);
-       __le16 psm  = req->psm;
+       __le16 psm = req->psm;
 
        BT_DBG("psm 0x%2.2x scid 0x%4.4x", psm, scid);
 
@@ -1491,6 +1841,14 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd
                goto sendresp;
        }
 
+       /* 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;
+       }
+
        result = L2CAP_CR_NO_MEM;
 
        /* Check for backlog size */
@@ -1499,7 +1857,7 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd
                goto response;
        }
 
-       sk = l2cap_sock_alloc(parent->sk_net, NULL, BTPROTO_L2CAP, GFP_ATOMIC);
+       sk = l2cap_sock_alloc(sock_net(parent), NULL, BTPROTO_L2CAP, GFP_ATOMIC);
        if (!sk)
                goto response;
 
@@ -1526,25 +1884,31 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd
 
        l2cap_sock_set_timer(sk, sk->sk_sndtimeo);
 
-       /* Service level security */
-       result = L2CAP_CR_PEND;
-       status = L2CAP_CS_AUTHEN_PEND;
-       sk->sk_state = BT_CONNECT2;
        l2cap_pi(sk)->ident = cmd->ident;
 
-       if ((l2cap_pi(sk)->link_mode & L2CAP_LM_ENCRYPT) ||
-                       (l2cap_pi(sk)->link_mode & L2CAP_LM_SECURE)) {
-               if (!hci_conn_encrypt(conn->hcon))
-                       goto done;
-       } else if (l2cap_pi(sk)->link_mode & L2CAP_LM_AUTH) {
-               if (!hci_conn_auth(conn->hcon))
-                       goto done;
+       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;
+                               result = L2CAP_CR_PEND;
+                               status = L2CAP_CS_AUTHOR_PEND;
+                               parent->sk_data_ready(parent, 0);
+                       } else {
+                               sk->sk_state = BT_CONFIG;
+                               result = L2CAP_CR_SUCCESS;
+                               status = L2CAP_CS_NO_INFO;
+                       }
+               } else {
+                       sk->sk_state = BT_CONNECT2;
+                       result = L2CAP_CR_PEND;
+                       status = L2CAP_CS_AUTHEN_PEND;
+               }
+       } else {
+               sk->sk_state = BT_CONNECT2;
+               result = L2CAP_CR_PEND;
+               status = L2CAP_CS_NO_INFO;
        }
 
-       sk->sk_state = BT_CONFIG;
-       result = status = 0;
-
-done:
        write_unlock_bh(&list->lock);
 
 response:
@@ -1556,6 +1920,21 @@ sendresp:
        rsp.result = cpu_to_le16(result);
        rsp.status = cpu_to_le16(status);
        l2cap_send_cmd(conn, cmd->ident, L2CAP_CONN_RSP, sizeof(rsp), &rsp);
+
+       if (result == L2CAP_CR_PEND && status == L2CAP_CS_NO_INFO) {
+               struct l2cap_info_req info;
+               info.type = cpu_to_le16(L2CAP_IT_FEAT_MASK);
+
+               conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_SENT;
+               conn->info_ident = l2cap_get_ident(conn);
+
+               mod_timer(&conn->info_timer, jiffies +
+                                       msecs_to_jiffies(L2CAP_INFO_TIMEOUT));
+
+               l2cap_send_cmd(conn, conn->info_ident,
+                                       L2CAP_INFO_REQ, sizeof(info), &info);
+       }
+
        return 0;
 }
 
@@ -1588,11 +1967,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:
@@ -1664,9 +2046,9 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr
        }
 
        if (!(l2cap_pi(sk)->conf_state & L2CAP_CONF_REQ_SENT)) {
-               u8 req[64];
+               u8 buf[64];
                l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
-                                       l2cap_build_conf_req(sk, req), req);
+                                       l2cap_build_conf_req(sk, buf), buf);
        }
 
 unlock:
@@ -1708,7 +2090,7 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr
 
        default:
                sk->sk_state = BT_DISCONN;
-               sk->sk_err   = ECONNRESET;
+               sk->sk_err = ECONNRESET;
                l2cap_sock_set_timer(sk, HZ * 5);
                {
                        struct l2cap_disconn_req req;
@@ -1801,6 +2183,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);
@@ -1822,14 +2212,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)
-               conn->feat_mask = __le32_to_cpu(get_unaligned((__le32 *) rsp->data));
+       if (type == L2CAP_IT_FEAT_MASK) {
+               conn->feat_mask = get_unaligned_le32(rsp->data);
 
-       l2cap_conn_start(conn);
+               if (conn->feat_mask & 0x0080) {
+                       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;
 }
@@ -2036,10 +2443,15 @@ static int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
                        continue;
 
                if (!bacmp(&bt_sk(sk)->src, &hdev->bdaddr)) {
-                       lm1 |= (HCI_LM_ACCEPT | l2cap_pi(sk)->link_mode);
+                       lm1 |= HCI_LM_ACCEPT;
+                       if (l2cap_pi(sk)->role_switch)
+                               lm1 |= HCI_LM_MASTER;
                        exact++;
-               } else if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY))
-                       lm2 |= (HCI_LM_ACCEPT | l2cap_pi(sk)->link_mode);
+               } else if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY)) {
+                       lm2 |= HCI_LM_ACCEPT;
+                       if (l2cap_pi(sk)->role_switch)
+                               lm2 |= HCI_LM_MASTER;
+               }
        }
        read_unlock(&l2cap_sk_list.lock);
 
@@ -2065,75 +2477,52 @@ 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)
 {
-       BT_DBG("hcon %p reason %d", hcon, reason);
+       struct l2cap_conn *conn = hcon->l2cap_data;
 
-       if (hcon->type != ACL_LINK)
-               return 0;
+       BT_DBG("hcon %p", hcon);
 
-       l2cap_conn_del(hcon, bt_err(reason));
+       if (hcon->type != ACL_LINK || !conn)
+               return 0x13;
 
-       return 0;
+       return conn->disc_reason;
 }
 
-static int l2cap_auth_cfm(struct hci_conn *hcon, u8 status)
+static int l2cap_disconn_cfm(struct hci_conn *hcon, u8 reason)
 {
-       struct l2cap_chan_list *l;
-       struct l2cap_conn *conn = conn = hcon->l2cap_data;
-       struct l2cap_conn_rsp rsp;
-       struct sock *sk;
-       int result;
+       BT_DBG("hcon %p reason %d", hcon, reason);
 
-       if (!conn)
+       if (hcon->type != ACL_LINK)
                return 0;
 
-       l = &conn->chan_list;
-
-       BT_DBG("conn %p", conn);
-
-       read_lock(&l->lock);
-
-       for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) {
-               bh_lock_sock(sk);
-
-               if (sk->sk_state != BT_CONNECT2 ||
-                               (l2cap_pi(sk)->link_mode & L2CAP_LM_ENCRYPT) ||
-                               (l2cap_pi(sk)->link_mode & L2CAP_LM_SECURE)) {
-                       bh_unlock_sock(sk);
-                       continue;
-               }
+       l2cap_conn_del(hcon, bt_err(reason));
 
-               if (!status) {
-                       sk->sk_state = BT_CONFIG;
-                       result = 0;
-               } else {
-                       sk->sk_state = BT_DISCONN;
-                       l2cap_sock_set_timer(sk, HZ/10);
-                       result = L2CAP_CR_SEC_BLOCK;
-               }
+       return 0;
+}
 
-               rsp.scid   = cpu_to_le16(l2cap_pi(sk)->dcid);
-               rsp.dcid   = cpu_to_le16(l2cap_pi(sk)->scid);
-               rsp.result = cpu_to_le16(result);
-               rsp.status = cpu_to_le16(0);
-               l2cap_send_cmd(conn, l2cap_pi(sk)->ident,
-                               L2CAP_CONN_RSP, sizeof(rsp), &rsp);
+static inline void l2cap_check_encryption(struct sock *sk, u8 encrypt)
+{
+       if (sk->sk_type != SOCK_SEQPACKET)
+               return;
 
-               bh_unlock_sock(sk);
+       if (encrypt == 0x00) {
+               if (l2cap_pi(sk)->sec_level == BT_SECURITY_MEDIUM) {
+                       l2cap_sock_clear_timer(sk);
+                       l2cap_sock_set_timer(sk, HZ * 5);
+               } else if (l2cap_pi(sk)->sec_level == BT_SECURITY_HIGH)
+                       __l2cap_sock_close(sk, ECONNREFUSED);
+       } else {
+               if (l2cap_pi(sk)->sec_level == BT_SECURITY_MEDIUM)
+                       l2cap_sock_clear_timer(sk);
        }
-
-       read_unlock(&l->lock);
-       return 0;
 }
 
-static int l2cap_encrypt_cfm(struct hci_conn *hcon, u8 status)
+static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
 {
        struct l2cap_chan_list *l;
        struct l2cap_conn *conn = hcon->l2cap_data;
-       struct l2cap_conn_rsp rsp;
        struct sock *sk;
-       int result;
 
        if (!conn)
                return 0;
@@ -2147,34 +2536,58 @@ static int l2cap_encrypt_cfm(struct hci_conn *hcon, u8 status)
        for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) {
                bh_lock_sock(sk);
 
-               if (sk->sk_state != BT_CONNECT2) {
+               if (l2cap_pi(sk)->conf_state & L2CAP_CONF_CONNECT_PEND) {
                        bh_unlock_sock(sk);
                        continue;
                }
 
-               if (!status) {
-                       sk->sk_state = BT_CONFIG;
-                       result = 0;
-               } else {
-                       sk->sk_state = BT_DISCONN;
-                       l2cap_sock_set_timer(sk, HZ/10);
-                       result = L2CAP_CR_SEC_BLOCK;
+               if (!status && (sk->sk_state == BT_CONNECTED ||
+                                               sk->sk_state == BT_CONFIG)) {
+                       l2cap_check_encryption(sk, encrypt);
+                       bh_unlock_sock(sk);
+                       continue;
                }
 
-               rsp.scid   = cpu_to_le16(l2cap_pi(sk)->dcid);
-               rsp.dcid   = cpu_to_le16(l2cap_pi(sk)->scid);
-               rsp.result = cpu_to_le16(result);
-               rsp.status = cpu_to_le16(0);
-               l2cap_send_cmd(conn, l2cap_pi(sk)->ident,
-                               L2CAP_CONN_RSP, sizeof(rsp), &rsp);
+               if (sk->sk_state == BT_CONNECT) {
+                       if (!status) {
+                               struct l2cap_conn_req req;
+                               req.scid = cpu_to_le16(l2cap_pi(sk)->scid);
+                               req.psm  = l2cap_pi(sk)->psm;
 
-               if (l2cap_pi(sk)->link_mode & L2CAP_LM_SECURE)
-                       hci_conn_change_link_key(hcon);
+                               l2cap_pi(sk)->ident = l2cap_get_ident(conn);
+
+                               l2cap_send_cmd(conn, l2cap_pi(sk)->ident,
+                                       L2CAP_CONN_REQ, sizeof(req), &req);
+                       } else {
+                               l2cap_sock_clear_timer(sk);
+                               l2cap_sock_set_timer(sk, HZ / 10);
+                       }
+               } else if (sk->sk_state == BT_CONNECT2) {
+                       struct l2cap_conn_rsp rsp;
+                       __u16 result;
+
+                       if (!status) {
+                               sk->sk_state = BT_CONFIG;
+                               result = L2CAP_CR_SUCCESS;
+                       } else {
+                               sk->sk_state = BT_DISCONN;
+                               l2cap_sock_set_timer(sk, HZ / 10);
+                               result = L2CAP_CR_SEC_BLOCK;
+                       }
+
+                       rsp.scid   = cpu_to_le16(l2cap_pi(sk)->dcid);
+                       rsp.dcid   = cpu_to_le16(l2cap_pi(sk)->scid);
+                       rsp.result = cpu_to_le16(result);
+                       rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
+                       l2cap_send_cmd(conn, l2cap_pi(sk)->ident,
+                                       L2CAP_CONN_RSP, sizeof(rsp), &rsp);
+               }
 
                bh_unlock_sock(sk);
        }
 
        read_unlock(&l->lock);
+
        return 0;
 }
 
@@ -2228,7 +2641,7 @@ static int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 fl
                        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);
@@ -2250,7 +2663,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) {
@@ -2276,10 +2689,10 @@ static ssize_t l2cap_sysfs_show(struct class *dev, char *buf)
        sk_for_each(sk, node, &l2cap_sk_list.head) {
                struct l2cap_pinfo *pi = l2cap_pi(sk);
 
-               str += sprintf(str, "%s %s %d %d 0x%4.4x 0x%4.4x %d %d 0x%x\n",
+               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->link_mode);
+                               pi->imtu, pi->omtu, pi->sec_level);
        }
 
        read_unlock_bh(&l2cap_sk_list.lock);
@@ -2299,11 +2712,11 @@ static const struct proto_ops l2cap_sock_ops = {
        .accept         = l2cap_sock_accept,
        .getname        = l2cap_sock_getname,
        .sendmsg        = l2cap_sock_sendmsg,
-       .recvmsg        = bt_sock_recvmsg,
+       .recvmsg        = l2cap_sock_recvmsg,
        .poll           = bt_sock_poll,
+       .ioctl          = bt_sock_ioctl,
        .mmap           = sock_no_mmap,
        .socketpair     = sock_no_socketpair,
-       .ioctl          = sock_no_ioctl,
        .shutdown       = l2cap_sock_shutdown,
        .setsockopt     = l2cap_sock_setsockopt,
        .getsockopt     = l2cap_sock_getsockopt
@@ -2321,8 +2734,8 @@ static struct hci_proto l2cap_hci_proto = {
        .connect_ind    = l2cap_connect_ind,
        .connect_cfm    = l2cap_connect_cfm,
        .disconn_ind    = l2cap_disconn_ind,
-       .auth_cfm       = l2cap_auth_cfm,
-       .encrypt_cfm    = l2cap_encrypt_cfm,
+       .disconn_cfm    = l2cap_disconn_cfm,
+       .security_cfm   = l2cap_security_cfm,
        .recv_acldata   = l2cap_recv_acldata
 };
 
@@ -2385,7 +2798,7 @@ EXPORT_SYMBOL(l2cap_load);
 module_init(l2cap_init);
 module_exit(l2cap_exit);
 
-MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>, Marcel Holtmann <marcel@holtmann.org>");
+MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
 MODULE_DESCRIPTION("Bluetooth L2CAP ver " VERSION);
 MODULE_VERSION(VERSION);
 MODULE_LICENSE("GPL");