Răsfoiți Sursa

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>
Marcel Holtmann 16 ani în urmă
părinte
comite
bb23c0ab82
3 a modificat fișierele cu 88 adăugiri și 18 ștergeri
  1. 4 2
      include/net/bluetooth/rfcomm.h
  2. 41 15
      net/bluetooth/rfcomm/core.c
  3. 43 1
      net/bluetooth/rfcomm/sock.c

+ 4 - 2
include/net/bluetooth/rfcomm.h

@@ -185,6 +185,7 @@ struct rfcomm_dlc {
 	u8            out;
 	u8            out;
 
 
 	u32           link_mode;
 	u32           link_mode;
+	u32           defer_setup;
 
 
 	uint          mtu;
 	uint          mtu;
 	uint          cfc;
 	uint          cfc;
@@ -202,10 +203,11 @@ struct rfcomm_dlc {
 #define RFCOMM_RX_THROTTLED 0
 #define RFCOMM_RX_THROTTLED 0
 #define RFCOMM_TX_THROTTLED 1
 #define RFCOMM_TX_THROTTLED 1
 #define RFCOMM_TIMED_OUT    2
 #define RFCOMM_TIMED_OUT    2
-#define RFCOMM_MSC_PENDING  3 
+#define RFCOMM_MSC_PENDING  3
 #define RFCOMM_AUTH_PENDING 4
 #define RFCOMM_AUTH_PENDING 4
 #define RFCOMM_AUTH_ACCEPT  5
 #define RFCOMM_AUTH_ACCEPT  5
 #define RFCOMM_AUTH_REJECT  6
 #define RFCOMM_AUTH_REJECT  6
+#define RFCOMM_DEFER_SETUP  7
 
 
 /* Scheduling flags and events */
 /* Scheduling flags and events */
 #define RFCOMM_SCHED_STATE  0
 #define RFCOMM_SCHED_STATE  0
@@ -239,6 +241,7 @@ int  rfcomm_dlc_close(struct rfcomm_dlc *d, int reason);
 int  rfcomm_dlc_send(struct rfcomm_dlc *d, struct sk_buff *skb);
 int  rfcomm_dlc_send(struct rfcomm_dlc *d, struct sk_buff *skb);
 int  rfcomm_dlc_set_modem_status(struct rfcomm_dlc *d, u8 v24_sig);
 int  rfcomm_dlc_set_modem_status(struct rfcomm_dlc *d, u8 v24_sig);
 int  rfcomm_dlc_get_modem_status(struct rfcomm_dlc *d, u8 *v24_sig);
 int  rfcomm_dlc_get_modem_status(struct rfcomm_dlc *d, u8 *v24_sig);
+void rfcomm_dlc_accept(struct rfcomm_dlc *d);
 
 
 #define rfcomm_dlc_lock(d)     spin_lock(&d->lock)
 #define rfcomm_dlc_lock(d)     spin_lock(&d->lock)
 #define rfcomm_dlc_unlock(d)   spin_unlock(&d->lock)
 #define rfcomm_dlc_unlock(d)   spin_unlock(&d->lock)
@@ -333,7 +336,6 @@ struct rfcomm_dev_req {
 	bdaddr_t src;
 	bdaddr_t src;
 	bdaddr_t dst;
 	bdaddr_t dst;
 	u8       channel;
 	u8       channel;
-	
 };
 };
 
 
 struct rfcomm_dev_info {
 struct rfcomm_dev_info {

+ 41 - 15
net/bluetooth/rfcomm/core.c

@@ -421,9 +421,16 @@ static int __rfcomm_dlc_close(struct rfcomm_dlc *d, int err)
 			d, d->state, d->dlci, err, s);
 			d, d->state, d->dlci, err, s);
 
 
 	switch (d->state) {
 	switch (d->state) {
-	case BT_CONNECTED:
-	case BT_CONFIG:
 	case BT_CONNECT:
 	case BT_CONNECT:
+	case BT_CONFIG:
+		if (test_and_clear_bit(RFCOMM_DEFER_SETUP, &d->flags)) {
+			set_bit(RFCOMM_AUTH_REJECT, &d->flags);
+			rfcomm_schedule(RFCOMM_SCHED_AUTH);
+			break;
+		}
+		/* Fall through */
+
+	case BT_CONNECTED:
 		d->state = BT_DISCONN;
 		d->state = BT_DISCONN;
 		if (skb_queue_empty(&d->tx_queue)) {
 		if (skb_queue_empty(&d->tx_queue)) {
 			rfcomm_send_disc(s, d->dlci);
 			rfcomm_send_disc(s, d->dlci);
@@ -434,6 +441,14 @@ static int __rfcomm_dlc_close(struct rfcomm_dlc *d, int err)
 		}
 		}
 		break;
 		break;
 
 
+	case BT_OPEN:
+		if (test_and_clear_bit(RFCOMM_DEFER_SETUP, &d->flags)) {
+			set_bit(RFCOMM_AUTH_REJECT, &d->flags);
+			rfcomm_schedule(RFCOMM_SCHED_AUTH);
+			break;
+		}
+		/* Fall through */
+
 	default:
 	default:
 		rfcomm_dlc_clear_timer(d);
 		rfcomm_dlc_clear_timer(d);
 
 
@@ -1162,7 +1177,7 @@ static int rfcomm_recv_disc(struct rfcomm_session *s, u8 dlci)
 	return 0;
 	return 0;
 }
 }
 
 
-static void rfcomm_dlc_accept(struct rfcomm_dlc *d)
+void rfcomm_dlc_accept(struct rfcomm_dlc *d)
 {
 {
 	struct sock *sk = d->session->sock->sk;
 	struct sock *sk = d->session->sock->sk;
 
 
@@ -1181,6 +1196,20 @@ static void rfcomm_dlc_accept(struct rfcomm_dlc *d)
 	rfcomm_send_msc(d->session, 1, d->dlci, d->v24_sig);
 	rfcomm_send_msc(d->session, 1, d->dlci, d->v24_sig);
 }
 }
 
 
+static void rfcomm_check_accept(struct rfcomm_dlc *d)
+{
+	if (rfcomm_check_link_mode(d)) {
+		set_bit(RFCOMM_AUTH_PENDING, &d->flags);
+		rfcomm_dlc_set_timer(d, RFCOMM_AUTH_TIMEOUT);
+	} else {
+		if (d->defer_setup) {
+			set_bit(RFCOMM_DEFER_SETUP, &d->flags);
+			rfcomm_dlc_set_timer(d, RFCOMM_AUTH_TIMEOUT);
+		} else
+			rfcomm_dlc_accept(d);
+	}
+}
+
 static int rfcomm_recv_sabm(struct rfcomm_session *s, u8 dlci)
 static int rfcomm_recv_sabm(struct rfcomm_session *s, u8 dlci)
 {
 {
 	struct rfcomm_dlc *d;
 	struct rfcomm_dlc *d;
@@ -1203,11 +1232,7 @@ static int rfcomm_recv_sabm(struct rfcomm_session *s, u8 dlci)
 	if (d) {
 	if (d) {
 		if (d->state == BT_OPEN) {
 		if (d->state == BT_OPEN) {
 			/* DLC was previously opened by PN request */
 			/* DLC was previously opened by PN request */
-			if (rfcomm_check_link_mode(d)) {
-				set_bit(RFCOMM_AUTH_PENDING, &d->flags);
-				rfcomm_dlc_set_timer(d, RFCOMM_AUTH_TIMEOUT);
-			} else
-				rfcomm_dlc_accept(d);
+			rfcomm_check_accept(d);
 		}
 		}
 		return 0;
 		return 0;
 	}
 	}
@@ -1219,11 +1244,7 @@ static int rfcomm_recv_sabm(struct rfcomm_session *s, u8 dlci)
 		d->addr = __addr(s->initiator, dlci);
 		d->addr = __addr(s->initiator, dlci);
 		rfcomm_dlc_link(s, d);
 		rfcomm_dlc_link(s, d);
 
 
-		if (rfcomm_check_link_mode(d)) {
-			set_bit(RFCOMM_AUTH_PENDING, &d->flags);
-			rfcomm_dlc_set_timer(d, RFCOMM_AUTH_TIMEOUT);
-		} else
-			rfcomm_dlc_accept(d);
+		rfcomm_check_accept(d);
 	} else {
 	} else {
 		rfcomm_send_dm(s, dlci);
 		rfcomm_send_dm(s, dlci);
 	}
 	}
@@ -1717,8 +1738,13 @@ static inline void rfcomm_process_dlcs(struct rfcomm_session *s)
 			if (d->out) {
 			if (d->out) {
 				rfcomm_send_pn(s, 1, d);
 				rfcomm_send_pn(s, 1, d);
 				rfcomm_dlc_set_timer(d, RFCOMM_CONN_TIMEOUT);
 				rfcomm_dlc_set_timer(d, RFCOMM_CONN_TIMEOUT);
-			} else
-				rfcomm_dlc_accept(d);
+			} else {
+				if (d->defer_setup) {
+					set_bit(RFCOMM_DEFER_SETUP, &d->flags);
+					rfcomm_dlc_set_timer(d, RFCOMM_AUTH_TIMEOUT);
+				} else
+					rfcomm_dlc_accept(d);
+			}
 			if (d->link_mode & RFCOMM_LM_SECURE) {
 			if (d->link_mode & RFCOMM_LM_SECURE) {
 				struct sock *sk = s->sock->sk;
 				struct sock *sk = s->sock->sk;
 				hci_conn_change_link_key(l2cap_pi(sk)->conn->hcon);
 				hci_conn_change_link_key(l2cap_pi(sk)->conn->hcon);

+ 43 - 1
net/bluetooth/rfcomm/sock.c

@@ -262,8 +262,10 @@ static void rfcomm_sock_init(struct sock *sk, struct sock *parent)
 	if (parent) {
 	if (parent) {
 		sk->sk_type = parent->sk_type;
 		sk->sk_type = parent->sk_type;
 		pi->link_mode = rfcomm_pi(parent)->link_mode;
 		pi->link_mode = rfcomm_pi(parent)->link_mode;
+		pi->dlc->defer_setup = bt_sk(parent)->defer_setup;
 	} else {
 	} else {
 		pi->link_mode = 0;
 		pi->link_mode = 0;
+		pi->dlc->defer_setup = 0;
 	}
 	}
 
 
 	pi->dlc->link_mode = pi->link_mode;
 	pi->dlc->link_mode = pi->link_mode;
@@ -554,6 +556,9 @@ static int rfcomm_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
 	struct sk_buff *skb;
 	struct sk_buff *skb;
 	int sent = 0;
 	int sent = 0;
 
 
+	if (test_bit(RFCOMM_DEFER_SETUP, &d->flags))
+		return -ENOTCONN;
+
 	if (msg->msg_flags & MSG_OOB)
 	if (msg->msg_flags & MSG_OOB)
 		return -EOPNOTSUPP;
 		return -EOPNOTSUPP;
 
 
@@ -633,10 +638,16 @@ static int rfcomm_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
 			       struct msghdr *msg, size_t size, int flags)
 			       struct msghdr *msg, size_t size, int flags)
 {
 {
 	struct sock *sk = sock->sk;
 	struct sock *sk = sock->sk;
+	struct rfcomm_dlc *d = rfcomm_pi(sk)->dlc;
 	int err = 0;
 	int err = 0;
 	size_t target, copied = 0;
 	size_t target, copied = 0;
 	long timeo;
 	long timeo;
 
 
+	if (test_and_clear_bit(RFCOMM_DEFER_SETUP, &d->flags)) {
+		rfcomm_dlc_accept(d);
+		return 0;
+	}
+
 	if (flags & MSG_OOB)
 	if (flags & MSG_OOB)
 		return -EOPNOTSUPP;
 		return -EOPNOTSUPP;
 
 
@@ -746,6 +757,7 @@ static int rfcomm_sock_setsockopt(struct socket *sock, int level, int optname, c
 {
 {
 	struct sock *sk = sock->sk;
 	struct sock *sk = sock->sk;
 	int err = 0;
 	int err = 0;
+	u32 opt;
 
 
 	BT_DBG("sk %p", sk);
 	BT_DBG("sk %p", sk);
 
 
@@ -755,6 +767,20 @@ static int rfcomm_sock_setsockopt(struct socket *sock, int level, int optname, c
 	lock_sock(sk);
 	lock_sock(sk);
 
 
 	switch (optname) {
 	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:
 	default:
 		err = -ENOPROTOOPT;
 		err = -ENOPROTOOPT;
 		break;
 		break;
@@ -785,7 +811,8 @@ static int rfcomm_sock_getsockopt_old(struct socket *sock, int optname, char __u
 		break;
 		break;
 
 
 	case RFCOMM_CONNINFO:
 	case RFCOMM_CONNINFO:
-		if (sk->sk_state != BT_CONNECTED) {
+		if (sk->sk_state != BT_CONNECTED &&
+					!rfcomm_pi(sk)->dlc->defer_setup) {
 			err = -ENOTCONN;
 			err = -ENOTCONN;
 			break;
 			break;
 		}
 		}
@@ -826,6 +853,17 @@ static int rfcomm_sock_getsockopt(struct socket *sock, int level, int optname, c
 	lock_sock(sk);
 	lock_sock(sk);
 
 
 	switch (optname) {
 	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:
 	default:
 		err = -ENOPROTOOPT;
 		err = -ENOPROTOOPT;
 		break;
 		break;
@@ -938,6 +976,10 @@ int rfcomm_connect_ind(struct rfcomm_session *s, u8 channel, struct rfcomm_dlc *
 
 
 done:
 done:
 	bh_unlock_sock(parent);
 	bh_unlock_sock(parent);
+
+	if (bt_sk(parent)->defer_setup)
+		parent->sk_state_change(parent);
+
 	return result;
 	return result;
 }
 }