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 <bgix@codeaurora.org>
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 6f38d97..51d7fa8 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -337,6 +337,8 @@
 	__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 64c4f16..04f01b7 100644
--- a/include/net/bluetooth/l2cap.h
+++ b/include/net/bluetooth/l2cap.h
@@ -452,8 +452,6 @@
 
 	__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 15a15a0..71845dd 100644
--- a/include/net/bluetooth/smp.h
+++ b/include/net/bluetooth/smp.h
@@ -126,5 +126,6 @@
 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 bbb637d..17a6f12 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -1724,6 +1724,9 @@
 	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 2149ebe..76b0185 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -1058,13 +1058,6 @@
 	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 @@
 	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 @@
 			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 8943510..aea2447 100644
--- a/net/bluetooth/smp.c
+++ b/net/bluetooth/smp.c
@@ -437,6 +437,7 @@
 		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 @@
 
 	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 @@
 		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 @@
 
 	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 @@
 		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 @@
 	case SMP_CMD_PAIRING_FAIL:
 		reason = 0;
 		err = -EPERM;
+		del_timer(&hcon->smp_timer);
 		hci_conn_put(hcon);
 		break;
 
@@ -893,6 +892,7 @@
 		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 @@
 	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 @@
 
 	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);
+}