Bluetooth: Add LE SecMgr and mgmtops support

Enabled ECB Block encoding for Low Energy pairing
Implemented missing components of MGMTOPS interface
Differentiated as needed between BR/EDR pairing and LE pairing

Signed-off-by: Brian Gix <bgix@codeaurora.org>

Conflicts:

	net/bluetooth/mgmt.c
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 6a17f4a..0c731f9 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -498,6 +498,8 @@
 	 * command otherwise */
 	u8 events[8] = { 0xff, 0xff, 0xfb, 0xff, 0x00, 0x00, 0x00, 0x00 };
 
+	BT_DBG("");
+
 	/* Events for 1.2 and newer controllers */
 	if (hdev->lmp_ver > 1) {
 		events[4] |= 0x01; /* Flow Specification Complete */
@@ -631,6 +633,23 @@
 
 	memcpy(hdev->features, rp->features, 8);
 
+	if (hdev->dev_type == HCI_BREDR && test_bit(HCI_INIT, &hdev->flags)) {
+		if (hdev->features[6] & LMP_SIMPLE_PAIR) {
+			u8 mode = 0x01;
+			hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE,
+					sizeof(mode), &mode);
+		}
+
+		if (hdev->features[3] & LMP_RSSI_INQ)
+			hci_setup_inquiry_mode(hdev);
+
+		if (hdev->features[7] & LMP_INQ_TX_PWR)
+			hci_send_cmd(hdev, HCI_OP_READ_INQ_RSP_TX_POWER,
+								0, NULL);
+
+		hci_setup_event_mask(hdev);
+	}
+
 	/* Adjust default settings according to features
 	 * supported by device. */
 
@@ -963,7 +982,6 @@
 	param_scan_enable = *((__u8 *) sent);
 	if (param_scan_enable == 0x01) {
 		del_timer(&hdev->adv_timer);
-		hci_adv_entries_clear(hdev);
 	} else if (param_scan_enable == 0x00) {
 		mod_timer(&hdev->adv_timer, jiffies + ADV_CLEAR_TIMEOUT);
 	}
@@ -977,8 +995,11 @@
 		hci_req_complete(hdev, HCI_OP_INQUIRY, status);
 
 		hci_conn_check_pending(hdev);
-	} else
+	} else {
 		set_bit(HCI_INQUIRY, &hdev->flags);
+		if (test_bit(HCI_MGMT, &hdev->flags))
+			mgmt_inquiry_started(hdev->id);
+	}
 }
 
 static inline void hci_cs_create_conn(struct hci_dev *hdev, __u8 status)
@@ -1481,11 +1502,16 @@
 
 	BT_DBG("%s status %d", hdev->name, status);
 
-	clear_bit(HCI_INQUIRY, &hdev->flags);
+	if (!lmp_le_capable(hdev))
+		clear_bit(HCI_INQUIRY, &hdev->flags);
 
 	hci_req_complete(hdev, HCI_OP_INQUIRY, status);
 
-	hci_conn_check_pending(hdev);
+	if (test_bit(HCI_MGMT, &hdev->flags))
+		mgmt_inquiry_complete_evt(hdev->id, status);
+
+	if (!lmp_le_capable(hdev))
+		hci_conn_check_pending(hdev);
 }
 
 static inline void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *skb)
@@ -1511,8 +1537,8 @@
 		data.rssi		= 0x00;
 		data.ssp_mode		= 0x00;
 		hci_inquiry_cache_update(hdev, &data);
-		mgmt_device_found(hdev->id, &info->bdaddr, info->dev_class, 0,
-									NULL);
+		mgmt_device_found(hdev->id, &info->bdaddr, 0, 0,
+					info->dev_class, 0, 0, NULL);
 	}
 
 	hci_dev_unlock(hdev);
@@ -1547,6 +1573,10 @@
 			hci_conn_hold(conn);
 			conn->disc_timeout = HCI_DISCONN_TIMEOUT;
 			mgmt_connected(hdev->id, &ev->bdaddr);
+		} else if (conn->type == LE_LINK) {
+			conn->state = BT_CONNECTED;
+			conn->disc_timeout = HCI_DISCONN_TIMEOUT;
+			mgmt_connected(hdev->id, &ev->bdaddr);
 		} else
 			conn->state = BT_CONNECTED;
 
@@ -1577,7 +1607,7 @@
 		}
 	} else {
 		conn->state = BT_CLOSED;
-		if (conn->type == ACL_LINK)
+		if (conn->type == ACL_LINK || conn->type == LE_LINK)
 			mgmt_connect_failed(hdev->id, &ev->bdaddr, ev->status);
 	}
 
@@ -1691,7 +1721,7 @@
 
 	conn->state = BT_CLOSED;
 
-	if (conn->type == ACL_LINK)
+	if (conn->type == ACL_LINK || conn->type == LE_LINK)
 		mgmt_disconnected(hdev->id, &conn->dst);
 
 	hci_proto_disconn_cfm(conn, ev->reason);
@@ -1782,8 +1812,8 @@
 
 	hci_dev_lock(hdev);
 
-	if (ev->status == 0 && test_bit(HCI_MGMT, &hdev->flags))
-		mgmt_remote_name(hdev->id, &ev->bdaddr, ev->name);
+	if (test_bit(HCI_MGMT, &hdev->flags))
+		mgmt_remote_name(hdev->id, &ev->bdaddr, ev->status, ev->name);
 
 	conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr);
 	if (conn && hci_outgoing_auth_needed(hdev, conn)) {
@@ -2604,9 +2634,9 @@
 			data.rssi		= info->rssi;
 			data.ssp_mode		= 0x00;
 			hci_inquiry_cache_update(hdev, &data);
-			mgmt_device_found(hdev->id, &info->bdaddr,
+			mgmt_device_found(hdev->id, &info->bdaddr, 0, 0,
 						info->dev_class, info->rssi,
-						NULL);
+						0, NULL);
 		}
 	} else {
 		struct inquiry_info_with_rssi *info = (void *) (skb->data + 1);
@@ -2621,9 +2651,9 @@
 			data.rssi		= info->rssi;
 			data.ssp_mode		= 0x00;
 			hci_inquiry_cache_update(hdev, &data);
-			mgmt_device_found(hdev->id, &info->bdaddr,
+			mgmt_device_found(hdev->id, &info->bdaddr, 0, 0,
 						info->dev_class, info->rssi,
-						NULL);
+						0, NULL);
 		}
 	}
 
@@ -2764,8 +2794,9 @@
 		data.rssi		= info->rssi;
 		data.ssp_mode		= 0x01;
 		hci_inquiry_cache_update(hdev, &data);
-		mgmt_device_found(hdev->id, &info->bdaddr, info->dev_class,
-						info->rssi, info->data);
+		mgmt_device_found(hdev->id, &info->bdaddr, 0, 0,
+				info->dev_class, info->rssi,
+				HCI_MAX_EIR_LENGTH, info->data);
 	}
 
 	hci_dev_unlock(hdev);
@@ -2773,18 +2804,22 @@
 
 static inline u8 hci_get_auth_req(struct hci_conn *conn)
 {
+	BT_DBG("%p", conn);
+
 	/* If remote requests dedicated bonding follow that lead */
 	if (conn->remote_auth == 0x02 || conn->remote_auth == 0x03) {
 		/* If both remote and local IO capabilities allow MITM
 		 * protection then require it, otherwise don't */
-		if (conn->remote_cap == 0x03 || conn->io_capability == 0x03)
+		if (conn->remote_cap == 0x03 || conn->io_capability == 0x03) {
 			return 0x02;
-		else
+		} else {
+			conn->auth_type |= 0x01;
 			return 0x03;
+		}
 	}
 
 	/* If remote requests no-bonding follow that lead */
-	if (conn->remote_auth == 0x00 || conn->remote_auth == 0x01)
+	if (conn->remote_auth <= 0x01)
 		return 0x00;
 
 	return conn->auth_type;
@@ -2811,10 +2846,15 @@
 	if (test_bit(HCI_PAIRABLE, &hdev->flags) ||
 			(conn->remote_auth & ~0x01) == HCI_AT_NO_BONDING) {
 		struct hci_cp_io_capability_reply cp;
+		u8 io_cap = conn->io_capability;
 
+		/* ACL-SSP does not support IO CAP 0x04 */
+		cp.capability = (io_cap == 0x04) ? 0x01 : io_cap;
 		bacpy(&cp.bdaddr, &ev->bdaddr);
-		cp.capability = conn->io_capability;
-		cp.authentication = hci_get_auth_req(conn);
+		if (conn->auth_initiator)
+			cp.authentication = conn->auth_type;
+		else
+			cp.authentication = hci_get_auth_req(conn);
 
 		if ((conn->out == 0x01 || conn->remote_oob == 0x01) &&
 				hci_find_remote_oob_data(hdev, &conn->dst))
@@ -2859,8 +2899,8 @@
 	hci_dev_unlock(hdev);
 }
 
-static inline void hci_user_confirm_request_evt(struct hci_dev *hdev,
-							struct sk_buff *skb)
+static inline void hci_user_ssp_confirmation_evt(struct hci_dev *hdev,
+						u8 event, struct sk_buff *skb)
 {
 	struct hci_ev_user_confirm_req *ev = (void *) skb->data;
 
@@ -2868,8 +2908,14 @@
 
 	hci_dev_lock(hdev);
 
-	if (test_bit(HCI_MGMT, &hdev->flags))
-		mgmt_user_confirm_request(hdev->id, &ev->bdaddr, ev->passkey);
+	if (test_bit(HCI_MGMT, &hdev->flags)) {
+		if (event == HCI_EV_USER_PASSKEY_REQUEST)
+			mgmt_user_confirm_request(hdev->id, event,
+							&ev->bdaddr, 0);
+		else
+			mgmt_user_confirm_request(hdev->id, event,
+						&ev->bdaddr, ev->passkey);
+	}
 
 	hci_dev_unlock(hdev);
 }
@@ -2981,6 +3027,7 @@
 	conn->sec_level = BT_SECURITY_LOW;
 	conn->handle = __le16_to_cpu(ev->handle);
 	conn->state = BT_CONNECTED;
+	conn->disc_timeout = HCI_DISCONN_TIMEOUT;
 
 	hci_conn_hold_device(conn);
 	hci_conn_add_sysfs(conn);
@@ -3036,11 +3083,12 @@
 
 	num_reports = skb->data[0];
 	ev = (void *) &skb->data[1];
-	hci_add_adv_entry(hdev, ev);
 
-	while (--num_reports) {
-		ev = (void *) (ev->data + ev->length + 1);
+	while (num_reports--) {
+		mgmt_device_found(hdev->id, &ev->bdaddr, ev->bdaddr_type,
+				1, NULL, 0, ev->length, ev->data);
 		hci_add_adv_entry(hdev, ev);
+		ev = (void *) (ev->data + ev->length + 1);
 	}
 }
 
@@ -3326,8 +3374,10 @@
 		hci_io_capa_reply_evt(hdev, skb);
 		break;
 
+	case HCI_EV_USER_PASSKEY_REQUEST:
+	case HCI_EV_USER_PASSKEY_NOTIFICATION:
 	case HCI_EV_USER_CONFIRM_REQUEST:
-		hci_user_confirm_request_evt(hdev, skb);
+		hci_user_ssp_confirmation_evt(hdev, event, skb);
 		break;
 
 	case HCI_EV_SIMPLE_PAIR_COMPLETE: