Initial Contribution

msm-2.6.38: tag AU_LINUX_ANDROID_GINGERBREAD.02.03.04.00.142

Signed-off-by: Bryan Huntsman <bryanh@codeaurora.org>
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 6cddd03..84e3975 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -1,6 +1,6 @@
 /*
    BlueZ - Bluetooth protocol stack for Linux
-   Copyright (c) 2000-2001, 2010, Code Aurora Forum. All rights reserved.
+   Copyright (c) 2000-2001, 2010-2011, Code Aurora Forum. All rights reserved.
 
    Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
 
@@ -45,8 +45,6 @@
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/hci_core.h>
 
-static int enable_le;
-
 /* Handle HCI Event packets */
 
 static void hci_cc_inquiry_cancel(struct hci_dev *hdev, struct sk_buff *skb)
@@ -58,9 +56,7 @@
 	if (status)
 		return;
 
-	if (test_bit(HCI_MGMT, &hdev->flags) &&
-				test_and_clear_bit(HCI_INQUIRY, &hdev->flags))
-		mgmt_discovering(hdev->id, 0);
+	clear_bit(HCI_INQUIRY, &hdev->flags);
 
 	hci_req_complete(hdev, HCI_OP_INQUIRY_CANCEL, status);
 
@@ -76,13 +72,36 @@
 	if (status)
 		return;
 
-	if (test_bit(HCI_MGMT, &hdev->flags) &&
-				test_and_clear_bit(HCI_INQUIRY, &hdev->flags))
-		mgmt_discovering(hdev->id, 0);
+	clear_bit(HCI_INQUIRY, &hdev->flags);
 
 	hci_conn_check_pending(hdev);
 }
 
+static void hci_cc_link_key_reply(struct hci_dev *hdev, struct sk_buff *skb)
+{
+	struct hci_rp_link_key_reply *rp = (void *) skb->data;
+	struct hci_conn *conn;
+	struct hci_cp_link_key_reply *cp;
+
+	BT_DBG("%s status 0x%x", hdev->name, rp->status);
+	if (rp->status)
+		return;
+
+	cp = hci_sent_cmd_data(hdev, HCI_OP_LINK_KEY_REPLY);
+	if (!cp)
+		return;
+
+	hci_dev_lock(hdev);
+	conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
+	if (conn) {
+		hci_conn_hold(conn);
+		memcpy(conn->link_key, cp->link_key, sizeof(conn->link_key));
+		conn->key_type = 5;
+		hci_conn_put(conn);
+	}
+	hci_dev_unlock(hdev);
+}
+
 static void hci_cc_remote_name_req_cancel(struct hci_dev *hdev, struct sk_buff *skb)
 {
 	BT_DBG("%s", hdev->name);
@@ -479,16 +498,14 @@
 	 * command otherwise */
 	u8 events[8] = { 0xff, 0xff, 0xfb, 0xff, 0x00, 0x00, 0x00, 0x00 };
 
-	/* CSR 1.1 dongles does not accept any bitfield so don't try to set
-	 * any event mask for pre 1.2 devices */
-	if (hdev->lmp_ver <= 1)
-		return;
-
-	events[4] |= 0x01; /* Flow Specification Complete */
-	events[4] |= 0x02; /* Inquiry Result with RSSI */
-	events[4] |= 0x04; /* Read Remote Extended Features Complete */
-	events[5] |= 0x08; /* Synchronous Connection Complete */
-	events[5] |= 0x10; /* Synchronous Connection Changed */
+	/* Events for 1.2 and newer controllers */
+	if (hdev->lmp_ver > 1) {
+		events[4] |= 0x01; /* Flow Specification Complete */
+		events[4] |= 0x02; /* Inquiry Result with RSSI */
+		events[4] |= 0x04; /* Read Remote Extended Features Complete */
+		events[5] |= 0x08; /* Synchronous Connection Complete */
+		events[5] |= 0x10; /* Synchronous Connection Changed */
+	}
 
 	if (hdev->features[3] & LMP_RSSI_INQ)
 		events[4] |= 0x04; /* Inquiry Result with RSSI */
@@ -527,20 +544,6 @@
 	hci_send_cmd(hdev, HCI_OP_SET_EVENT_MASK, sizeof(events), events);
 }
 
-static void hci_set_le_support(struct hci_dev *hdev)
-{
-	struct hci_cp_write_le_host_supported cp;
-
-	memset(&cp, 0, sizeof(cp));
-
-	if (enable_le) {
-		cp.le = 1;
-		cp.simul = !!(hdev->features[6] & LMP_SIMUL_LE_BR);
-	}
-
-	hci_send_cmd(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(cp), &cp);
-}
-
 static void hci_setup(struct hci_dev *hdev)
 {
 	hci_setup_event_mask(hdev);
@@ -558,17 +561,6 @@
 
 	if (hdev->features[7] & LMP_INQ_TX_PWR)
 		hci_send_cmd(hdev, HCI_OP_READ_INQ_RSP_TX_POWER, 0, NULL);
-
-	if (hdev->features[7] & LMP_EXTFEATURES) {
-		struct hci_cp_read_local_ext_features cp;
-
-		cp.page = 0x01;
-		hci_send_cmd(hdev, HCI_OP_READ_LOCAL_EXT_FEATURES,
-							sizeof(cp), &cp);
-	}
-
-	if (hdev->features[4] & LMP_LE)
-		hci_set_le_support(hdev);
 }
 
 static void hci_cc_read_local_version(struct hci_dev *hdev, struct sk_buff *skb)
@@ -590,7 +582,7 @@
 					hdev->manufacturer,
 					hdev->hci_ver, hdev->hci_rev);
 
-	if (test_bit(HCI_INIT, &hdev->flags))
+	if (hdev->dev_type == HCI_BREDR && test_bit(HCI_INIT, &hdev->flags))
 		hci_setup(hdev);
 }
 
@@ -685,19 +677,17 @@
 					hdev->features[6], hdev->features[7]);
 }
 
-static void hci_cc_read_local_ext_features(struct hci_dev *hdev,
-							struct sk_buff *skb)
+static void hci_cc_read_flow_control_mode(struct hci_dev *hdev,
+					struct sk_buff *skb)
 {
-	struct hci_rp_read_local_ext_features *rp = (void *) skb->data;
+	struct hci_rp_read_flow_control_mode *rp = (void *) skb->data;
 
 	BT_DBG("%s status 0x%x", hdev->name, rp->status);
 
 	if (rp->status)
 		return;
 
-	memcpy(hdev->extfeatures, rp->features, 8);
-
-	hci_req_complete(hdev, HCI_OP_READ_LOCAL_EXT_FEATURES, rp->status);
+	hdev->flow_ctl_mode = rp->mode;
 }
 
 static void hci_cc_read_buffer_size(struct hci_dev *hdev, struct sk_buff *skb)
@@ -709,18 +699,20 @@
 	if (rp->status)
 		return;
 
-	hdev->acl_mtu  = __le16_to_cpu(rp->acl_mtu);
-	hdev->sco_mtu  = rp->sco_mtu;
-	hdev->acl_pkts = __le16_to_cpu(rp->acl_max_pkt);
-	hdev->sco_pkts = __le16_to_cpu(rp->sco_max_pkt);
+	if (hdev->flow_ctl_mode == HCI_PACKET_BASED_FLOW_CTL_MODE) {
+		hdev->acl_mtu  = __le16_to_cpu(rp->acl_mtu);
+		hdev->sco_mtu  = rp->sco_mtu;
+		hdev->acl_pkts = __le16_to_cpu(rp->acl_max_pkt);
+		hdev->sco_pkts = __le16_to_cpu(rp->sco_max_pkt);
+		hdev->acl_cnt = hdev->acl_pkts;
+		hdev->sco_cnt = hdev->sco_pkts;
+	}
 
 	if (test_bit(HCI_QUIRK_FIXUP_BUFFER_SIZE, &hdev->quirks)) {
 		hdev->sco_mtu  = 64;
 		hdev->sco_pkts = 8;
 	}
 
-	hdev->acl_cnt = hdev->acl_pkts;
-	hdev->sco_cnt = hdev->sco_pkts;
 
 	BT_DBG("%s acl mtu %d:%d sco mtu %d:%d", hdev->name,
 					hdev->acl_mtu, hdev->acl_pkts,
@@ -748,6 +740,55 @@
 	hci_req_complete(hdev, HCI_OP_WRITE_CA_TIMEOUT, status);
 }
 
+static void hci_cc_read_data_block_size(struct hci_dev *hdev,
+					struct sk_buff *skb)
+{
+	struct hci_rp_read_data_block_size *rp = (void *) skb->data;
+
+	BT_DBG("%s status 0x%x", hdev->name, rp->status);
+
+	if (rp->status)
+		return;
+
+	if (hdev->flow_ctl_mode == HCI_BLOCK_BASED_FLOW_CTL_MODE) {
+		hdev->acl_mtu  = __le16_to_cpu(rp->max_acl_len);
+		hdev->sco_mtu = 0;
+		hdev->data_block_len = __le16_to_cpu(rp->data_block_len);
+		/* acl_pkts indicates the number of blocks */
+		hdev->acl_pkts = __le16_to_cpu(rp->num_blocks);
+		hdev->sco_pkts = 0;
+		hdev->acl_cnt = hdev->acl_pkts;
+		hdev->sco_cnt = 0;
+	}
+
+	BT_DBG("%s acl mtu %d:%d, data block len %d", hdev->name,
+			hdev->acl_mtu, hdev->acl_cnt, hdev->data_block_len);
+}
+
+static void hci_cc_read_local_amp_info(struct hci_dev *hdev,
+				struct sk_buff *skb)
+{
+	struct hci_rp_read_local_amp_info *rp = (void *) skb->data;
+
+	BT_DBG("%s status 0x%x", hdev->name, rp->status);
+
+	if (rp->status)
+		return;
+
+	hdev->amp_status = rp->amp_status;
+	hdev->amp_total_bw = __le32_to_cpu(rp->total_bw);
+	hdev->amp_max_bw = __le32_to_cpu(rp->max_bw);
+	hdev->amp_min_latency = __le32_to_cpu(rp->min_latency);
+	hdev->amp_max_pdu = __le32_to_cpu(rp->max_pdu);
+	hdev->amp_type = rp->amp_type;
+	hdev->amp_pal_cap = __le16_to_cpu(rp->pal_cap);
+	hdev->amp_assoc_size = __le16_to_cpu(rp->max_assoc_size);
+	hdev->amp_be_flush_to = __le32_to_cpu(rp->be_flush_to);
+	hdev->amp_max_flush_to = __le32_to_cpu(rp->max_flush_to);
+
+	hci_req_complete(hdev, HCI_OP_READ_LOCAL_AMP_INFO, rp->status);
+}
+
 static void hci_cc_delete_stored_link_key(struct hci_dev *hdev,
 							struct sk_buff *skb)
 {
@@ -883,33 +924,6 @@
 						rp->randomizer, rp->status);
 }
 
-static void hci_cc_le_set_scan_enable(struct hci_dev *hdev,
-					struct sk_buff *skb)
-{
-	struct hci_cp_le_set_scan_enable *cp;
-	__u8 status = *((__u8 *) skb->data);
-
-	BT_DBG("%s status 0x%x", hdev->name, status);
-
-	if (status)
-		return;
-
-	cp = hci_sent_cmd_data(hdev, HCI_OP_LE_SET_SCAN_ENABLE);
-	if (!cp)
-		return;
-
-	hci_dev_lock(hdev);
-
-	if (cp->enable == 0x01) {
-		del_timer(&hdev->adv_timer);
-		hci_adv_entries_clear(hdev);
-	} else if (cp->enable == 0x00) {
-		mod_timer(&hdev->adv_timer, jiffies + ADV_CLEAR_TIMEOUT);
-	}
-
-	hci_dev_unlock(hdev);
-}
-
 static void hci_cc_le_ltk_reply(struct hci_dev *hdev, struct sk_buff *skb)
 {
 	struct hci_rp_le_ltk_reply *rp = (void *) skb->data;
@@ -934,19 +948,27 @@
 	hci_req_complete(hdev, HCI_OP_LE_LTK_NEG_REPLY, rp->status);
 }
 
-static inline void hci_cc_write_le_host_supported(struct hci_dev *hdev,
-							struct sk_buff *skb)
+static void hci_cc_le_set_scan_enable(struct hci_dev *hdev,
+					struct sk_buff *skb)
 {
-	struct hci_cp_read_local_ext_features cp;
+	void *sent;
+	__u8 param_scan_enable;
 	__u8 status = *((__u8 *) skb->data);
 
-	BT_DBG("%s status 0x%x", hdev->name, status);
-
 	if (status)
 		return;
 
-	cp.page = 0x01;
-	hci_send_cmd(hdev, HCI_OP_READ_LOCAL_EXT_FEATURES, sizeof(cp), &cp);
+	sent = hci_sent_cmd_data(hdev, HCI_OP_LE_SET_SCAN_ENABLE);
+	if (!sent)
+		return;
+
+	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);
+	}
 }
 
 static inline void hci_cs_inquiry(struct hci_dev *hdev, __u8 status)
@@ -955,14 +977,10 @@
 
 	if (status) {
 		hci_req_complete(hdev, HCI_OP_INQUIRY, status);
-		hci_conn_check_pending(hdev);
-		return;
-	}
 
-	if (test_bit(HCI_MGMT, &hdev->flags) &&
-					!test_and_set_bit(HCI_INQUIRY,
-							&hdev->flags))
-		mgmt_discovering(hdev->id, 1);
+		hci_conn_check_pending(hdev);
+	} else
+		set_bit(HCI_INQUIRY, &hdev->flags);
 }
 
 static inline void hci_cs_create_conn(struct hci_dev *hdev, __u8 status)
@@ -1131,19 +1149,12 @@
 	hci_dev_lock(hdev);
 
 	conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
-	if (!conn)
-		goto unlock;
-
-	if (!hci_outgoing_auth_needed(hdev, conn))
-		goto unlock;
-
-	if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->pend)) {
+	if (conn && hci_outgoing_auth_needed(hdev, conn)) {
 		struct hci_cp_auth_requested cp;
 		cp.handle = __cpu_to_le16(conn->handle);
 		hci_send_cmd(hdev, HCI_OP_AUTH_REQUESTED, sizeof(cp), &cp);
 	}
 
-unlock:
 	hci_dev_unlock(hdev);
 }
 
@@ -1316,19 +1327,150 @@
 		}
 	} else {
 		if (!conn) {
-			conn = hci_conn_add(hdev, LE_LINK, 0, &cp->peer_addr);
-			if (conn) {
-				conn->dst_type = cp->peer_addr_type;
+			conn = hci_le_conn_add(hdev, &cp->peer_addr,
+						cp->peer_addr_type);
+			if (conn)
 				conn->out = 1;
-			} else {
+			else
 				BT_ERR("No memory for new connection");
-			}
 		}
 	}
 
 	hci_dev_unlock(hdev);
 }
 
+static void hci_cs_accept_logical_link(struct hci_dev *hdev, __u8 status)
+{
+	struct hci_cp_create_logical_link *ap;
+	struct hci_chan *chan;
+
+	BT_DBG("%s status 0x%x", hdev->name, status);
+
+	ap = hci_sent_cmd_data(hdev, HCI_OP_ACCEPT_LOGICAL_LINK);
+	if (!ap)
+		return;
+
+	hci_dev_lock(hdev);
+
+	chan = hci_chan_list_lookup_id(hdev, ap->phy_handle);
+
+	BT_DBG("%s chan %p", hdev->name, chan);
+
+	if (status) {
+		if (chan && chan->state == BT_CONNECT) {
+			chan->state = BT_CLOSED;
+			hci_proto_create_cfm(chan, status);
+			hci_chan_del(chan);
+		}
+	} else if (chan)
+			chan->state = BT_CONNECT2;
+
+	hci_dev_unlock(hdev);
+}
+
+static void hci_cs_create_logical_link(struct hci_dev *hdev, __u8 status)
+{
+	struct hci_cp_create_logical_link *cp;
+	struct hci_chan *chan;
+
+	BT_DBG("%s status 0x%x", hdev->name, status);
+
+	cp = hci_sent_cmd_data(hdev, HCI_OP_CREATE_LOGICAL_LINK);
+	if (!cp)
+		return;
+
+	hci_dev_lock(hdev);
+
+	chan = hci_chan_list_lookup_id(hdev, cp->phy_handle);
+
+	BT_DBG("%s chan %p", hdev->name, chan);
+
+	if (status) {
+		if (chan && chan->state == BT_CONNECT) {
+			chan->state = BT_CLOSED;
+			hci_proto_create_cfm(chan, status);
+			hci_chan_del(chan);
+		}
+	} else if (chan)
+			chan->state = BT_CONNECT2;
+
+	hci_dev_unlock(hdev);
+}
+
+static void hci_cs_flow_spec_modify(struct hci_dev *hdev, __u8 status)
+{
+	struct hci_cp_flow_spec_modify *cp;
+	struct hci_chan *chan;
+
+	BT_DBG("%s status 0x%x", hdev->name, status);
+
+	cp = hci_sent_cmd_data(hdev, HCI_OP_FLOW_SPEC_MODIFY);
+	if (!cp)
+		return;
+
+	hci_dev_lock(hdev);
+
+	chan = hci_chan_list_lookup_handle(hdev, cp->log_handle);
+	if (chan) {
+		if (status)
+			hci_proto_modify_cfm(chan, status);
+		else {
+			chan->tx_fs = cp->tx_fs;
+			chan->rx_fs = cp->rx_fs;
+		}
+	}
+
+	hci_dev_unlock(hdev);
+}
+
+static void hci_cs_disconn_logical_link(struct hci_dev *hdev, __u8 status)
+{
+	struct hci_cp_disconn_logical_link *cp;
+	struct hci_chan *chan;
+
+	if (!status)
+		return;
+
+	BT_DBG("%s status 0x%x", hdev->name, status);
+
+	cp = hci_sent_cmd_data(hdev, HCI_OP_DISCONN_LOGICAL_LINK);
+	if (!cp)
+		return;
+
+	hci_dev_lock(hdev);
+
+	chan = hci_chan_list_lookup_handle(hdev, cp->log_handle);
+	if (chan)
+		hci_chan_del(chan);
+
+	hci_dev_unlock(hdev);
+}
+
+static void hci_cs_disconn_physical_link(struct hci_dev *hdev, __u8 status)
+{
+	struct hci_cp_disconn_phys_link *cp;
+	struct hci_conn *conn;
+
+	if (!status)
+		return;
+
+	BT_DBG("%s status 0x%x", hdev->name, status);
+
+	cp = hci_sent_cmd_data(hdev, HCI_OP_DISCONN_PHYS_LINK);
+	if (!cp)
+		return;
+
+	hci_dev_lock(hdev);
+
+	conn = hci_conn_hash_lookup_handle(hdev, cp->phy_handle);
+	if (conn) {
+		conn->state = BT_CLOSED;
+		hci_conn_del(conn);
+	}
+
+	hci_dev_unlock(hdev);
+}
+
 static void hci_cs_le_start_enc(struct hci_dev *hdev, u8 status)
 {
 	BT_DBG("%s status 0x%x", hdev->name, status);
@@ -1340,9 +1482,7 @@
 
 	BT_DBG("%s status %d", hdev->name, status);
 
-	if (test_bit(HCI_MGMT, &hdev->flags) &&
-				test_and_clear_bit(HCI_INQUIRY, &hdev->flags))
-		mgmt_discovering(hdev->id, 0);
+	clear_bit(HCI_INQUIRY, &hdev->flags);
 
 	hci_req_complete(hdev, HCI_OP_INQUIRY, status);
 
@@ -1362,12 +1502,6 @@
 
 	hci_dev_lock(hdev);
 
-	if (!test_and_set_bit(HCI_INQUIRY, &hdev->flags)) {
-
-		if (test_bit(HCI_MGMT, &hdev->flags))
-			mgmt_discovering(hdev->id, 1);
-	}
-
 	for (; num_rsp; num_rsp--, info++) {
 		bacpy(&data.bdaddr, &info->bdaddr);
 		data.pscan_rep_mode	= info->pscan_rep_mode;
@@ -1521,9 +1655,9 @@
 
 			cp.tx_bandwidth   = cpu_to_le32(0x00001f40);
 			cp.rx_bandwidth   = cpu_to_le32(0x00001f40);
-			cp.max_latency    = cpu_to_le16(0xffff);
+			cp.max_latency    = cpu_to_le16(0x000A);
 			cp.content_format = cpu_to_le16(hdev->voice_setting);
-			cp.retrans_effort = 0xff;
+			cp.retrans_effort = 0x01;
 
 			hci_send_cmd(hdev, HCI_OP_ACCEPT_SYNC_CONN_REQ,
 							sizeof(cp), &cp);
@@ -1558,7 +1692,7 @@
 
 	conn->state = BT_CLOSED;
 
-	if (conn->type == ACL_LINK || conn->type == LE_LINK)
+	if (conn->type == ACL_LINK)
 		mgmt_disconnected(hdev->id, &conn->dst);
 
 	hci_proto_disconn_cfm(conn, ev->reason);
@@ -1578,58 +1712,63 @@
 	hci_dev_lock(hdev);
 
 	conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle));
-	if (!conn)
-		goto unlock;
+	if (conn) {
+		if (ev->status == 0x06 && hdev->ssp_mode > 0 &&
+							conn->ssp_mode > 0) {
+			struct hci_cp_auth_requested cp;
+			cp.handle = cpu_to_le16(conn->handle);
+			hci_send_cmd(conn->hdev, HCI_OP_AUTH_REQUESTED,
+							sizeof(cp), &cp);
+			hci_dev_unlock(hdev);
+			BT_INFO("Pin or key missing");
+			return;
+		}
 
-	if (!ev->status) {
-		if (!(conn->ssp_mode > 0 && hdev->ssp_mode > 0) &&
-				test_bit(HCI_CONN_REAUTH_PEND,	&conn->pend)) {
-			BT_INFO("re-auth of legacy device is not possible.");
-		} else {
+		if (!ev->status) {
 			conn->link_mode |= HCI_LM_AUTH;
 			conn->sec_level = conn->pending_sec_level;
-		}
-	} else {
-		mgmt_auth_failed(hdev->id, &conn->dst, ev->status);
-	}
-
-	clear_bit(HCI_CONN_AUTH_PEND, &conn->pend);
-	clear_bit(HCI_CONN_REAUTH_PEND, &conn->pend);
-
-	if (conn->state == BT_CONFIG) {
-		if (!ev->status && hdev->ssp_mode > 0 && conn->ssp_mode > 0) {
-			struct hci_cp_set_conn_encrypt cp;
-			cp.handle  = ev->handle;
-			cp.encrypt = 0x01;
-			hci_send_cmd(hdev, HCI_OP_SET_CONN_ENCRYPT, sizeof(cp),
-									&cp);
 		} else {
-			conn->state = BT_CONNECTED;
-			hci_proto_connect_cfm(conn, ev->status);
+			mgmt_auth_failed(hdev->id, &conn->dst, ev->status);
+			conn->sec_level = BT_SECURITY_LOW;
+		}
+
+		clear_bit(HCI_CONN_AUTH_PEND, &conn->pend);
+
+		if (conn->state == BT_CONFIG) {
+			if (!ev->status && hdev->ssp_mode > 0 &&
+							conn->ssp_mode > 0) {
+				struct hci_cp_set_conn_encrypt cp;
+				cp.handle  = ev->handle;
+				cp.encrypt = 0x01;
+				hci_send_cmd(hdev, HCI_OP_SET_CONN_ENCRYPT,
+							sizeof(cp), &cp);
+			} else {
+				conn->state = BT_CONNECTED;
+				hci_proto_connect_cfm(conn, ev->status);
+				hci_conn_put(conn);
+			}
+		} else {
+			hci_auth_cfm(conn, ev->status);
+
+			hci_conn_hold(conn);
+			conn->disc_timeout = HCI_DISCONN_TIMEOUT;
 			hci_conn_put(conn);
 		}
-	} else {
-		hci_auth_cfm(conn, ev->status);
 
-		hci_conn_hold(conn);
-		conn->disc_timeout = HCI_DISCONN_TIMEOUT;
-		hci_conn_put(conn);
-	}
-
-	if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend)) {
-		if (!ev->status) {
-			struct hci_cp_set_conn_encrypt cp;
-			cp.handle  = ev->handle;
-			cp.encrypt = 0x01;
-			hci_send_cmd(hdev, HCI_OP_SET_CONN_ENCRYPT, sizeof(cp),
-									&cp);
-		} else {
-			clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend);
-			hci_encrypt_cfm(conn, ev->status, 0x00);
+		if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend)) {
+			if (!ev->status) {
+				struct hci_cp_set_conn_encrypt cp;
+				cp.handle  = ev->handle;
+				cp.encrypt = 0x01;
+				hci_send_cmd(hdev, HCI_OP_SET_CONN_ENCRYPT,
+							sizeof(cp), &cp);
+			} else {
+				clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend);
+				hci_encrypt_cfm(conn, ev->status, 0x00);
+			}
 		}
 	}
 
-unlock:
 	hci_dev_unlock(hdev);
 }
 
@@ -1648,19 +1787,12 @@
 		mgmt_remote_name(hdev->id, &ev->bdaddr, ev->name);
 
 	conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr);
-	if (!conn)
-		goto unlock;
-
-	if (!hci_outgoing_auth_needed(hdev, conn))
-		goto unlock;
-
-	if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->pend)) {
+	if (conn && hci_outgoing_auth_needed(hdev, conn)) {
 		struct hci_cp_auth_requested cp;
 		cp.handle = __cpu_to_le16(conn->handle);
 		hci_send_cmd(hdev, HCI_OP_AUTH_REQUESTED, sizeof(cp), &cp);
 	}
 
-unlock:
 	hci_dev_unlock(hdev);
 }
 
@@ -1796,6 +1928,10 @@
 		hci_cc_exit_periodic_inq(hdev, skb);
 		break;
 
+	case HCI_OP_LINK_KEY_REPLY:
+		hci_cc_link_key_reply(hdev, skb);
+		break;
+
 	case HCI_OP_REMOTE_NAME_REQ_CANCEL:
 		hci_cc_remote_name_req_cancel(hdev, skb);
 		break;
@@ -1884,10 +2020,6 @@
 		hci_cc_read_local_features(hdev, skb);
 		break;
 
-	case HCI_OP_READ_LOCAL_EXT_FEATURES:
-		hci_cc_read_local_ext_features(hdev, skb);
-		break;
-
 	case HCI_OP_READ_BUFFER_SIZE:
 		hci_cc_read_buffer_size(hdev, skb);
 		break;
@@ -1900,6 +2032,23 @@
 		hci_cc_write_ca_timeout(hdev, skb);
 		break;
 
+	case HCI_OP_READ_FLOW_CONTROL_MODE:
+		hci_cc_read_flow_control_mode(hdev, skb);
+		break;
+
+	case HCI_OP_READ_DATA_BLOCK_SIZE:
+		hci_cc_read_data_block_size(hdev, skb);
+		break;
+
+	case HCI_OP_READ_LOCAL_AMP_INFO:
+		hci_cc_read_local_amp_info(hdev, skb);
+		break;
+
+	case HCI_OP_READ_LOCAL_AMP_ASSOC:
+	case HCI_OP_WRITE_REMOTE_AMP_ASSOC:
+		hci_amp_cmd_complete(hdev, opcode, skb);
+		break;
+
 	case HCI_OP_DELETE_STORED_LINK_KEY:
 		hci_cc_delete_stored_link_key(hdev, skb);
 		break;
@@ -1944,10 +2093,6 @@
 		hci_cc_user_confirm_neg_reply(hdev, skb);
 		break;
 
-	case HCI_OP_LE_SET_SCAN_ENABLE:
-		hci_cc_le_set_scan_enable(hdev, skb);
-		break;
-
 	case HCI_OP_LE_LTK_REPLY:
 		hci_cc_le_ltk_reply(hdev, skb);
 		break;
@@ -1956,8 +2101,8 @@
 		hci_cc_le_ltk_neg_reply(hdev, skb);
 		break;
 
-	case HCI_OP_WRITE_LE_HOST_SUPPORTED:
-		hci_cc_write_le_host_supported(hdev, skb);
+	case HCI_OP_LE_SET_SCAN_ENABLE:
+		hci_cc_le_set_scan_enable(hdev, skb);
 		break;
 
 	default:
@@ -2029,6 +2174,30 @@
 		hci_cs_exit_sniff_mode(hdev, ev->status);
 		break;
 
+	case HCI_OP_CREATE_LOGICAL_LINK:
+		hci_cs_create_logical_link(hdev, ev->status);
+		break;
+
+	case HCI_OP_ACCEPT_LOGICAL_LINK:
+		hci_cs_accept_logical_link(hdev, ev->status);
+		break;
+
+	case HCI_OP_DISCONN_LOGICAL_LINK:
+		hci_cs_disconn_logical_link(hdev, ev->status);
+		break;
+
+	case HCI_OP_FLOW_SPEC_MODIFY:
+		hci_cs_flow_spec_modify(hdev, ev->status);
+		break;
+
+	case HCI_OP_CREATE_PHYS_LINK:
+	case HCI_OP_ACCEPT_PHYS_LINK:
+		hci_amp_cmd_status(hdev, opcode, ev->status);
+		break;
+
+	case HCI_OP_DISCONN_PHYS_LINK:
+		hci_cs_disconn_physical_link(hdev, ev->status);
+
 	case HCI_OP_DISCONNECT:
 		if (ev->status != 0)
 			mgmt_disconnect_failed(hdev->id);
@@ -2101,13 +2270,20 @@
 	tasklet_disable(&hdev->tx_task);
 
 	for (i = 0, ptr = (__le16 *) skb->data; i < ev->num_hndl; i++) {
-		struct hci_conn *conn;
+		struct hci_conn *conn = NULL;
+		struct hci_chan *chan;
 		__u16  handle, count;
 
 		handle = get_unaligned_le16(ptr++);
 		count  = get_unaligned_le16(ptr++);
 
-		conn = hci_conn_hash_lookup_handle(hdev, handle);
+		if (hdev->dev_type == HCI_BREDR)
+			conn = hci_conn_hash_lookup_handle(hdev, handle);
+		else {
+			chan = hci_chan_list_lookup_handle(hdev, handle);
+			if (chan)
+				conn = chan->conn;
+		}
 		if (conn) {
 			conn->sent -= count;
 
@@ -2138,6 +2314,68 @@
 	tasklet_enable(&hdev->tx_task);
 }
 
+static inline void hci_num_comp_blocks_evt(struct hci_dev *hdev,
+					struct sk_buff *skb)
+{
+	struct hci_ev_num_comp_blocks *ev = (void *) skb->data;
+	__le16 *ptr;
+	int i;
+
+	skb_pull(skb, sizeof(*ev));
+
+	BT_DBG("%s total_num_blocks %d num_hndl %d",
+		hdev->name, ev->total_num_blocks, ev->num_hndl);
+
+	if (skb->len < ev->num_hndl * 6) {
+		BT_DBG("%s bad parameters", hdev->name);
+		return;
+	}
+
+	tasklet_disable(&hdev->tx_task);
+
+	for (i = 0, ptr = (__le16 *) skb->data; i < ev->num_hndl; i++) {
+		struct hci_conn *conn = NULL;
+		struct hci_chan *chan;
+		__u16  handle, block_count;
+
+		handle = get_unaligned_le16(ptr++);
+
+		/* Skip packet count */
+		ptr++;
+		block_count  = get_unaligned_le16(ptr++);
+
+		BT_DBG("%s handle %d count %d", hdev->name, handle,
+			block_count);
+
+		if (hdev->dev_type == HCI_BREDR)
+			conn = hci_conn_hash_lookup_handle(hdev, handle);
+		else {
+			chan = hci_chan_list_lookup_handle(hdev, handle);
+			if (chan)
+				conn = chan->conn;
+		}
+		if (conn) {
+			BT_DBG("%s conn %p sent %d", hdev->name,
+				conn, conn->sent);
+
+			conn->sent -= block_count;
+
+			if (conn->type == ACL_LINK) {
+				hdev->acl_cnt += block_count;
+				if (hdev->acl_cnt > hdev->acl_pkts)
+					hdev->acl_cnt = hdev->acl_pkts;
+			} else {
+				/* We should not find ourselves here */
+				BT_DBG("Unexpected event for SCO connection");
+			}
+		}
+	}
+
+	tasklet_schedule(&hdev->tx_task);
+
+	tasklet_enable(&hdev->tx_task);
+}
+
 static inline void hci_mode_change_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
 	struct hci_ev_mode_change *ev = (void *) skb->data;
@@ -2185,16 +2423,9 @@
 	if (!test_bit(HCI_PAIRABLE, &hdev->flags))
 		hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
 					sizeof(ev->bdaddr), &ev->bdaddr);
-	else if (test_bit(HCI_MGMT, &hdev->flags)) {
-		u8 secure;
 
-		if (conn->pending_sec_level == BT_SECURITY_HIGH)
-			secure = 1;
-		else
-			secure = 0;
-
-		mgmt_pin_code_request(hdev->id, &ev->bdaddr, secure);
-	}
+	if (test_bit(HCI_MGMT, &hdev->flags))
+		mgmt_pin_code_request(hdev->id, &ev->bdaddr);
 
 	hci_dev_unlock(hdev);
 }
@@ -2223,30 +2454,17 @@
 	BT_DBG("%s found key type %u for %s", hdev->name, key->type,
 							batostr(&ev->bdaddr));
 
-	if (!test_bit(HCI_DEBUG_KEYS, &hdev->flags) &&
-				key->type == HCI_LK_DEBUG_COMBINATION) {
+	if (!test_bit(HCI_DEBUG_KEYS, &hdev->flags) && key->type == 0x03) {
 		BT_DBG("%s ignoring debug key", hdev->name);
 		goto not_found;
 	}
 
 	conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr);
-	if (conn) {
-		if (key->type == HCI_LK_UNAUTH_COMBINATION &&
-				conn->auth_type != 0xff &&
-				(conn->auth_type & 0x01)) {
-			BT_DBG("%s ignoring unauthenticated key", hdev->name);
-			goto not_found;
-		}
 
-		if (key->type == HCI_LK_COMBINATION && key->pin_len < 16 &&
-				conn->pending_sec_level == BT_SECURITY_HIGH) {
-			BT_DBG("%s ignoring key unauthenticated for high \
-							security", hdev->name);
-			goto not_found;
-		}
-
-		conn->key_type = key->type;
-		conn->pin_length = key->pin_len;
+	if (key->type == 0x04 && conn && conn->auth_type != 0xff &&
+						(conn->auth_type & 0x01)) {
+		BT_DBG("%s ignoring unauthenticated key", hdev->name);
+		goto not_found;
 	}
 
 	bacpy(&cp.bdaddr, &ev->bdaddr);
@@ -2269,7 +2487,7 @@
 	struct hci_conn *conn;
 	u8 pin_len = 0;
 
-	BT_DBG("%s", hdev->name);
+	BT_DBG("%s type %d", hdev->name, ev->key_type);
 
 	hci_dev_lock(hdev);
 
@@ -2277,16 +2495,17 @@
 	if (conn) {
 		hci_conn_hold(conn);
 		conn->disc_timeout = HCI_DISCONN_TIMEOUT;
+
+		memcpy(conn->link_key, ev->link_key, 16);
+		conn->key_type = ev->key_type;
+		hci_disconnect_amp(conn, 0x06);
+
 		pin_len = conn->pin_length;
-
-		if (ev->key_type != HCI_LK_CHANGED_COMBINATION)
-			conn->key_type = ev->key_type;
-
 		hci_conn_put(conn);
 	}
 
 	if (test_bit(HCI_LINK_KEYS, &hdev->flags))
-		hci_add_link_key(hdev, conn, 1, &ev->bdaddr, ev->link_key,
+		hci_add_link_key(hdev, 1, &ev->bdaddr, ev->link_key,
 							ev->key_type, pin_len);
 
 	hci_dev_unlock(hdev);
@@ -2361,12 +2580,6 @@
 
 	hci_dev_lock(hdev);
 
-	if (!test_and_set_bit(HCI_INQUIRY, &hdev->flags)) {
-
-		if (test_bit(HCI_MGMT, &hdev->flags))
-			mgmt_discovering(hdev->id, 1);
-	}
-
 	if ((skb->len - 1) / num_rsp != sizeof(struct inquiry_info_with_rssi)) {
 		struct inquiry_info_with_rssi_and_pscan_mode *info;
 		info = (void *) (skb->data + 1);
@@ -2481,7 +2694,6 @@
 		hci_conn_add_sysfs(conn);
 		break;
 
-	case 0x10:	/* Connection Accept Timeout */
 	case 0x11:	/* Unsupported Feature or Parameter Value */
 	case 0x1c:	/* SCO interval rejected */
 	case 0x1a:	/* Unsupported Remote Feature */
@@ -2530,12 +2742,6 @@
 	if (!num_rsp)
 		return;
 
-	if (!test_and_set_bit(HCI_INQUIRY, &hdev->flags)) {
-
-		if (test_bit(HCI_MGMT, &hdev->flags))
-			mgmt_discovering(hdev->id, 1);
-	}
-
 	hci_dev_lock(hdev);
 
 	for (; num_rsp; num_rsp--, info++) {
@@ -2569,7 +2775,7 @@
 
 	/* If remote requests no-bonding follow that lead */
 	if (conn->remote_auth == 0x00 || conn->remote_auth == 0x01)
-		return conn->remote_auth | (conn->auth_type & 0x01);
+		return 0x00;
 
 	return conn->auth_type;
 }
@@ -2598,8 +2804,7 @@
 
 		bacpy(&cp.bdaddr, &ev->bdaddr);
 		cp.capability = conn->io_capability;
-		conn->auth_type = hci_get_auth_req(conn);
-		cp.authentication = conn->auth_type;
+		cp.authentication = hci_get_auth_req(conn);
 
 		if ((conn->out == 0x01 || conn->remote_oob == 0x01) &&
 				hci_find_remote_oob_data(hdev, &conn->dst))
@@ -2613,7 +2818,7 @@
 		struct hci_cp_io_capability_neg_reply cp;
 
 		bacpy(&cp.bdaddr, &ev->bdaddr);
-		cp.reason = 0x18; /* Pairing not allowed */
+		cp.reason = 0x16; /* Pairing not allowed */
 
 		hci_send_cmd(hdev, HCI_OP_IO_CAPABILITY_NEG_REPLY,
 							sizeof(cp), &cp);
@@ -2648,67 +2853,14 @@
 							struct sk_buff *skb)
 {
 	struct hci_ev_user_confirm_req *ev = (void *) skb->data;
-	int loc_mitm, rem_mitm, confirm_hint = 0;
-	struct hci_conn *conn;
 
 	BT_DBG("%s", hdev->name);
 
 	hci_dev_lock(hdev);
 
-	if (!test_bit(HCI_MGMT, &hdev->flags))
-		goto unlock;
+	if (test_bit(HCI_MGMT, &hdev->flags))
+		mgmt_user_confirm_request(hdev->id, &ev->bdaddr, ev->passkey);
 
-	conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr);
-	if (!conn)
-		goto unlock;
-
-	loc_mitm = (conn->auth_type & 0x01);
-	rem_mitm = (conn->remote_auth & 0x01);
-
-	/* If we require MITM but the remote device can't provide that
-	 * (it has NoInputNoOutput) then reject the confirmation
-	 * request. The only exception is when we're dedicated bonding
-	 * initiators (connect_cfm_cb set) since then we always have the MITM
-	 * bit set. */
-	if (!conn->connect_cfm_cb && loc_mitm && conn->remote_cap == 0x03) {
-		BT_DBG("Rejecting request: remote device can't provide MITM");
-		hci_send_cmd(hdev, HCI_OP_USER_CONFIRM_NEG_REPLY,
-					sizeof(ev->bdaddr), &ev->bdaddr);
-		goto unlock;
-	}
-
-	/* If no side requires MITM protection; auto-accept */
-	if ((!loc_mitm || conn->remote_cap == 0x03) &&
-				(!rem_mitm || conn->io_capability == 0x03)) {
-
-		/* If we're not the initiators request authorization to
-		 * proceed from user space (mgmt_user_confirm with
-		 * confirm_hint set to 1). */
-		if (!test_bit(HCI_CONN_AUTH_PEND, &conn->pend)) {
-			BT_DBG("Confirming auto-accept as acceptor");
-			confirm_hint = 1;
-			goto confirm;
-		}
-
-		BT_DBG("Auto-accept of user confirmation with %ums delay",
-						hdev->auto_accept_delay);
-
-		if (hdev->auto_accept_delay > 0) {
-			int delay = msecs_to_jiffies(hdev->auto_accept_delay);
-			mod_timer(&conn->auto_accept_timer, jiffies + delay);
-			goto unlock;
-		}
-
-		hci_send_cmd(hdev, HCI_OP_USER_CONFIRM_REPLY,
-						sizeof(ev->bdaddr), &ev->bdaddr);
-		goto unlock;
-	}
-
-confirm:
-	mgmt_user_confirm_request(hdev->id, &ev->bdaddr, ev->passkey,
-								confirm_hint);
-
-unlock:
 	hci_dev_unlock(hdev);
 }
 
@@ -2801,26 +2953,21 @@
 
 	conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &ev->bdaddr);
 	if (!conn) {
-		conn = hci_conn_add(hdev, LE_LINK, 0, &ev->bdaddr);
+		conn = hci_le_conn_add(hdev, &ev->bdaddr, ev->bdaddr_type);
 		if (!conn) {
 			BT_ERR("No memory for new connection");
 			hci_dev_unlock(hdev);
 			return;
 		}
-
-		conn->dst_type = ev->bdaddr_type;
 	}
 
 	if (ev->status) {
-		mgmt_connect_failed(hdev->id, &ev->bdaddr, ev->status);
 		hci_proto_connect_cfm(conn, ev->status);
 		conn->state = BT_CLOSED;
 		hci_conn_del(conn);
 		goto unlock;
 	}
 
-	mgmt_connected(hdev->id, &ev->bdaddr);
-
 	conn->sec_level = BT_SECURITY_LOW;
 	conn->handle = __le16_to_cpu(ev->handle);
 	conn->state = BT_CONNECTED;
@@ -2834,27 +2981,6 @@
 	hci_dev_unlock(hdev);
 }
 
-static inline void hci_le_adv_report_evt(struct hci_dev *hdev,
-						struct sk_buff *skb)
-{
-	struct hci_ev_le_advertising_info *ev;
-	u8 num_reports;
-
-	num_reports = skb->data[0];
-	ev = (void *) &skb->data[1];
-
-	hci_dev_lock(hdev);
-
-	hci_add_adv_entry(hdev, ev);
-
-	while (--num_reports) {
-		ev = (void *) (ev->data + ev->length + 1);
-		hci_add_adv_entry(hdev, ev);
-	}
-
-	hci_dev_unlock(hdev);
-}
-
 static inline void hci_le_ltk_request_evt(struct hci_dev *hdev,
 						struct sk_buff *skb)
 {
@@ -2892,6 +3018,22 @@
 	hci_dev_unlock(hdev);
 }
 
+static inline void hci_le_adv_report_evt(struct hci_dev *hdev,
+						struct sk_buff *skb)
+{
+	struct hci_ev_le_advertising_info *ev;
+	u8 num_reports;
+
+	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);
+		hci_add_adv_entry(hdev, ev);
+	}
+}
+
 static inline void hci_le_meta_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
 	struct hci_ev_le_meta *le_ev = (void *) skb->data;
@@ -2903,19 +3045,145 @@
 		hci_le_conn_complete_evt(hdev, skb);
 		break;
 
-	case HCI_EV_LE_ADVERTISING_REPORT:
-		hci_le_adv_report_evt(hdev, skb);
-		break;
-
 	case HCI_EV_LE_LTK_REQ:
 		hci_le_ltk_request_evt(hdev, skb);
 		break;
 
+	case HCI_EV_LE_ADVERTISING_REPORT:
+		hci_le_adv_report_evt(hdev, skb);
+		break;
+
 	default:
 		break;
 	}
 }
 
+static inline void hci_phy_link_complete(struct hci_dev *hdev,
+					struct sk_buff *skb)
+{
+	struct hci_ev_phys_link_complete *ev = (void *) skb->data;
+	struct hci_conn *conn;
+
+	BT_DBG("%s handle %d status %d", hdev->name, ev->phy_handle,
+		ev->status);
+
+	hci_dev_lock(hdev);
+
+	if (ev->status == 0) {
+		conn = hci_conn_add(hdev, ACL_LINK, 0, BDADDR_ANY);
+		if (conn) {
+			conn->handle = ev->phy_handle;
+			conn->state = BT_CONNECTED;
+
+			hci_conn_hold(conn);
+			conn->disc_timeout = HCI_DISCONN_TIMEOUT/2;
+			hci_conn_put(conn);
+
+			hci_conn_hold_device(conn);
+			hci_conn_add_sysfs(conn);
+		} else
+			BT_ERR("No memory for new connection");
+	}
+
+	hci_dev_unlock(hdev);
+}
+
+static inline void hci_log_link_complete(struct hci_dev *hdev,
+					struct sk_buff *skb)
+{
+	struct hci_ev_log_link_complete *ev = (void *) skb->data;
+	struct hci_chan *chan;
+
+	BT_DBG("%s handle %d status %d", hdev->name,
+		__le16_to_cpu(ev->log_handle), ev->status);
+
+	hci_dev_lock(hdev);
+
+	chan = hci_chan_list_lookup_id(hdev, ev->phy_handle);
+
+	if (ev->status == 0) {
+		if (chan) {
+			chan->ll_handle = __le16_to_cpu(ev->log_handle);
+			chan->state = BT_CONNECTED;
+			hci_proto_create_cfm(chan, ev->status);
+			hci_chan_hold(chan);
+		}
+	} else {
+		if (chan) {
+			chan->state = BT_CLOSED;
+			hci_proto_create_cfm(chan, ev->status);
+			hci_chan_del(chan);
+		}
+	}
+
+	hci_dev_unlock(hdev);
+}
+
+static inline void hci_flow_spec_modify_complete(struct hci_dev *hdev,
+					struct sk_buff *skb)
+{
+	struct hci_ev_flow_spec_modify_complete *ev = (void *) skb->data;
+	struct hci_chan *chan;
+
+	BT_DBG("%s handle %d status %d", hdev->name,
+		__le16_to_cpu(ev->log_handle), ev->status);
+
+	hci_dev_lock(hdev);
+
+	chan = hci_chan_list_lookup_handle(hdev, ev->log_handle);
+	if (chan)
+		hci_proto_modify_cfm(chan, ev->status);
+
+	hci_dev_unlock(hdev);
+}
+
+static inline void hci_disconn_log_link_complete_evt(struct hci_dev *hdev,
+						struct sk_buff *skb)
+{
+	struct hci_ev_disconn_log_link_complete *ev = (void *) skb->data;
+	struct hci_chan *chan;
+
+	BT_DBG("%s handle %d status %d", hdev->name,
+		__le16_to_cpu(ev->log_handle), ev->status);
+
+	if (ev->status)
+		return;
+
+	hci_dev_lock(hdev);
+
+	chan = hci_chan_list_lookup_handle(hdev, __le16_to_cpu(ev->log_handle));
+	if (chan) {
+		hci_proto_destroy_cfm(chan, ev->reason);
+		hci_chan_del(chan);
+	}
+
+	hci_dev_unlock(hdev);
+}
+
+static inline void hci_disconn_phy_link_complete_evt(struct hci_dev *hdev,
+						struct sk_buff *skb)
+{
+	struct hci_ev_disconn_phys_link_complete *ev = (void *) skb->data;
+	struct hci_conn *conn;
+
+	BT_DBG("%s status %d", hdev->name, ev->status);
+
+	if (ev->status)
+		return;
+
+	hci_dev_lock(hdev);
+
+	conn = hci_conn_hash_lookup_handle(hdev, ev->phy_handle);
+	if (conn) {
+		conn->state = BT_CLOSED;
+
+		hci_proto_disconn_cfm(conn, ev->reason);
+		hci_conn_del(conn);
+	}
+
+	hci_dev_unlock(hdev);
+}
+
 void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
 {
 	struct hci_event_hdr *hdr = (void *) skb->data;
@@ -3068,6 +3336,40 @@
 		hci_remote_oob_data_request_evt(hdev, skb);
 		break;
 
+	case HCI_EV_PHYS_LINK_COMPLETE:
+		hci_phy_link_complete(hdev, skb);
+		hci_amp_event_packet(hdev, event, skb);
+		break;
+
+	case HCI_EV_LOG_LINK_COMPLETE:
+		hci_log_link_complete(hdev, skb);
+		break;
+
+	case HCI_EV_FLOW_SPEC_MODIFY_COMPLETE:
+		hci_flow_spec_modify_complete(hdev, skb);
+		break;
+
+	case HCI_EV_DISCONN_LOG_LINK_COMPLETE:
+		hci_disconn_log_link_complete_evt(hdev, skb);
+		break;
+
+	case HCI_EV_DISCONN_PHYS_LINK_COMPLETE:
+		hci_disconn_phy_link_complete_evt(hdev, skb);
+		hci_amp_event_packet(hdev, event, skb);
+		break;
+
+	case HCI_EV_NUM_COMP_BLOCKS:
+		hci_num_comp_blocks_evt(hdev, skb);
+		break;
+
+	case HCI_EV_CHANNEL_SELECTED:
+		hci_amp_event_packet(hdev, event, skb);
+		break;
+
+	case HCI_EV_AMP_STATUS_CHANGE:
+		hci_amp_event_packet(hdev, event, skb);
+		break;
+
 	default:
 		BT_DBG("%s event 0x%x", hdev->name, event);
 		break;
@@ -3104,6 +3406,3 @@
 	hci_send_to_sock(hdev, skb, NULL);
 	kfree_skb(skb);
 }
-
-module_param(enable_le, bool, 0444);
-MODULE_PARM_DESC(enable_le, "Enable LE support");