Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit bb23c0ab authored by Marcel Holtmann's avatar Marcel Holtmann
Browse files

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: default avatarMarcel Holtmann <marcel@holtmann.org>
parent c4f912e1
Loading
Loading
Loading
Loading
+4 −2
Original line number Original line Diff line number Diff line
@@ -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;
@@ -206,6 +207,7 @@ struct rfcomm_dlc {
#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
Original line number Original line Diff line number Diff line
@@ -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)) {
			rfcomm_check_accept(d);
				set_bit(RFCOMM_AUTH_PENDING, &d->flags);
				rfcomm_dlc_set_timer(d, RFCOMM_AUTH_TIMEOUT);
			} else
				rfcomm_dlc_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)) {
		rfcomm_check_accept(d);
			set_bit(RFCOMM_AUTH_PENDING, &d->flags);
			rfcomm_dlc_set_timer(d, RFCOMM_AUTH_TIMEOUT);
		} else
			rfcomm_dlc_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 {
				if (d->defer_setup) {
					set_bit(RFCOMM_DEFER_SETUP, &d->flags);
					rfcomm_dlc_set_timer(d, RFCOMM_AUTH_TIMEOUT);
				} else
				} else
					rfcomm_dlc_accept(d);
					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
Original line number Original line Diff line number Diff line
@@ -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;
}
}