Skip to content

Commit

Permalink
Bluetooth: Add support for resuming socket when SMP is finished
Browse files Browse the repository at this point in the history
This adds support for resuming the user space traffic when SMP
negotiation is complete.

Signed-off-by: Vinicius Costa Gomes <vinicius.gomes@openbossa.org>
Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi>
  • Loading branch information
Vinicius Costa Gomes authored and Gustavo F. Padovan committed Jun 13, 2011
1 parent 9b3d674 commit f1cb9af
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 42 deletions.
61 changes: 31 additions & 30 deletions net/bluetooth/l2cap_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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);
Expand Down Expand Up @@ -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)
{
Expand Down Expand Up @@ -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;
Expand Down
16 changes: 16 additions & 0 deletions net/bluetooth/l2cap_sock.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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:
Expand Down
40 changes: 28 additions & 12 deletions net/bluetooth/smp.c
Original file line number Diff line number Diff line change
Expand Up @@ -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));

Expand All @@ -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)
Expand All @@ -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;
Expand All @@ -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;
}

Expand Down

0 comments on commit f1cb9af

Please sign in to comment.