Bluetooth: Add support for deferring RFCOMM connection setup

In order to decide if listening RFCOMM sockets should be accept()ed
the BD_ADDR of the remote device needs to be known. This patch adds
a socket option which defines a timeout for deferring the actual
connection setup.

The connection setup is done after reading from the socket for the
first time. Until then writing to the socket returns ENOTCONN.

Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c
index 65dd713..d37a829 100644
--- a/net/bluetooth/rfcomm/sock.c
+++ b/net/bluetooth/rfcomm/sock.c
@@ -262,8 +262,10 @@
 	if (parent) {
 		sk->sk_type = parent->sk_type;
 		pi->link_mode = rfcomm_pi(parent)->link_mode;
+		pi->dlc->defer_setup = bt_sk(parent)->defer_setup;
 	} else {
 		pi->link_mode = 0;
+		pi->dlc->defer_setup = 0;
 	}
 
 	pi->dlc->link_mode = pi->link_mode;
@@ -554,6 +556,9 @@
 	struct sk_buff *skb;
 	int sent = 0;
 
+	if (test_bit(RFCOMM_DEFER_SETUP, &d->flags))
+		return -ENOTCONN;
+
 	if (msg->msg_flags & MSG_OOB)
 		return -EOPNOTSUPP;
 
@@ -633,10 +638,16 @@
 			       struct msghdr *msg, size_t size, int flags)
 {
 	struct sock *sk = sock->sk;
+	struct rfcomm_dlc *d = rfcomm_pi(sk)->dlc;
 	int err = 0;
 	size_t target, copied = 0;
 	long timeo;
 
+	if (test_and_clear_bit(RFCOMM_DEFER_SETUP, &d->flags)) {
+		rfcomm_dlc_accept(d);
+		return 0;
+	}
+
 	if (flags & MSG_OOB)
 		return -EOPNOTSUPP;
 
@@ -746,6 +757,7 @@
 {
 	struct sock *sk = sock->sk;
 	int err = 0;
+	u32 opt;
 
 	BT_DBG("sk %p", sk);
 
@@ -755,6 +767,20 @@
 	lock_sock(sk);
 
 	switch (optname) {
+	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;
@@ -785,7 +811,8 @@
 		break;
 
 	case RFCOMM_CONNINFO:
-		if (sk->sk_state != BT_CONNECTED) {
+		if (sk->sk_state != BT_CONNECTED &&
+					!rfcomm_pi(sk)->dlc->defer_setup) {
 			err = -ENOTCONN;
 			break;
 		}
@@ -826,6 +853,17 @@
 	lock_sock(sk);
 
 	switch (optname) {
+	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;
@@ -938,6 +976,10 @@
 
 done:
 	bh_unlock_sock(parent);
+
+	if (bt_sk(parent)->defer_setup)
+		parent->sk_state_change(parent);
+
 	return result;
 }