Bluetooth: Ensure socket pointer is set during callback

Fix issue where when setting up an AMP link the socket pointer
is not set when the logical link complete callback is called,
resulting in the L2CAP channel being disconnected.

The socket pointer must be set before the HCI logical link
create command is sent, as it is possible for the logical link
complete event to arrive before the HCI command send logic
has returned.

Change-Id: I5d89c14d45bd6b4cf47d5754f822b435ce8076a8
Signed-off-by: Peter Krystad <pkrystad@codeaurora.org>
CRs-fixed: 344553
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index 2854395..f87be20 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -520,6 +520,7 @@
 
 	return chan;
 }
+EXPORT_SYMBOL(hci_chan_add);
 
 int hci_chan_del(struct hci_chan *chan)
 {
@@ -1001,18 +1002,12 @@
 	}
 }
 
-struct hci_chan *hci_chan_accept(struct hci_conn *conn,
+struct hci_chan *hci_chan_create(struct hci_chan *chan,
 			struct hci_ext_fs *tx_fs, struct hci_ext_fs *rx_fs)
 {
-	struct hci_chan *chan;
 	struct hci_cp_create_logical_link cp;
 
-	chan = hci_chan_add(conn->hdev);
-	if (!chan)
-		return NULL;
-
 	chan->state = BT_CONNECT;
-	chan->conn = conn;
 	chan->tx_fs = *tx_fs;
 	chan->rx_fs = *rx_fs;
 	cp.phy_handle = chan->conn->handle;
@@ -1029,40 +1024,12 @@
 	cp.rx_fs.acc_latency = cpu_to_le32(chan->rx_fs.acc_latency);
 	cp.rx_fs.flush_to = cpu_to_le32(chan->rx_fs.flush_to);
 	hci_conn_hold(chan->conn);
-	hci_send_cmd(conn->hdev, HCI_OP_ACCEPT_LOGICAL_LINK, sizeof(cp), &cp);
-	return chan;
-}
-EXPORT_SYMBOL(hci_chan_accept);
-
-struct hci_chan *hci_chan_create(struct hci_conn *conn,
-			struct hci_ext_fs *tx_fs, struct hci_ext_fs *rx_fs)
-{
-	struct hci_chan *chan;
-	struct hci_cp_create_logical_link cp;
-
-	chan = hci_chan_add(conn->hdev);
-	if (!chan)
-		return NULL;
-
-	chan->state = BT_CONNECT;
-	chan->conn = conn;
-	chan->tx_fs = *tx_fs;
-	chan->rx_fs = *rx_fs;
-	cp.phy_handle = chan->conn->handle;
-	cp.tx_fs.id = chan->tx_fs.id;
-	cp.tx_fs.type = chan->tx_fs.type;
-	cp.tx_fs.max_sdu = cpu_to_le16(chan->tx_fs.max_sdu);
-	cp.tx_fs.sdu_arr_time = cpu_to_le32(chan->tx_fs.sdu_arr_time);
-	cp.tx_fs.acc_latency = cpu_to_le32(chan->tx_fs.acc_latency);
-	cp.tx_fs.flush_to = cpu_to_le32(chan->tx_fs.flush_to);
-	cp.rx_fs.id = chan->rx_fs.id;
-	cp.rx_fs.type = chan->rx_fs.type;
-	cp.rx_fs.max_sdu = cpu_to_le16(chan->rx_fs.max_sdu);
-	cp.rx_fs.sdu_arr_time = cpu_to_le32(chan->rx_fs.sdu_arr_time);
-	cp.rx_fs.acc_latency = cpu_to_le32(chan->rx_fs.acc_latency);
-	cp.rx_fs.flush_to = cpu_to_le32(chan->rx_fs.flush_to);
-	hci_conn_hold(chan->conn);
-	hci_send_cmd(conn->hdev, HCI_OP_CREATE_LOGICAL_LINK, sizeof(cp), &cp);
+	if (chan->conn->out)
+		hci_send_cmd(chan->conn->hdev, HCI_OP_CREATE_LOGICAL_LINK,
+							sizeof(cp), &cp);
+	else
+		hci_send_cmd(chan->conn->hdev, HCI_OP_ACCEPT_LOGICAL_LINK,
+							sizeof(cp), &cp);
 	return chan;
 }
 EXPORT_SYMBOL(hci_chan_create);
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 47b6d4d..de3ab22 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -3186,8 +3186,9 @@
 	return 1;
 }
 
-static struct hci_chan *l2cap_chan_admit(u8 amp_id, struct l2cap_pinfo *pi)
+static struct hci_chan *l2cap_chan_admit(u8 amp_id, struct sock *sk)
 {
+	struct l2cap_pinfo *pi = l2cap_pi(sk);
 	struct hci_dev *hdev;
 	struct hci_conn *hcon;
 	struct hci_chan *chan;
@@ -3207,19 +3208,23 @@
 	chan = hci_chan_list_lookup_id(hdev, hcon->handle);
 	if (chan) {
 		l2cap_aggregate(chan, pi);
+		sock_hold(sk);
+		chan->l2cap_sk = sk;
+		hci_chan_hold(chan);
+		pi->ampchan = chan;
 		goto done;
 	}
 
-	if (bt_sk(pi)->parent) {
-		/* Incoming connection */
-		chan = hci_chan_accept(hcon,
-					(struct hci_ext_fs *) &pi->local_fs,
-					(struct hci_ext_fs *) &pi->remote_fs);
-	} else {
-		/* Outgoing connection */
-		chan = hci_chan_create(hcon,
-					(struct hci_ext_fs *) &pi->local_fs,
-					(struct hci_ext_fs *) &pi->remote_fs);
+	chan = hci_chan_add(hdev);
+	if (chan) {
+		chan->conn = hcon;
+		sock_hold(sk);
+		chan->l2cap_sk = sk;
+		hci_chan_hold(chan);
+		pi->ampchan = chan;
+		hci_chan_create(chan,
+			(struct hci_ext_fs *) &pi->local_fs,
+			(struct hci_ext_fs *) &pi->remote_fs);
 	}
 done:
 	hci_dev_put(hdev);
@@ -3625,14 +3630,10 @@
 				struct hci_chan *chan;
 				/* Trigger logical link creation only on AMP */
 
-				chan = l2cap_chan_admit(pi->amp_id, pi);
+				chan = l2cap_chan_admit(pi->amp_id, sk);
 				if (!chan)
 					return -ECONNREFUSED;
 
-				hci_chan_hold(chan);
-				pi->ampchan = chan;
-				chan->l2cap_sk = sk;
-
 				if (chan->state == BT_CONNECTED)
 					l2cap_create_cfm(chan, 0);
 			}
@@ -4466,17 +4467,13 @@
 			/* Already sent a 'pending' response, so set up
 			 * the logical link now
 			 */
-			chan = l2cap_chan_admit(pi->amp_id, pi);
+			chan = l2cap_chan_admit(pi->amp_id, sk);
 			if (!chan) {
 				l2cap_send_disconn_req(pi->conn, sk,
 							ECONNRESET);
 				goto done;
 			}
 
-			hci_chan_hold(chan);
-			pi->ampchan = chan;
-			chan->l2cap_sk = sk;
-
 			if (chan->state == BT_CONNECTED)
 				l2cap_create_cfm(chan, 0);
 		}
@@ -5004,7 +5001,7 @@
 			}
 			pi->remote_fs = default_fs;
 			pi->local_fs = default_fs;
-			chan = l2cap_chan_admit(pi->amp_move_id, pi);
+			chan = l2cap_chan_admit(pi->amp_move_id, sk);
 			if (!chan) {
 				/* Logical link not available */
 				l2cap_send_move_chan_cfm(conn, pi, pi->scid,
@@ -5012,10 +5009,6 @@
 				break;
 			}
 
-			hci_chan_hold(chan);
-			pi->ampchan = chan;
-			chan->l2cap_sk = sk;
-
 			if (chan->state == BT_CONNECTED) {
 				/* Logical link is already ready to go */
 				pi->ampcon = chan->conn;
@@ -5323,12 +5316,8 @@
 				0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF};
 		pi->remote_fs = default_fs;
 		pi->local_fs = default_fs;
-		chan = l2cap_chan_admit(local_id, pi);
+		chan = l2cap_chan_admit(local_id, sk);
 		if (chan) {
-			hci_chan_hold(chan);
-			pi->ampchan = chan;
-			chan->l2cap_sk = sk;
-
 			if (chan->state == BT_CONNECTED) {
 				/* Logical link is ready to go */
 				pi->ampcon = chan->conn;
@@ -5546,9 +5535,7 @@
 {
 	struct l2cap_logical_link_work *amp_work;
 
-	if (chan->l2cap_sk) {
-		sock_hold(chan->l2cap_sk);
-	} else {
+	if (!chan->l2cap_sk) {
 		BT_ERR("Expected l2cap_sk to point to connecting socket");
 		return -EFAULT;
 	}