Bluetooth: Add LE/BR flag to Connect notification

When remote device is connected outside the control of BlueZ, it
needs to be informed of whether the new connection is LE or BR/EDR.

Signed-off-by: Brian Gix <bgix@codeaurora.org>
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index 7ee9ff0..079538b 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -630,8 +630,10 @@
 		struct adv_entry *entry;
 
 		le = hci_conn_hash_lookup_ba(hdev, LE_LINK, dst);
-		if (le)
+		if (le) {
+			hci_conn_hold(le);
 			return le;
+		}
 
 		entry = hci_find_adv_entry(hdev, dst);
 		if (!entry)
@@ -783,11 +785,19 @@
 				(!conn->ssp_mode || !conn->hdev->ssp_mode))
 		return 1;
 
-	if (conn->link_mode & HCI_LM_ENCRYPT)
-		return hci_conn_auth(conn, sec_level, auth_type);
+	if (conn->type == LE_LINK) {
+		if (conn->pending_sec_level > sec_level)
+			sec_level = conn->pending_sec_level;
 
-	if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend))
+		if (sec_level > conn->sec_level)
+			conn->pending_sec_level = sec_level;
+		hci_proto_connect_cfm(conn, 0);
 		return 0;
+	} else if (conn->link_mode & HCI_LM_ENCRYPT) {
+		return hci_conn_auth(conn, sec_level, auth_type);
+	} else if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend)) {
+		return 0;
+	}
 
 	if (hci_conn_auth(conn, sec_level, auth_type)) {
 		struct hci_cp_set_conn_encrypt cp;
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 2891209..1e59cb3 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -1572,11 +1572,11 @@
 			conn->state = BT_CONFIG;
 			hci_conn_hold(conn);
 			conn->disc_timeout = HCI_DISCONN_TIMEOUT;
-			mgmt_connected(hdev->id, &ev->bdaddr);
+			mgmt_connected(hdev->id, &ev->bdaddr, 0);
 		} else if (conn->type == LE_LINK) {
 			conn->state = BT_CONNECTED;
 			conn->disc_timeout = HCI_DISCONN_TIMEOUT;
-			mgmt_connected(hdev->id, &ev->bdaddr);
+			mgmt_connected(hdev->id, &ev->bdaddr, 1);
 		} else
 			conn->state = BT_CONNECTED;
 
@@ -3030,7 +3030,7 @@
 	conn->handle = __le16_to_cpu(ev->handle);
 	conn->state = BT_CONNECTED;
 	conn->disc_timeout = HCI_DISCONN_TIMEOUT;
-	mgmt_connected(hdev->id, &ev->bdaddr);
+	mgmt_connected(hdev->id, &ev->bdaddr, 1);
 
 	hci_conn_hold(conn);
 	hci_conn_hold_device(conn);
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index ea81593..3bb58f9 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -1004,8 +1004,13 @@
 			bh_lock_sock(sk);
 
 			if (conn->hcon->type == LE_LINK) {
-				if (smp_conn_security(conn,
-						l2cap_pi(sk)->sec_level))
+				u8 sec_level = l2cap_pi(sk)->sec_level;
+				u8 pending_sec = conn->hcon->pending_sec_level;
+
+				if (pending_sec > sec_level)
+					sec_level = pending_sec;
+
+				if (smp_conn_security(conn, sec_level))
 					l2cap_chan_ready(sk);
 
 			} else if (sk->sk_type != SOCK_SEQPACKET &&
@@ -1212,15 +1217,12 @@
 
 		conn = hcon->l2cap_data;
 	} else {
-		if (l2cap_pi(sk)->dcid == L2CAP_CID_LE_DATA) {
+		if (l2cap_pi(sk)->dcid == L2CAP_CID_LE_DATA)
 			hcon = hci_connect(hdev, LE_LINK, 0, dst,
 					l2cap_pi(sk)->sec_level, auth_type);
-			if (hcon->state == BT_CONNECTED)
-				hci_conn_hold(hcon);
-		} else {
+		else
 			hcon = hci_connect(hdev, ACL_LINK, 0, dst,
 					l2cap_pi(sk)->sec_level, auth_type);
-		}
 
 		if (IS_ERR(hcon)) {
 			err = PTR_ERR(hcon);
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 4343184..79e0891 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -2286,11 +2286,12 @@
 	return err;
 }
 
-int mgmt_connected(u16 index, bdaddr_t *bdaddr)
+int mgmt_connected(u16 index, bdaddr_t *bdaddr, u8 le)
 {
 	struct mgmt_ev_connected ev;
 
 	bacpy(&ev.bdaddr, bdaddr);
+	ev.le = le;
 
 	return mgmt_event(MGMT_EV_CONNECTED, index, &ev, sizeof(ev), NULL);
 }