diff options
author | Vinicius Costa Gomes <vinicius.gomes@openbossa.org> | 2011-01-27 00:42:57 (GMT) |
---|---|---|
committer | Gustavo F. Padovan <padovan@profusion.mobi> | 2011-06-13 19:05:34 (GMT) |
commit | f1cb9af557dd8fb5d98fbcc4b5d3eb9d6d235af7 (patch) | |
tree | e2701e2cecfbf5cea1a079a7a87f8bfe020b7598 /net | |
parent | 9b3d67405b17d61ba8be9d824222fb410f487b8a (diff) | |
download | linux-f1cb9af557dd8fb5d98fbcc4b5d3eb9d6d235af7.tar.xz |
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: Vinicius Costa Gomes <vinicius.gomes@openbossa.org>
Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi>
Diffstat (limited to 'net')
-rw-r--r-- | net/bluetooth/l2cap_core.c | 61 | ||||
-rw-r--r-- | net/bluetooth/l2cap_sock.c | 16 | ||||
-rw-r--r-- | net/bluetooth/smp.c | 40 |
3 files changed, 75 insertions, 42 deletions
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 8657165..584a423 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -890,6 +890,23 @@ clean: 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; diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index 1d9c365..5c819e0 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -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: diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 6983979..da46d76 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -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; } |