From e9ceb522ff08c3634da2efaaf6bc045136ca29ad Mon Sep 17 00:00:00 2001 From: Brian Gix Date: Thu, 22 Sep 2011 10:46:35 -0700 Subject: [PATCH] Bluetooth: Fix LE Pairing time-out Timer that was started at beginning of LE Pairing did not correctly terminate pairing process when it fired, and was not properly cleaned up on pairing completion. Signed-off-by: Brian Gix --- include/net/bluetooth/hci_core.h | 2 ++ include/net/bluetooth/l2cap.h | 2 -- include/net/bluetooth/smp.h | 1 + net/bluetooth/hci_event.c | 3 +++ net/bluetooth/l2cap_core.c | 11 ++--------- net/bluetooth/smp.c | 27 ++++++++++++++++++++------- 6 files changed, 28 insertions(+), 18 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 6f38d9775f9..51d7fa826af 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -337,6 +337,8 @@ struct hci_conn { __u8 sec_req; __u8 auth; void *smp_conn; + struct timer_list smp_timer; + void (*connect_cfm_cb) (struct hci_conn *conn, u8 status); void (*security_cfm_cb) (struct hci_conn *conn, u8 status); diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 64c4f167602..04f01b71fd8 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -452,8 +452,6 @@ struct l2cap_conn { __u8 disc_reason; - struct timer_list security_timer; - struct l2cap_chan_list chan_list; }; diff --git a/include/net/bluetooth/smp.h b/include/net/bluetooth/smp.h index 15a15a0bc95..71845ddc167 100644 --- a/include/net/bluetooth/smp.h +++ b/include/net/bluetooth/smp.h @@ -126,5 +126,6 @@ struct smp_cmd_security_req { int smp_conn_security(struct l2cap_conn *conn, __u8 sec_level); int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb); int smp_link_encrypt_cmplt(struct l2cap_conn *conn, __u8 status, __u8 encrypt); +void smp_timeout(unsigned long l2cap_conn); #endif /* __SMP_H */ diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index bbb637d1373..17a6f12ef54 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1724,6 +1724,9 @@ static inline void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff if (conn->type == ACL_LINK || conn->type == LE_LINK) mgmt_disconnected(hdev->id, &conn->dst); + if (conn->type == LE_LINK) + del_timer(&conn->smp_timer); + hci_proto_disconn_cfm(conn, ev->reason); hci_conn_del(conn); diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 2149ebe50f4..76b01856951 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -1058,13 +1058,6 @@ static void l2cap_info_timeout(unsigned long arg) l2cap_conn_start(conn); } -static void security_timeout(unsigned long arg) -{ - struct l2cap_conn *conn = (void *) arg; - - l2cap_conn_del(conn->hcon, ETIMEDOUT); -} - static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status) { struct l2cap_conn *conn = hcon->l2cap_data; @@ -1095,7 +1088,7 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status) rwlock_init(&conn->chan_list.lock); if (hcon->type == LE_LINK) - setup_timer(&conn->security_timer, security_timeout, + setup_timer(&hcon->smp_timer, smp_timeout, (unsigned long) conn); else setup_timer(&conn->info_timer, l2cap_info_timeout, @@ -7263,7 +7256,7 @@ static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) if (!status && encrypt) l2cap_pi(sk)->sec_level = hcon->sec_level; - del_timer(&conn->security_timer); + del_timer(&hcon->smp_timer); l2cap_chan_ready(sk); smp_link_encrypt_cmplt(conn, status, encrypt); diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 8943510119a..aea2447f093 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -437,6 +437,7 @@ int le_user_confirm_reply(struct hci_conn *hcon, u16 mgmt_op, void *cp) BT_DBG("smp_send_cmd: SMP_CMD_PAIRING_FAIL"); smp_send_cmd(conn, SMP_CMD_PAIRING_FAIL, sizeof(reason), &reason); + del_timer(&hcon->smp_timer); hci_conn_put(hcon); } else if (hcon->cfm_pending) { BT_DBG("send_pairing_confirm"); @@ -490,8 +491,7 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb) smp_send_cmd(conn, SMP_CMD_PAIRING_RSP, sizeof(rsp), &rsp); - mod_timer(&conn->security_timer, jiffies + - msecs_to_jiffies(SMP_TIMEOUT)); + mod_timer(&hcon->smp_timer, jiffies + msecs_to_jiffies(SMP_TIMEOUT)); return 0; } @@ -569,8 +569,7 @@ static u8 smp_cmd_pairing_confirm(struct l2cap_conn *conn, struct sk_buff *skb) hcon->cfm_pending = TRUE; - mod_timer(&conn->security_timer, jiffies + - msecs_to_jiffies(SMP_TIMEOUT)); + mod_timer(&hcon->smp_timer, jiffies + msecs_to_jiffies(SMP_TIMEOUT)); return 0; } @@ -682,8 +681,7 @@ static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb) smp_send_cmd(conn, SMP_CMD_PAIRING_REQ, sizeof(cp), &cp); - mod_timer(&conn->security_timer, jiffies + - msecs_to_jiffies(SMP_TIMEOUT)); + mod_timer(&hcon->smp_timer, jiffies + msecs_to_jiffies(SMP_TIMEOUT)); set_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend); @@ -750,7 +748,7 @@ int smp_conn_security(struct l2cap_conn *conn, __u8 sec_level) hcon->preq[0] = SMP_CMD_PAIRING_REQ; memcpy(&hcon->preq[1], &cp, sizeof(cp)); - mod_timer(&conn->security_timer, jiffies + + mod_timer(&hcon->smp_timer, jiffies + msecs_to_jiffies(SMP_TIMEOUT)); smp_send_cmd(conn, SMP_CMD_PAIRING_REQ, sizeof(cp), &cp); @@ -846,6 +844,7 @@ int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb) case SMP_CMD_PAIRING_FAIL: reason = 0; err = -EPERM; + del_timer(&hcon->smp_timer); hci_conn_put(hcon); break; @@ -893,6 +892,7 @@ done: BT_ERR("SMP_CMD_PAIRING_FAIL: %d", reason); smp_send_cmd(conn, SMP_CMD_PAIRING_FAIL, sizeof(reason), &reason); + del_timer(&hcon->smp_timer); hci_conn_put(hcon); } @@ -984,6 +984,8 @@ static int smp_distribute_keys(struct l2cap_conn *conn, __u8 force) if (hcon->out || rsp->resp_key_dist) { if (hcon->disconn_cfm_cb) hcon->disconn_cfm_cb(hcon, 0); + + del_timer(&hcon->smp_timer); hci_conn_put(hcon); } @@ -1005,3 +1007,14 @@ int smp_link_encrypt_cmplt(struct l2cap_conn *conn, u8 status, u8 encrypt) return 0; } + +void smp_timeout(unsigned long arg) +{ + struct l2cap_conn *conn = (void *) arg; + u8 reason = SMP_UNSPECIFIED; + + BT_DBG("%p", conn); + + smp_send_cmd(conn, SMP_CMD_PAIRING_FAIL, sizeof(reason), &reason); + hci_conn_put(conn->hcon); +}