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

Commit f1cb9af5 authored by Vinicius Costa Gomes's avatar Vinicius Costa Gomes Committed by Gustavo Padovan
Browse files

Bluetooth: Add support for resuming socket when SMP is finished



This adds support for resuming the user space traffic when SMP
negotiation is complete.

Signed-off-by: default avatarVinicius Costa Gomes <vinicius.gomes@openbossa.org>
Signed-off-by: default avatarGustavo F. Padovan <padovan@profusion.mobi>
parent 9b3d6740
Loading
Loading
Loading
Loading
+31 −30
Original line number Diff line number Diff line
@@ -890,6 +890,23 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn)
	bh_unlock_sock(parent);
}

static void l2cap_chan_ready(struct sock *sk)
{
	struct l2cap_chan *chan = l2cap_pi(sk)->chan;
	struct sock *parent = bt_sk(sk)->parent;

	BT_DBG("sk %p, parent %p", sk, parent);

	chan->conf_state = 0;
	__clear_chan_timer(chan);

	sk->sk_state = BT_CONNECTED;
	sk->sk_state_change(sk);

	if (parent)
		parent->sk_data_ready(parent, 0);
}

static void l2cap_conn_ready(struct l2cap_conn *conn)
{
	struct l2cap_chan *chan;
@@ -906,13 +923,9 @@ static void l2cap_conn_ready(struct l2cap_conn *conn)

		bh_lock_sock(sk);

		if (conn->hcon->type == LE_LINK) {
			__clear_chan_timer(chan);
			l2cap_state_change(chan, BT_CONNECTED);
			sk->sk_state_change(sk);
		if (conn->hcon->type == LE_LINK)
			if (smp_conn_security(conn, chan->sec_level))
				BT_DBG("Insufficient security");
		}
				l2cap_chan_ready(sk);

		if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
			__clear_chan_timer(chan);
@@ -1675,30 +1688,6 @@ int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len)
	return err;
}

static void l2cap_chan_ready(struct sock *sk)
{
	struct sock *parent = bt_sk(sk)->parent;
	struct l2cap_chan *chan = l2cap_pi(sk)->chan;

	BT_DBG("sk %p, parent %p", sk, parent);

	chan->conf_state = 0;
	__clear_chan_timer(chan);

	if (!parent) {
		/* Outgoing channel.
		 * Wake up socket sleeping on connect.
		 */
		l2cap_state_change(chan, BT_CONNECTED);
		sk->sk_state_change(sk);
	} else {
		/* Incoming channel.
		 * Wake up socket sleeping on accept.
		 */
		parent->sk_data_ready(parent, 0);
	}
}

/* Copy frame to all raw sockets on that connection */
static void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb)
{
@@ -4188,6 +4177,18 @@ static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)

		bh_lock_sock(sk);

		BT_DBG("chan->scid %d", chan->scid);

		if (chan->scid == L2CAP_CID_LE_DATA) {
			if (!status && encrypt) {
				chan->sec_level = hcon->sec_level;
				l2cap_chan_ready(sk);
			}

			bh_unlock_sock(sk);
			continue;
		}

		if (chan->conf_state & L2CAP_CONF_CONNECT_PEND) {
			bh_unlock_sock(sk);
			continue;
+16 −0
Original line number Diff line number Diff line
@@ -29,6 +29,7 @@
#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h>
#include <net/bluetooth/l2cap.h>
#include <net/bluetooth/smp.h>

static const struct proto_ops l2cap_sock_ops;
static void l2cap_sock_init(struct sock *sk, struct sock *parent);
@@ -562,6 +563,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch
	struct l2cap_chan *chan = l2cap_pi(sk)->chan;
	struct bt_security sec;
	struct bt_power pwr;
	struct l2cap_conn *conn;
	int len, err = 0;
	u32 opt;

@@ -598,6 +600,20 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch
		}

		chan->sec_level = sec.level;

		conn = chan->conn;
		if (conn && chan->scid == L2CAP_CID_LE_DATA) {
			if (!conn->hcon->out) {
				err = -EINVAL;
				break;
			}

			if (smp_conn_security(conn, sec.level))
				break;

			err = 0;
			sk->sk_state = BT_CONFIG;
		}
		break;

	case BT_DEFER_SETUP:
+28 −12
Original line number Diff line number Diff line
@@ -336,9 +336,13 @@ static void smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb)
{
	struct smp_cmd_security_req *rp = (void *) skb->data;
	struct smp_cmd_pairing cp;
	struct hci_conn *hcon = conn->hcon;

	BT_DBG("conn %p", conn);

	if (test_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend))
		return;

	skb_pull(skb, sizeof(*rp));
	memset(&cp, 0, sizeof(cp));

@@ -353,6 +357,20 @@ static void smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb)
	memcpy(&conn->preq[1], &cp, sizeof(cp));

	smp_send_cmd(conn, SMP_CMD_PAIRING_REQ, sizeof(cp), &cp);

	set_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend);
}

static __u8 seclevel_to_authreq(__u8 level)
{
	switch (level) {
	case BT_SECURITY_HIGH:
		/* For now we don't support bonding */
		return SMP_AUTH_MITM;

	default:
		return SMP_AUTH_NONE;
	}
}

int smp_conn_security(struct l2cap_conn *conn, __u8 sec_level)
@@ -365,21 +383,16 @@ int smp_conn_security(struct l2cap_conn *conn, __u8 sec_level)
	if (IS_ERR(hcon->hdev->tfm))
		return 1;

	switch (sec_level) {
	case BT_SECURITY_MEDIUM:
		/* Encrypted, no MITM protection */
		authreq = HCI_AT_NO_BONDING_MITM;
		break;
	if (test_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend))
		return 0;

	case BT_SECURITY_HIGH:
		/* Bonding, MITM protection */
		authreq = HCI_AT_GENERAL_BONDING_MITM;
		break;
	if (sec_level == BT_SECURITY_LOW)
		return 1;

	case BT_SECURITY_LOW:
	default:
	if (hcon->sec_level >= sec_level)
		return 1;
	}

	authreq = seclevel_to_authreq(sec_level);

	if (hcon->link_mode & HCI_LM_MASTER) {
		struct smp_cmd_pairing cp;
@@ -400,6 +413,9 @@ int smp_conn_security(struct l2cap_conn *conn, __u8 sec_level)
		smp_send_cmd(conn, SMP_CMD_SECURITY_REQ, sizeof(cp), &cp);
	}

	hcon->pending_sec_level = sec_level;
	set_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend);

	return 0;
}