diff options
| author | Vinicius Costa Gomes <vinicius.gomes@openbossa.org> | 2011-01-26 19:42:57 -0500 |
|---|---|---|
| committer | Gustavo F. Padovan <padovan@profusion.mobi> | 2011-06-13 15:05:34 -0400 |
| commit | f1cb9af557dd8fb5d98fbcc4b5d3eb9d6d235af7 (patch) | |
| tree | e2701e2cecfbf5cea1a079a7a87f8bfe020b7598 | |
| parent | 9b3d67405b17d61ba8be9d824222fb410f487b8a (diff) | |
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>
| -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 865716504396..584a4237eb3f 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c | |||
| @@ -890,6 +890,23 @@ clean: | |||
| 890 | bh_unlock_sock(parent); | 890 | bh_unlock_sock(parent); |
| 891 | } | 891 | } |
| 892 | 892 | ||
| 893 | static void l2cap_chan_ready(struct sock *sk) | ||
| 894 | { | ||
| 895 | struct l2cap_chan *chan = l2cap_pi(sk)->chan; | ||
| 896 | struct sock *parent = bt_sk(sk)->parent; | ||
| 897 | |||
| 898 | BT_DBG("sk %p, parent %p", sk, parent); | ||
| 899 | |||
| 900 | chan->conf_state = 0; | ||
| 901 | __clear_chan_timer(chan); | ||
| 902 | |||
| 903 | sk->sk_state = BT_CONNECTED; | ||
| 904 | sk->sk_state_change(sk); | ||
| 905 | |||
| 906 | if (parent) | ||
| 907 | parent->sk_data_ready(parent, 0); | ||
| 908 | } | ||
| 909 | |||
| 893 | static void l2cap_conn_ready(struct l2cap_conn *conn) | 910 | static void l2cap_conn_ready(struct l2cap_conn *conn) |
| 894 | { | 911 | { |
| 895 | struct l2cap_chan *chan; | 912 | struct l2cap_chan *chan; |
| @@ -906,13 +923,9 @@ static void l2cap_conn_ready(struct l2cap_conn *conn) | |||
| 906 | 923 | ||
| 907 | bh_lock_sock(sk); | 924 | bh_lock_sock(sk); |
| 908 | 925 | ||
| 909 | if (conn->hcon->type == LE_LINK) { | 926 | if (conn->hcon->type == LE_LINK) |
| 910 | __clear_chan_timer(chan); | ||
| 911 | l2cap_state_change(chan, BT_CONNECTED); | ||
| 912 | sk->sk_state_change(sk); | ||
| 913 | if (smp_conn_security(conn, chan->sec_level)) | 927 | if (smp_conn_security(conn, chan->sec_level)) |
| 914 | BT_DBG("Insufficient security"); | 928 | l2cap_chan_ready(sk); |
| 915 | } | ||
| 916 | 929 | ||
| 917 | if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) { | 930 | if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) { |
| 918 | __clear_chan_timer(chan); | 931 | __clear_chan_timer(chan); |
| @@ -1675,30 +1688,6 @@ int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len) | |||
| 1675 | return err; | 1688 | return err; |
| 1676 | } | 1689 | } |
| 1677 | 1690 | ||
| 1678 | static void l2cap_chan_ready(struct sock *sk) | ||
| 1679 | { | ||
| 1680 | struct sock *parent = bt_sk(sk)->parent; | ||
| 1681 | struct l2cap_chan *chan = l2cap_pi(sk)->chan; | ||
| 1682 | |||
| 1683 | BT_DBG("sk %p, parent %p", sk, parent); | ||
| 1684 | |||
| 1685 | chan->conf_state = 0; | ||
| 1686 | __clear_chan_timer(chan); | ||
| 1687 | |||
| 1688 | if (!parent) { | ||
| 1689 | /* Outgoing channel. | ||
| 1690 | * Wake up socket sleeping on connect. | ||
| 1691 | */ | ||
| 1692 | l2cap_state_change(chan, BT_CONNECTED); | ||
| 1693 | sk->sk_state_change(sk); | ||
| 1694 | } else { | ||
| 1695 | /* Incoming channel. | ||
| 1696 | * Wake up socket sleeping on accept. | ||
| 1697 | */ | ||
| 1698 | parent->sk_data_ready(parent, 0); | ||
| 1699 | } | ||
| 1700 | } | ||
| 1701 | |||
| 1702 | /* Copy frame to all raw sockets on that connection */ | 1691 | /* Copy frame to all raw sockets on that connection */ |
| 1703 | static void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb) | 1692 | static void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb) |
| 1704 | { | 1693 | { |
| @@ -4188,6 +4177,18 @@ static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) | |||
| 4188 | 4177 | ||
| 4189 | bh_lock_sock(sk); | 4178 | bh_lock_sock(sk); |
| 4190 | 4179 | ||
| 4180 | BT_DBG("chan->scid %d", chan->scid); | ||
| 4181 | |||
| 4182 | if (chan->scid == L2CAP_CID_LE_DATA) { | ||
| 4183 | if (!status && encrypt) { | ||
| 4184 | chan->sec_level = hcon->sec_level; | ||
| 4185 | l2cap_chan_ready(sk); | ||
| 4186 | } | ||
| 4187 | |||
| 4188 | bh_unlock_sock(sk); | ||
| 4189 | continue; | ||
| 4190 | } | ||
| 4191 | |||
| 4191 | if (chan->conf_state & L2CAP_CONF_CONNECT_PEND) { | 4192 | if (chan->conf_state & L2CAP_CONF_CONNECT_PEND) { |
| 4192 | bh_unlock_sock(sk); | 4193 | bh_unlock_sock(sk); |
| 4193 | continue; | 4194 | continue; |
diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index 1d9c36509d7b..5c819e002fb1 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c | |||
| @@ -29,6 +29,7 @@ | |||
| 29 | #include <net/bluetooth/bluetooth.h> | 29 | #include <net/bluetooth/bluetooth.h> |
| 30 | #include <net/bluetooth/hci_core.h> | 30 | #include <net/bluetooth/hci_core.h> |
| 31 | #include <net/bluetooth/l2cap.h> | 31 | #include <net/bluetooth/l2cap.h> |
| 32 | #include <net/bluetooth/smp.h> | ||
| 32 | 33 | ||
| 33 | static const struct proto_ops l2cap_sock_ops; | 34 | static const struct proto_ops l2cap_sock_ops; |
| 34 | static void l2cap_sock_init(struct sock *sk, struct sock *parent); | 35 | 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 | |||
| 562 | struct l2cap_chan *chan = l2cap_pi(sk)->chan; | 563 | struct l2cap_chan *chan = l2cap_pi(sk)->chan; |
| 563 | struct bt_security sec; | 564 | struct bt_security sec; |
| 564 | struct bt_power pwr; | 565 | struct bt_power pwr; |
| 566 | struct l2cap_conn *conn; | ||
| 565 | int len, err = 0; | 567 | int len, err = 0; |
| 566 | u32 opt; | 568 | u32 opt; |
| 567 | 569 | ||
| @@ -598,6 +600,20 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch | |||
| 598 | } | 600 | } |
| 599 | 601 | ||
| 600 | chan->sec_level = sec.level; | 602 | chan->sec_level = sec.level; |
| 603 | |||
| 604 | conn = chan->conn; | ||
| 605 | if (conn && chan->scid == L2CAP_CID_LE_DATA) { | ||
| 606 | if (!conn->hcon->out) { | ||
| 607 | err = -EINVAL; | ||
| 608 | break; | ||
| 609 | } | ||
| 610 | |||
| 611 | if (smp_conn_security(conn, sec.level)) | ||
| 612 | break; | ||
| 613 | |||
| 614 | err = 0; | ||
| 615 | sk->sk_state = BT_CONFIG; | ||
| 616 | } | ||
| 601 | break; | 617 | break; |
| 602 | 618 | ||
| 603 | case BT_DEFER_SETUP: | 619 | case BT_DEFER_SETUP: |
diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 69839797b7dc..da46d76fc13d 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) | |||
| 336 | { | 336 | { |
| 337 | struct smp_cmd_security_req *rp = (void *) skb->data; | 337 | struct smp_cmd_security_req *rp = (void *) skb->data; |
| 338 | struct smp_cmd_pairing cp; | 338 | struct smp_cmd_pairing cp; |
| 339 | struct hci_conn *hcon = conn->hcon; | ||
| 339 | 340 | ||
| 340 | BT_DBG("conn %p", conn); | 341 | BT_DBG("conn %p", conn); |
| 341 | 342 | ||
| 343 | if (test_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend)) | ||
| 344 | return; | ||
| 345 | |||
| 342 | skb_pull(skb, sizeof(*rp)); | 346 | skb_pull(skb, sizeof(*rp)); |
| 343 | memset(&cp, 0, sizeof(cp)); | 347 | memset(&cp, 0, sizeof(cp)); |
| 344 | 348 | ||
| @@ -353,6 +357,20 @@ static void smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb) | |||
| 353 | memcpy(&conn->preq[1], &cp, sizeof(cp)); | 357 | memcpy(&conn->preq[1], &cp, sizeof(cp)); |
| 354 | 358 | ||
| 355 | smp_send_cmd(conn, SMP_CMD_PAIRING_REQ, sizeof(cp), &cp); | 359 | smp_send_cmd(conn, SMP_CMD_PAIRING_REQ, sizeof(cp), &cp); |
| 360 | |||
| 361 | set_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend); | ||
| 362 | } | ||
| 363 | |||
| 364 | static __u8 seclevel_to_authreq(__u8 level) | ||
| 365 | { | ||
| 366 | switch (level) { | ||
| 367 | case BT_SECURITY_HIGH: | ||
| 368 | /* For now we don't support bonding */ | ||
| 369 | return SMP_AUTH_MITM; | ||
| 370 | |||
| 371 | default: | ||
| 372 | return SMP_AUTH_NONE; | ||
| 373 | } | ||
| 356 | } | 374 | } |
| 357 | 375 | ||
| 358 | int smp_conn_security(struct l2cap_conn *conn, __u8 sec_level) | 376 | 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) | |||
| 365 | if (IS_ERR(hcon->hdev->tfm)) | 383 | if (IS_ERR(hcon->hdev->tfm)) |
| 366 | return 1; | 384 | return 1; |
| 367 | |||
