]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - net/bluetooth/l2cap_sock.c
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/geert/linux...
[karo-tx-linux.git] / net / bluetooth / l2cap_sock.c
index c1455f72bf03178e45d23d7559d96b1c89c964a3..fc85e7ae33c732fe729ee76db3d8df03e0e5d572 100644 (file)
 /* Bluetooth L2CAP sockets. */
 
 #include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci_core.h>
 #include <net/bluetooth/l2cap.h>
 
+/* ---- L2CAP timers ---- */
 static void l2cap_sock_timeout(unsigned long arg)
 {
        struct sock *sk = (struct sock *) arg;
@@ -62,6 +64,928 @@ static void l2cap_sock_timeout(unsigned long arg)
        sock_put(sk);
 }
 
+void l2cap_sock_set_timer(struct sock *sk, long timeout)
+{
+       BT_DBG("sk %p state %d timeout %ld", sk, sk->sk_state, timeout);
+       sk_reset_timer(sk, &sk->sk_timer, jiffies + timeout);
+}
+
+void l2cap_sock_clear_timer(struct sock *sk)
+{
+       BT_DBG("sock %p state %d", sk, sk->sk_state);
+       sk_stop_timer(sk, &sk->sk_timer);
+}
+
+static struct sock *__l2cap_get_sock_by_addr(__le16 psm, bdaddr_t *src)
+{
+       struct sock *sk;
+       struct hlist_node *node;
+       sk_for_each(sk, node, &l2cap_sk_list.head)
+               if (l2cap_pi(sk)->sport == psm && !bacmp(&bt_sk(sk)->src, src))
+                       goto found;
+       sk = NULL;
+found:
+       return sk;
+}
+
+static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen)
+{
+       struct sock *sk = sock->sk;
+       struct sockaddr_l2 la;
+       int len, err = 0;
+
+       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 && la.l2_psm)
+               return -EINVAL;
+
+       lock_sock(sk);
+
+       if (sk->sk_state != BT_OPEN) {
+               err = -EBADFD;
+               goto done;
+       }
+
+       if (la.l2_psm) {
+               __u16 psm = __le16_to_cpu(la.l2_psm);
+
+               /* PSM must be odd and lsb of upper byte must be 0 */
+               if ((psm & 0x0101) != 0x0001) {
+                       err = -EINVAL;
+                       goto done;
+               }
+
+               /* Restrict usage of well-known PSMs */
+               if (psm < 0x1001 && !capable(CAP_NET_BIND_SERVICE)) {
+                       err = -EACCES;
+                       goto done;
+               }
+       }
+
+       write_lock_bh(&l2cap_sk_list.lock);
+
+       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;
+               sk->sk_state = BT_BOUND;
+
+               if (__le16_to_cpu(la.l2_psm) == 0x0001 ||
+                                       __le16_to_cpu(la.l2_psm) == 0x0003)
+                       l2cap_pi(sk)->sec_level = BT_SECURITY_SDP;
+       }
+
+       if (la.l2_cid)
+               l2cap_pi(sk)->scid = la.l2_cid;
+
+       write_unlock_bh(&l2cap_sk_list.lock);
+
+done:
+       release_sock(sk);
+       return err;
+}
+
+static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int alen, int flags)
+{
+       struct sock *sk = sock->sk;
+       struct sockaddr_l2 la;
+       int len, err = 0;
+
+       BT_DBG("sk %p", sk);
+
+       if (!addr || alen < sizeof(addr->sa_family) ||
+           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 && la.l2_psm)
+               return -EINVAL;
+
+       lock_sock(sk);
+
+       if ((sk->sk_type == SOCK_SEQPACKET || sk->sk_type == SOCK_STREAM)
+                       && !(la.l2_psm || la.l2_cid)) {
+               err = -EINVAL;
+               goto done;
+       }
+
+       switch (l2cap_pi(sk)->mode) {
+       case L2CAP_MODE_BASIC:
+               break;
+       case L2CAP_MODE_ERTM:
+       case L2CAP_MODE_STREAMING:
+               if (!disable_ertm)
+                       break;
+               /* fall through */
+       default:
+               err = -ENOTSUPP;
+               goto done;
+       }
+
+       switch (sk->sk_state) {
+       case BT_CONNECT:
+       case BT_CONNECT2:
+       case BT_CONFIG:
+               /* Already connecting */
+               goto wait;
+
+       case BT_CONNECTED:
+               /* Already connected */
+               err = -EISCONN;
+               goto done;
+
+       case BT_OPEN:
+       case BT_BOUND:
+               /* Can connect */
+               break;
+
+       default:
+               err = -EBADFD;
+               goto done;
+       }
+
+       /* PSM must be odd and lsb of upper byte must be 0 */
+       if ((__le16_to_cpu(la.l2_psm) & 0x0101) != 0x0001 &&
+                               sk->sk_type != SOCK_RAW && !la.l2_cid) {
+               err = -EINVAL;
+               goto done;
+       }
+
+       /* Set destination address and psm */
+       bacpy(&bt_sk(sk)->dst, &la.l2_bdaddr);
+       l2cap_pi(sk)->psm = la.l2_psm;
+       l2cap_pi(sk)->dcid = la.l2_cid;
+
+       err = l2cap_do_connect(sk);
+       if (err)
+               goto done;
+
+wait:
+       err = bt_sock_wait_state(sk, BT_CONNECTED,
+                       sock_sndtimeo(sk, flags & O_NONBLOCK));
+done:
+       release_sock(sk);
+       return err;
+}
+
+static int l2cap_sock_listen(struct socket *sock, int backlog)
+{
+       struct sock *sk = sock->sk;
+       int err = 0;
+
+       BT_DBG("sk %p backlog %d", sk, backlog);
+
+       lock_sock(sk);
+
+       if ((sock->type != SOCK_SEQPACKET && sock->type != SOCK_STREAM)
+                       || sk->sk_state != BT_BOUND) {
+               err = -EBADFD;
+               goto done;
+       }
+
+       switch (l2cap_pi(sk)->mode) {
+       case L2CAP_MODE_BASIC:
+               break;
+       case L2CAP_MODE_ERTM:
+       case L2CAP_MODE_STREAMING:
+               if (!disable_ertm)
+                       break;
+               /* fall through */
+       default:
+               err = -ENOTSUPP;
+               goto done;
+       }
+
+       if (!l2cap_pi(sk)->psm && !l2cap_pi(sk)->dcid) {
+               bdaddr_t *src = &bt_sk(sk)->src;
+               u16 psm;
+
+               err = -EINVAL;
+
+               write_lock_bh(&l2cap_sk_list.lock);
+
+               for (psm = 0x1001; psm < 0x1100; psm += 2)
+                       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;
+                       }
+
+               write_unlock_bh(&l2cap_sk_list.lock);
+
+               if (err < 0)
+                       goto done;
+       }
+
+       sk->sk_max_ack_backlog = backlog;
+       sk->sk_ack_backlog = 0;
+       sk->sk_state = BT_LISTEN;
+
+done:
+       release_sock(sk);
+       return err;
+}
+
+static int l2cap_sock_accept(struct socket *sock, struct socket *newsock, int flags)
+{
+       DECLARE_WAITQUEUE(wait, current);
+       struct sock *sk = sock->sk, *nsk;
+       long timeo;
+       int err = 0;
+
+       lock_sock_nested(sk, SINGLE_DEPTH_NESTING);
+
+       if (sk->sk_state != BT_LISTEN) {
+               err = -EBADFD;
+               goto done;
+       }
+
+       timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK);
+
+       BT_DBG("sk %p timeo %ld", sk, timeo);
+
+       /* Wait for an incoming connection. (wake-one). */
+       add_wait_queue_exclusive(sk_sleep(sk), &wait);
+       while (!(nsk = bt_accept_dequeue(sk, newsock))) {
+               set_current_state(TASK_INTERRUPTIBLE);
+               if (!timeo) {
+                       err = -EAGAIN;
+                       break;
+               }
+
+               release_sock(sk);
+               timeo = schedule_timeout(timeo);
+               lock_sock_nested(sk, SINGLE_DEPTH_NESTING);
+
+               if (sk->sk_state != BT_LISTEN) {
+                       err = -EBADFD;
+                       break;
+               }
+
+               if (signal_pending(current)) {
+                       err = sock_intr_errno(timeo);
+                       break;
+               }
+       }
+       set_current_state(TASK_RUNNING);
+       remove_wait_queue(sk_sleep(sk), &wait);
+
+       if (err)
+               goto done;
+
+       newsock->state = SS_CONNECTED;
+
+       BT_DBG("new socket %p", nsk);
+
+done:
+       release_sock(sk);
+       return err;
+}
+
+static int l2cap_sock_getname(struct socket *sock, struct sockaddr *addr, int *len, int peer)
+{
+       struct sockaddr_l2 *la = (struct sockaddr_l2 *) addr;
+       struct sock *sk = sock->sk;
+
+       BT_DBG("sock %p, sk %p", sock, sk);
+
+       addr->sa_family = AF_BLUETOOTH;
+       *len = sizeof(struct sockaddr_l2);
+
+       if (peer) {
+               la->l2_psm = l2cap_pi(sk)->psm;
+               bacpy(&la->l2_bdaddr, &bt_sk(sk)->dst);
+               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);
+       }
+
+       return 0;
+}
+
+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);
+
+       if (get_user(len, optlen))
+               return -EFAULT;
+
+       lock_sock(sk);
+
+       switch (optname) {
+       case L2CAP_OPTIONS:
+               memset(&opts, 0, sizeof(opts));
+               opts.imtu     = l2cap_pi(sk)->imtu;
+               opts.omtu     = l2cap_pi(sk)->omtu;
+               opts.flush_to = l2cap_pi(sk)->flush_to;
+               opts.mode     = l2cap_pi(sk)->mode;
+               opts.fcs      = l2cap_pi(sk)->fcs;
+               opts.max_tx   = l2cap_pi(sk)->max_tx;
+               opts.txwin_size = (__u16)l2cap_pi(sk)->tx_win;
+
+               len = min_t(unsigned int, len, sizeof(opts));
+               if (copy_to_user(optval, (char *) &opts, len))
+                       err = -EFAULT;
+
+               break;
+
+       case L2CAP_LM:
+               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 &&
+                                       !(sk->sk_state == BT_CONNECT2 &&
+                                               bt_sk(sk)->defer_setup)) {
+                       err = -ENOTCONN;
+                       break;
+               }
+
+               cinfo.hci_handle = l2cap_pi(sk)->conn->hcon->handle;
+               memcpy(cinfo.dev_class, l2cap_pi(sk)->conn->hcon->dev_class, 3);
+
+               len = min_t(unsigned int, len, sizeof(cinfo));
+               if (copy_to_user(optval, (char *) &cinfo, len))
+                       err = -EFAULT;
+
+               break;
+
+       default:
+               err = -ENOPROTOOPT;
+               break;
+       }
+
+       release_sock(sk);
+       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 && sk->sk_type != SOCK_STREAM
+                               && sk->sk_type != SOCK_RAW) {
+                       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;
+
+       case BT_FLUSHABLE:
+               if (put_user(l2cap_pi(sk)->flushable, (u32 __user *) optval))
+                       err = -EFAULT;
+
+               break;
+
+       default:
+               err = -ENOPROTOOPT;
+               break;
+       }
+
+       release_sock(sk);
+       return err;
+}
+
+static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __user *optval, unsigned int optlen)
+{
+       struct sock *sk = sock->sk;
+       struct l2cap_options opts;
+       int len, err = 0;
+       u32 opt;
+
+       BT_DBG("sk %p", sk);
+
+       lock_sock(sk);
+
+       switch (optname) {
+       case L2CAP_OPTIONS:
+               if (sk->sk_state == BT_CONNECTED) {
+                       err = -EINVAL;
+                       break;
+               }
+
+               opts.imtu     = l2cap_pi(sk)->imtu;
+               opts.omtu     = l2cap_pi(sk)->omtu;
+               opts.flush_to = l2cap_pi(sk)->flush_to;
+               opts.mode     = l2cap_pi(sk)->mode;
+               opts.fcs      = l2cap_pi(sk)->fcs;
+               opts.max_tx   = l2cap_pi(sk)->max_tx;
+               opts.txwin_size = (__u16)l2cap_pi(sk)->tx_win;
+
+               len = min_t(unsigned int, sizeof(opts), optlen);
+               if (copy_from_user((char *) &opts, optval, len)) {
+                       err = -EFAULT;
+                       break;
+               }
+
+               if (opts.txwin_size > L2CAP_DEFAULT_TX_WINDOW) {
+                       err = -EINVAL;
+                       break;
+               }
+
+               l2cap_pi(sk)->mode = opts.mode;
+               switch (l2cap_pi(sk)->mode) {
+               case L2CAP_MODE_BASIC:
+                       l2cap_pi(sk)->conf_state &= ~L2CAP_CONF_STATE2_DEVICE;
+                       break;
+               case L2CAP_MODE_ERTM:
+               case L2CAP_MODE_STREAMING:
+                       if (!disable_ertm)
+                               break;
+                       /* fall through */
+               default:
+                       err = -EINVAL;
+                       break;
+               }
+
+               l2cap_pi(sk)->imtu = opts.imtu;
+               l2cap_pi(sk)->omtu = opts.omtu;
+               l2cap_pi(sk)->fcs  = opts.fcs;
+               l2cap_pi(sk)->max_tx = opts.max_tx;
+               l2cap_pi(sk)->tx_win = (__u8)opts.txwin_size;
+               break;
+
+       case L2CAP_LM:
+               if (get_user(opt, (u32 __user *) optval)) {
+                       err = -EFAULT;
+                       break;
+               }
+
+               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:
+               err = -ENOPROTOOPT;
+               break;
+       }
+
+       release_sock(sk);
+       return err;
+}
+
+static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, char __user *optval, unsigned 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 && sk->sk_type != SOCK_STREAM
+                               && sk->sk_type != SOCK_RAW) {
+                       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;
+
+       case BT_FLUSHABLE:
+               if (get_user(opt, (u32 __user *) optval)) {
+                       err = -EFAULT;
+                       break;
+               }
+
+               if (opt > BT_FLUSHABLE_ON) {
+                       err = -EINVAL;
+                       break;
+               }
+
+               if (opt == BT_FLUSHABLE_OFF) {
+                       struct l2cap_conn *conn = l2cap_pi(sk)->conn;
+                       /* proceed futher only when we have l2cap_conn and
+                          No Flush support in the LM */
+                       if (!conn || !lmp_no_flush_capable(conn->hcon->hdev)) {
+                               err = -EINVAL;
+                               break;
+                       }
+               }
+
+               l2cap_pi(sk)->flushable = opt;
+               break;
+
+       default:
+               err = -ENOPROTOOPT;
+               break;
+       }
+
+       release_sock(sk);
+       return err;
+}
+
+static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, size_t len)
+{
+       struct sock *sk = sock->sk;
+       struct l2cap_pinfo *pi = l2cap_pi(sk);
+       struct sk_buff *skb;
+       u16 control;
+       int err;
+
+       BT_DBG("sock %p, sk %p", sock, sk);
+
+       err = sock_error(sk);
+       if (err)
+               return err;
+
+       if (msg->msg_flags & MSG_OOB)
+               return -EOPNOTSUPP;
+
+       lock_sock(sk);
+
+       if (sk->sk_state != BT_CONNECTED) {
+               err = -ENOTCONN;
+               goto done;
+       }
+
+       /* Connectionless channel */
+       if (sk->sk_type == SOCK_DGRAM) {
+               skb = l2cap_create_connless_pdu(sk, msg, len);
+               if (IS_ERR(skb)) {
+                       err = PTR_ERR(skb);
+               } else {
+                       l2cap_do_send(sk, skb);
+                       err = len;
+               }
+               goto done;
+       }
+
+       switch (pi->mode) {
+       case L2CAP_MODE_BASIC:
+               /* Check outgoing MTU */
+               if (len > pi->omtu) {
+                       err = -EMSGSIZE;
+                       goto done;
+               }
+
+               /* Create a basic PDU */
+               skb = l2cap_create_basic_pdu(sk, msg, len);
+               if (IS_ERR(skb)) {
+                       err = PTR_ERR(skb);
+                       goto done;
+               }
+
+               l2cap_do_send(sk, skb);
+               err = len;
+               break;
+
+       case L2CAP_MODE_ERTM:
+       case L2CAP_MODE_STREAMING:
+               /* Entire SDU fits into one PDU */
+               if (len <= pi->remote_mps) {
+                       control = L2CAP_SDU_UNSEGMENTED;
+                       skb = l2cap_create_iframe_pdu(sk, msg, len, control, 0);
+                       if (IS_ERR(skb)) {
+                               err = PTR_ERR(skb);
+                               goto done;
+                       }
+                       __skb_queue_tail(TX_QUEUE(sk), skb);
+
+                       if (sk->sk_send_head == NULL)
+                               sk->sk_send_head = skb;
+
+               } else {
+               /* Segment SDU into multiples PDUs */
+                       err = l2cap_sar_segment_sdu(sk, msg, len);
+                       if (err < 0)
+                               goto done;
+               }
+
+               if (pi->mode == L2CAP_MODE_STREAMING) {
+                       l2cap_streaming_send(sk);
+               } else {
+                       if ((pi->conn_state & L2CAP_CONN_REMOTE_BUSY) &&
+                                       (pi->conn_state & L2CAP_CONN_WAIT_F)) {
+                               err = len;
+                               break;
+                       }
+                       err = l2cap_ertm_send(sk);
+               }
+
+               if (err >= 0)
+                       err = len;
+               break;
+
+       default:
+               BT_DBG("bad state %1.1x", pi->mode);
+               err = -EBADFD;
+       }
+
+done:
+       release_sock(sk);
+       return err;
+}
+
+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;
+               struct l2cap_conn *conn = l2cap_pi(sk)->conn;
+               u8 buf[128];
+
+               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);
+
+               if (l2cap_pi(sk)->conf_state & L2CAP_CONF_REQ_SENT) {
+                       release_sock(sk);
+                       return 0;
+               }
+
+               l2cap_pi(sk)->conf_state |= L2CAP_CONF_REQ_SENT;
+               l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
+                               l2cap_build_conf_req(sk, buf), buf);
+               l2cap_pi(sk)->num_conf_req++;
+
+               release_sock(sk);
+               return 0;
+       }
+
+       release_sock(sk);
+
+       if (sock->type == SOCK_STREAM)
+               return bt_sock_stream_recvmsg(iocb, sock, msg, len, flags);
+
+       return bt_sock_recvmsg(iocb, sock, msg, len, flags);
+}
+
+/* Kill socket (only if zapped and orphan)
+ * Must be called on unlocked socket.
+ */
+void l2cap_sock_kill(struct sock *sk)
+{
+       if (!sock_flag(sk, SOCK_ZAPPED) || sk->sk_socket)
+               return;
+
+       BT_DBG("sk %p state %d", sk, sk->sk_state);
+
+       /* Kill poor orphan */
+       bt_sock_unlink(&l2cap_sk_list, sk);
+       sock_set_flag(sk, SOCK_DEAD);
+       sock_put(sk);
+}
+
+/* Must be called on unlocked socket. */
+static void l2cap_sock_close(struct sock *sk)
+{
+       l2cap_sock_clear_timer(sk);
+       lock_sock(sk);
+       __l2cap_sock_close(sk, ECONNRESET);
+       release_sock(sk);
+       l2cap_sock_kill(sk);
+}
+
+static void l2cap_sock_cleanup_listen(struct sock *parent)
+{
+       struct sock *sk;
+
+       BT_DBG("parent %p", parent);
+
+       /* Close not yet accepted channels */
+       while ((sk = bt_accept_dequeue(parent, NULL)))
+               l2cap_sock_close(sk);
+
+       parent->sk_state = BT_CLOSED;
+       sock_set_flag(parent, SOCK_ZAPPED);
+}
+
+void __l2cap_sock_close(struct sock *sk, int reason)
+{
+       struct l2cap_conn *conn = l2cap_pi(sk)->conn;
+
+       BT_DBG("sk %p state %d socket %p", sk, sk->sk_state, sk->sk_socket);
+
+       switch (sk->sk_state) {
+       case BT_LISTEN:
+               l2cap_sock_cleanup_listen(sk);
+               break;
+
+       case BT_CONNECTED:
+       case BT_CONFIG:
+               if ((sk->sk_type == SOCK_SEQPACKET ||
+                                       sk->sk_type == SOCK_STREAM) &&
+                                       conn->hcon->type == ACL_LINK) {
+                       l2cap_sock_set_timer(sk, sk->sk_sndtimeo);
+                       l2cap_send_disconn_req(conn, sk, reason);
+               } else
+                       l2cap_chan_del(sk, reason);
+               break;
+
+       case BT_CONNECT2:
+               if ((sk->sk_type == SOCK_SEQPACKET ||
+                                       sk->sk_type == SOCK_STREAM) &&
+                                       conn->hcon->type == ACL_LINK) {
+                       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:
+       case BT_DISCONN:
+               l2cap_chan_del(sk, reason);
+               break;
+
+       default:
+               sock_set_flag(sk, SOCK_ZAPPED);
+               break;
+       }
+}
+
+static int l2cap_sock_shutdown(struct socket *sock, int how)
+{
+       struct sock *sk = sock->sk;
+       int err = 0;
+
+       BT_DBG("sock %p, sk %p", sock, sk);
+
+       if (!sk)
+               return 0;
+
+       lock_sock(sk);
+       if (!sk->sk_shutdown) {
+               if (l2cap_pi(sk)->mode == L2CAP_MODE_ERTM)
+                       err = __l2cap_wait_ack(sk);
+
+               sk->sk_shutdown = SHUTDOWN_MASK;
+               l2cap_sock_clear_timer(sk);
+               __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);
+       }
+
+       if (!err && sk->sk_err)
+               err = -sk->sk_err;
+
+       release_sock(sk);
+       return err;
+}
+
+static int l2cap_sock_release(struct socket *sock)
+{
+       struct sock *sk = sock->sk;
+       int err;
+
+       BT_DBG("sock %p, sk %p", sock, sk);
+
+       if (!sk)
+               return 0;
+
+       err = l2cap_sock_shutdown(sock, 2);
+
+       sock_orphan(sk);
+       l2cap_sock_kill(sk);
+       return err;
+}
+
 static void l2cap_sock_destruct(struct sock *sk)
 {
        BT_DBG("sk %p", sk);
@@ -203,30 +1127,30 @@ static const struct net_proto_family l2cap_sock_family_ops = {
 
 int __init l2cap_init_sockets(void)
 {
-       int err;
+       int err;
 
-       err = proto_register(&l2cap_proto, 0);
-       if (err < 0)
-               return err;
+       err = proto_register(&l2cap_proto, 0);
+       if (err < 0)
+               return err;
 
-       err = bt_sock_register(BTPROTO_L2CAP, &l2cap_sock_family_ops);
-       if (err < 0)
-               goto error;
+       err = bt_sock_register(BTPROTO_L2CAP, &l2cap_sock_family_ops);
+       if (err < 0)
+               goto error;
 
-       BT_INFO("L2CAP socket layer initialized");
+       BT_INFO("L2CAP socket layer initialized");
 
-       return 0;
+       return 0;
 
 error:
-       BT_ERR("L2CAP socket registration failed");
-       proto_unregister(&l2cap_proto);
-       return err;
+       BT_ERR("L2CAP socket registration failed");
+       proto_unregister(&l2cap_proto);
+       return err;
 }
 
 void l2cap_cleanup_sockets(void)
 {
-       if (bt_sock_unregister(BTPROTO_L2CAP) < 0)
-               BT_ERR("L2CAP socket unregistration failed");
+       if (bt_sock_unregister(BTPROTO_L2CAP) < 0)
+               BT_ERR("L2CAP socket unregistration failed");
 
-       proto_unregister(&l2cap_proto);
+       proto_unregister(&l2cap_proto);
 }