18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci   Copyright (c) 2010,2011 Code Aurora Forum.  All rights reserved.
48c2ecf20Sopenharmony_ci   Copyright (c) 2011,2012 Intel Corp.
58c2ecf20Sopenharmony_ci
68c2ecf20Sopenharmony_ci*/
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#include <net/bluetooth/bluetooth.h>
98c2ecf20Sopenharmony_ci#include <net/bluetooth/hci_core.h>
108c2ecf20Sopenharmony_ci#include <net/bluetooth/l2cap.h>
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci#include "hci_request.h"
138c2ecf20Sopenharmony_ci#include "a2mp.h"
148c2ecf20Sopenharmony_ci#include "amp.h"
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_ci#define A2MP_FEAT_EXT	0x8000
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci/* Global AMP Manager list */
198c2ecf20Sopenharmony_cistatic LIST_HEAD(amp_mgr_list);
208c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(amp_mgr_list_lock);
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci/* A2MP build & send command helper functions */
238c2ecf20Sopenharmony_cistatic struct a2mp_cmd *__a2mp_build(u8 code, u8 ident, u16 len, void *data)
248c2ecf20Sopenharmony_ci{
258c2ecf20Sopenharmony_ci	struct a2mp_cmd *cmd;
268c2ecf20Sopenharmony_ci	int plen;
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci	plen = sizeof(*cmd) + len;
298c2ecf20Sopenharmony_ci	cmd = kzalloc(plen, GFP_KERNEL);
308c2ecf20Sopenharmony_ci	if (!cmd)
318c2ecf20Sopenharmony_ci		return NULL;
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci	cmd->code = code;
348c2ecf20Sopenharmony_ci	cmd->ident = ident;
358c2ecf20Sopenharmony_ci	cmd->len = cpu_to_le16(len);
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_ci	memcpy(cmd->data, data, len);
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci	return cmd;
408c2ecf20Sopenharmony_ci}
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_cistatic void a2mp_send(struct amp_mgr *mgr, u8 code, u8 ident, u16 len, void *data)
438c2ecf20Sopenharmony_ci{
448c2ecf20Sopenharmony_ci	struct l2cap_chan *chan = mgr->a2mp_chan;
458c2ecf20Sopenharmony_ci	struct a2mp_cmd *cmd;
468c2ecf20Sopenharmony_ci	u16 total_len = len + sizeof(*cmd);
478c2ecf20Sopenharmony_ci	struct kvec iv;
488c2ecf20Sopenharmony_ci	struct msghdr msg;
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ci	cmd = __a2mp_build(code, ident, len, data);
518c2ecf20Sopenharmony_ci	if (!cmd)
528c2ecf20Sopenharmony_ci		return;
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci	iv.iov_base = cmd;
558c2ecf20Sopenharmony_ci	iv.iov_len = total_len;
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci	memset(&msg, 0, sizeof(msg));
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ci	iov_iter_kvec(&msg.msg_iter, WRITE, &iv, 1, total_len);
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci	l2cap_chan_send(chan, &msg, total_len);
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci	kfree(cmd);
648c2ecf20Sopenharmony_ci}
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_cistatic u8 __next_ident(struct amp_mgr *mgr)
678c2ecf20Sopenharmony_ci{
688c2ecf20Sopenharmony_ci	if (++mgr->ident == 0)
698c2ecf20Sopenharmony_ci		mgr->ident = 1;
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ci	return mgr->ident;
728c2ecf20Sopenharmony_ci}
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_cistatic struct amp_mgr *amp_mgr_lookup_by_state(u8 state)
758c2ecf20Sopenharmony_ci{
768c2ecf20Sopenharmony_ci	struct amp_mgr *mgr;
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci	mutex_lock(&amp_mgr_list_lock);
798c2ecf20Sopenharmony_ci	list_for_each_entry(mgr, &amp_mgr_list, list) {
808c2ecf20Sopenharmony_ci		if (test_and_clear_bit(state, &mgr->state)) {
818c2ecf20Sopenharmony_ci			amp_mgr_get(mgr);
828c2ecf20Sopenharmony_ci			mutex_unlock(&amp_mgr_list_lock);
838c2ecf20Sopenharmony_ci			return mgr;
848c2ecf20Sopenharmony_ci		}
858c2ecf20Sopenharmony_ci	}
868c2ecf20Sopenharmony_ci	mutex_unlock(&amp_mgr_list_lock);
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci	return NULL;
898c2ecf20Sopenharmony_ci}
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci/* hci_dev_list shall be locked */
928c2ecf20Sopenharmony_cistatic void __a2mp_add_cl(struct amp_mgr *mgr, struct a2mp_cl *cl)
938c2ecf20Sopenharmony_ci{
948c2ecf20Sopenharmony_ci	struct hci_dev *hdev;
958c2ecf20Sopenharmony_ci	int i = 1;
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ci	cl[0].id = AMP_ID_BREDR;
988c2ecf20Sopenharmony_ci	cl[0].type = AMP_TYPE_BREDR;
998c2ecf20Sopenharmony_ci	cl[0].status = AMP_STATUS_BLUETOOTH_ONLY;
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci	list_for_each_entry(hdev, &hci_dev_list, list) {
1028c2ecf20Sopenharmony_ci		if (hdev->dev_type == HCI_AMP) {
1038c2ecf20Sopenharmony_ci			cl[i].id = hdev->id;
1048c2ecf20Sopenharmony_ci			cl[i].type = hdev->amp_type;
1058c2ecf20Sopenharmony_ci			if (test_bit(HCI_UP, &hdev->flags))
1068c2ecf20Sopenharmony_ci				cl[i].status = hdev->amp_status;
1078c2ecf20Sopenharmony_ci			else
1088c2ecf20Sopenharmony_ci				cl[i].status = AMP_STATUS_POWERED_DOWN;
1098c2ecf20Sopenharmony_ci			i++;
1108c2ecf20Sopenharmony_ci		}
1118c2ecf20Sopenharmony_ci	}
1128c2ecf20Sopenharmony_ci}
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ci/* Processing A2MP messages */
1158c2ecf20Sopenharmony_cistatic int a2mp_command_rej(struct amp_mgr *mgr, struct sk_buff *skb,
1168c2ecf20Sopenharmony_ci			    struct a2mp_cmd *hdr)
1178c2ecf20Sopenharmony_ci{
1188c2ecf20Sopenharmony_ci	struct a2mp_cmd_rej *rej = (void *) skb->data;
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ci	if (le16_to_cpu(hdr->len) < sizeof(*rej))
1218c2ecf20Sopenharmony_ci		return -EINVAL;
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci	BT_DBG("ident %d reason %d", hdr->ident, le16_to_cpu(rej->reason));
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_ci	skb_pull(skb, sizeof(*rej));
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci	return 0;
1288c2ecf20Sopenharmony_ci}
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_cistatic int a2mp_discover_req(struct amp_mgr *mgr, struct sk_buff *skb,
1318c2ecf20Sopenharmony_ci			     struct a2mp_cmd *hdr)
1328c2ecf20Sopenharmony_ci{
1338c2ecf20Sopenharmony_ci	struct a2mp_discov_req *req = (void *) skb->data;
1348c2ecf20Sopenharmony_ci	u16 len = le16_to_cpu(hdr->len);
1358c2ecf20Sopenharmony_ci	struct a2mp_discov_rsp *rsp;
1368c2ecf20Sopenharmony_ci	u16 ext_feat;
1378c2ecf20Sopenharmony_ci	u8 num_ctrl;
1388c2ecf20Sopenharmony_ci	struct hci_dev *hdev;
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_ci	if (len < sizeof(*req))
1418c2ecf20Sopenharmony_ci		return -EINVAL;
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_ci	skb_pull(skb, sizeof(*req));
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_ci	ext_feat = le16_to_cpu(req->ext_feat);
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_ci	BT_DBG("mtu %d efm 0x%4.4x", le16_to_cpu(req->mtu), ext_feat);
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_ci	/* check that packet is not broken for now */
1508c2ecf20Sopenharmony_ci	while (ext_feat & A2MP_FEAT_EXT) {
1518c2ecf20Sopenharmony_ci		if (len < sizeof(ext_feat))
1528c2ecf20Sopenharmony_ci			return -EINVAL;
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci		ext_feat = get_unaligned_le16(skb->data);
1558c2ecf20Sopenharmony_ci		BT_DBG("efm 0x%4.4x", ext_feat);
1568c2ecf20Sopenharmony_ci		len -= sizeof(ext_feat);
1578c2ecf20Sopenharmony_ci		skb_pull(skb, sizeof(ext_feat));
1588c2ecf20Sopenharmony_ci	}
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_ci	read_lock(&hci_dev_list_lock);
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_ci	/* at minimum the BR/EDR needs to be listed */
1638c2ecf20Sopenharmony_ci	num_ctrl = 1;
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_ci	list_for_each_entry(hdev, &hci_dev_list, list) {
1668c2ecf20Sopenharmony_ci		if (hdev->dev_type == HCI_AMP)
1678c2ecf20Sopenharmony_ci			num_ctrl++;
1688c2ecf20Sopenharmony_ci	}
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_ci	len = struct_size(rsp, cl, num_ctrl);
1718c2ecf20Sopenharmony_ci	rsp = kmalloc(len, GFP_ATOMIC);
1728c2ecf20Sopenharmony_ci	if (!rsp) {
1738c2ecf20Sopenharmony_ci		read_unlock(&hci_dev_list_lock);
1748c2ecf20Sopenharmony_ci		return -ENOMEM;
1758c2ecf20Sopenharmony_ci	}
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_ci	rsp->mtu = cpu_to_le16(L2CAP_A2MP_DEFAULT_MTU);
1788c2ecf20Sopenharmony_ci	rsp->ext_feat = 0;
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_ci	__a2mp_add_cl(mgr, rsp->cl);
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ci	read_unlock(&hci_dev_list_lock);
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_ci	a2mp_send(mgr, A2MP_DISCOVER_RSP, hdr->ident, len, rsp);
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_ci	kfree(rsp);
1878c2ecf20Sopenharmony_ci	return 0;
1888c2ecf20Sopenharmony_ci}
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_cistatic int a2mp_discover_rsp(struct amp_mgr *mgr, struct sk_buff *skb,
1918c2ecf20Sopenharmony_ci			     struct a2mp_cmd *hdr)
1928c2ecf20Sopenharmony_ci{
1938c2ecf20Sopenharmony_ci	struct a2mp_discov_rsp *rsp = (void *) skb->data;
1948c2ecf20Sopenharmony_ci	u16 len = le16_to_cpu(hdr->len);
1958c2ecf20Sopenharmony_ci	struct a2mp_cl *cl;
1968c2ecf20Sopenharmony_ci	u16 ext_feat;
1978c2ecf20Sopenharmony_ci	bool found = false;
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_ci	if (len < sizeof(*rsp))
2008c2ecf20Sopenharmony_ci		return -EINVAL;
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_ci	len -= sizeof(*rsp);
2038c2ecf20Sopenharmony_ci	skb_pull(skb, sizeof(*rsp));
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_ci	ext_feat = le16_to_cpu(rsp->ext_feat);
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_ci	BT_DBG("mtu %d efm 0x%4.4x", le16_to_cpu(rsp->mtu), ext_feat);
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_ci	/* check that packet is not broken for now */
2108c2ecf20Sopenharmony_ci	while (ext_feat & A2MP_FEAT_EXT) {
2118c2ecf20Sopenharmony_ci		if (len < sizeof(ext_feat))
2128c2ecf20Sopenharmony_ci			return -EINVAL;
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_ci		ext_feat = get_unaligned_le16(skb->data);
2158c2ecf20Sopenharmony_ci		BT_DBG("efm 0x%4.4x", ext_feat);
2168c2ecf20Sopenharmony_ci		len -= sizeof(ext_feat);
2178c2ecf20Sopenharmony_ci		skb_pull(skb, sizeof(ext_feat));
2188c2ecf20Sopenharmony_ci	}
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_ci	cl = (void *) skb->data;
2218c2ecf20Sopenharmony_ci	while (len >= sizeof(*cl)) {
2228c2ecf20Sopenharmony_ci		BT_DBG("Remote AMP id %d type %d status %d", cl->id, cl->type,
2238c2ecf20Sopenharmony_ci		       cl->status);
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_ci		if (cl->id != AMP_ID_BREDR && cl->type != AMP_TYPE_BREDR) {
2268c2ecf20Sopenharmony_ci			struct a2mp_info_req req;
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_ci			found = true;
2298c2ecf20Sopenharmony_ci
2308c2ecf20Sopenharmony_ci			memset(&req, 0, sizeof(req));
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_ci			req.id = cl->id;
2338c2ecf20Sopenharmony_ci			a2mp_send(mgr, A2MP_GETINFO_REQ, __next_ident(mgr),
2348c2ecf20Sopenharmony_ci				  sizeof(req), &req);
2358c2ecf20Sopenharmony_ci		}
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ci		len -= sizeof(*cl);
2388c2ecf20Sopenharmony_ci		cl = skb_pull(skb, sizeof(*cl));
2398c2ecf20Sopenharmony_ci	}
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_ci	/* Fall back to L2CAP init sequence */
2428c2ecf20Sopenharmony_ci	if (!found) {
2438c2ecf20Sopenharmony_ci		struct l2cap_conn *conn = mgr->l2cap_conn;
2448c2ecf20Sopenharmony_ci		struct l2cap_chan *chan;
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_ci		mutex_lock(&conn->chan_lock);
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_ci		list_for_each_entry(chan, &conn->chan_l, list) {
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_ci			BT_DBG("chan %p state %s", chan,
2518c2ecf20Sopenharmony_ci			       state_to_string(chan->state));
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_ci			if (chan->scid == L2CAP_CID_A2MP)
2548c2ecf20Sopenharmony_ci				continue;
2558c2ecf20Sopenharmony_ci
2568c2ecf20Sopenharmony_ci			l2cap_chan_lock(chan);
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_ci			if (chan->state == BT_CONNECT)
2598c2ecf20Sopenharmony_ci				l2cap_send_conn_req(chan);
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_ci			l2cap_chan_unlock(chan);
2628c2ecf20Sopenharmony_ci		}
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_ci		mutex_unlock(&conn->chan_lock);
2658c2ecf20Sopenharmony_ci	}
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_ci	return 0;
2688c2ecf20Sopenharmony_ci}
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_cistatic int a2mp_change_notify(struct amp_mgr *mgr, struct sk_buff *skb,
2718c2ecf20Sopenharmony_ci			      struct a2mp_cmd *hdr)
2728c2ecf20Sopenharmony_ci{
2738c2ecf20Sopenharmony_ci	struct a2mp_cl *cl = (void *) skb->data;
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_ci	while (skb->len >= sizeof(*cl)) {
2768c2ecf20Sopenharmony_ci		BT_DBG("Controller id %d type %d status %d", cl->id, cl->type,
2778c2ecf20Sopenharmony_ci		       cl->status);
2788c2ecf20Sopenharmony_ci		cl = skb_pull(skb, sizeof(*cl));
2798c2ecf20Sopenharmony_ci	}
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_ci	/* TODO send A2MP_CHANGE_RSP */
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_ci	return 0;
2848c2ecf20Sopenharmony_ci}
2858c2ecf20Sopenharmony_ci
2868c2ecf20Sopenharmony_cistatic void read_local_amp_info_complete(struct hci_dev *hdev, u8 status,
2878c2ecf20Sopenharmony_ci					 u16 opcode)
2888c2ecf20Sopenharmony_ci{
2898c2ecf20Sopenharmony_ci	BT_DBG("%s status 0x%2.2x", hdev->name, status);
2908c2ecf20Sopenharmony_ci
2918c2ecf20Sopenharmony_ci	a2mp_send_getinfo_rsp(hdev);
2928c2ecf20Sopenharmony_ci}
2938c2ecf20Sopenharmony_ci
2948c2ecf20Sopenharmony_cistatic int a2mp_getinfo_req(struct amp_mgr *mgr, struct sk_buff *skb,
2958c2ecf20Sopenharmony_ci			    struct a2mp_cmd *hdr)
2968c2ecf20Sopenharmony_ci{
2978c2ecf20Sopenharmony_ci	struct a2mp_info_req *req  = (void *) skb->data;
2988c2ecf20Sopenharmony_ci	struct hci_dev *hdev;
2998c2ecf20Sopenharmony_ci	struct hci_request hreq;
3008c2ecf20Sopenharmony_ci	int err = 0;
3018c2ecf20Sopenharmony_ci
3028c2ecf20Sopenharmony_ci	if (le16_to_cpu(hdr->len) < sizeof(*req))
3038c2ecf20Sopenharmony_ci		return -EINVAL;
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_ci	BT_DBG("id %d", req->id);
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_ci	hdev = hci_dev_get(req->id);
3088c2ecf20Sopenharmony_ci	if (!hdev || hdev->dev_type != HCI_AMP) {
3098c2ecf20Sopenharmony_ci		struct a2mp_info_rsp rsp;
3108c2ecf20Sopenharmony_ci
3118c2ecf20Sopenharmony_ci		memset(&rsp, 0, sizeof(rsp));
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_ci		rsp.id = req->id;
3148c2ecf20Sopenharmony_ci		rsp.status = A2MP_STATUS_INVALID_CTRL_ID;
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_ci		a2mp_send(mgr, A2MP_GETINFO_RSP, hdr->ident, sizeof(rsp),
3178c2ecf20Sopenharmony_ci			  &rsp);
3188c2ecf20Sopenharmony_ci
3198c2ecf20Sopenharmony_ci		goto done;
3208c2ecf20Sopenharmony_ci	}
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_ci	set_bit(READ_LOC_AMP_INFO, &mgr->state);
3238c2ecf20Sopenharmony_ci	hci_req_init(&hreq, hdev);
3248c2ecf20Sopenharmony_ci	hci_req_add(&hreq, HCI_OP_READ_LOCAL_AMP_INFO, 0, NULL);
3258c2ecf20Sopenharmony_ci	err = hci_req_run(&hreq, read_local_amp_info_complete);
3268c2ecf20Sopenharmony_ci	if (err < 0)
3278c2ecf20Sopenharmony_ci		a2mp_send_getinfo_rsp(hdev);
3288c2ecf20Sopenharmony_ci
3298c2ecf20Sopenharmony_cidone:
3308c2ecf20Sopenharmony_ci	if (hdev)
3318c2ecf20Sopenharmony_ci		hci_dev_put(hdev);
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_ci	skb_pull(skb, sizeof(*req));
3348c2ecf20Sopenharmony_ci	return 0;
3358c2ecf20Sopenharmony_ci}
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_cistatic int a2mp_getinfo_rsp(struct amp_mgr *mgr, struct sk_buff *skb,
3388c2ecf20Sopenharmony_ci			    struct a2mp_cmd *hdr)
3398c2ecf20Sopenharmony_ci{
3408c2ecf20Sopenharmony_ci	struct a2mp_info_rsp *rsp = (struct a2mp_info_rsp *) skb->data;
3418c2ecf20Sopenharmony_ci	struct a2mp_amp_assoc_req req;
3428c2ecf20Sopenharmony_ci	struct amp_ctrl *ctrl;
3438c2ecf20Sopenharmony_ci
3448c2ecf20Sopenharmony_ci	if (le16_to_cpu(hdr->len) < sizeof(*rsp))
3458c2ecf20Sopenharmony_ci		return -EINVAL;
3468c2ecf20Sopenharmony_ci
3478c2ecf20Sopenharmony_ci	BT_DBG("id %d status 0x%2.2x", rsp->id, rsp->status);
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_ci	if (rsp->status)
3508c2ecf20Sopenharmony_ci		return -EINVAL;
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_ci	ctrl = amp_ctrl_add(mgr, rsp->id);
3538c2ecf20Sopenharmony_ci	if (!ctrl)
3548c2ecf20Sopenharmony_ci		return -ENOMEM;
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_ci	memset(&req, 0, sizeof(req));
3578c2ecf20Sopenharmony_ci
3588c2ecf20Sopenharmony_ci	req.id = rsp->id;
3598c2ecf20Sopenharmony_ci	a2mp_send(mgr, A2MP_GETAMPASSOC_REQ, __next_ident(mgr), sizeof(req),
3608c2ecf20Sopenharmony_ci		  &req);
3618c2ecf20Sopenharmony_ci
3628c2ecf20Sopenharmony_ci	skb_pull(skb, sizeof(*rsp));
3638c2ecf20Sopenharmony_ci	return 0;
3648c2ecf20Sopenharmony_ci}
3658c2ecf20Sopenharmony_ci
3668c2ecf20Sopenharmony_cistatic int a2mp_getampassoc_req(struct amp_mgr *mgr, struct sk_buff *skb,
3678c2ecf20Sopenharmony_ci				struct a2mp_cmd *hdr)
3688c2ecf20Sopenharmony_ci{
3698c2ecf20Sopenharmony_ci	struct a2mp_amp_assoc_req *req = (void *) skb->data;
3708c2ecf20Sopenharmony_ci	struct hci_dev *hdev;
3718c2ecf20Sopenharmony_ci	struct amp_mgr *tmp;
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_ci	if (le16_to_cpu(hdr->len) < sizeof(*req))
3748c2ecf20Sopenharmony_ci		return -EINVAL;
3758c2ecf20Sopenharmony_ci
3768c2ecf20Sopenharmony_ci	BT_DBG("id %d", req->id);
3778c2ecf20Sopenharmony_ci
3788c2ecf20Sopenharmony_ci	/* Make sure that other request is not processed */
3798c2ecf20Sopenharmony_ci	tmp = amp_mgr_lookup_by_state(READ_LOC_AMP_ASSOC);
3808c2ecf20Sopenharmony_ci
3818c2ecf20Sopenharmony_ci	hdev = hci_dev_get(req->id);
3828c2ecf20Sopenharmony_ci	if (!hdev || hdev->amp_type == AMP_TYPE_BREDR || tmp) {
3838c2ecf20Sopenharmony_ci		struct a2mp_amp_assoc_rsp rsp;
3848c2ecf20Sopenharmony_ci
3858c2ecf20Sopenharmony_ci		memset(&rsp, 0, sizeof(rsp));
3868c2ecf20Sopenharmony_ci		rsp.id = req->id;
3878c2ecf20Sopenharmony_ci
3888c2ecf20Sopenharmony_ci		if (tmp) {
3898c2ecf20Sopenharmony_ci			rsp.status = A2MP_STATUS_COLLISION_OCCURED;
3908c2ecf20Sopenharmony_ci			amp_mgr_put(tmp);
3918c2ecf20Sopenharmony_ci		} else {
3928c2ecf20Sopenharmony_ci			rsp.status = A2MP_STATUS_INVALID_CTRL_ID;
3938c2ecf20Sopenharmony_ci		}
3948c2ecf20Sopenharmony_ci
3958c2ecf20Sopenharmony_ci		a2mp_send(mgr, A2MP_GETAMPASSOC_RSP, hdr->ident, sizeof(rsp),
3968c2ecf20Sopenharmony_ci			  &rsp);
3978c2ecf20Sopenharmony_ci
3988c2ecf20Sopenharmony_ci		goto done;
3998c2ecf20Sopenharmony_ci	}
4008c2ecf20Sopenharmony_ci
4018c2ecf20Sopenharmony_ci	amp_read_loc_assoc(hdev, mgr);
4028c2ecf20Sopenharmony_ci
4038c2ecf20Sopenharmony_cidone:
4048c2ecf20Sopenharmony_ci	if (hdev)
4058c2ecf20Sopenharmony_ci		hci_dev_put(hdev);
4068c2ecf20Sopenharmony_ci
4078c2ecf20Sopenharmony_ci	skb_pull(skb, sizeof(*req));
4088c2ecf20Sopenharmony_ci	return 0;
4098c2ecf20Sopenharmony_ci}
4108c2ecf20Sopenharmony_ci
4118c2ecf20Sopenharmony_cistatic int a2mp_getampassoc_rsp(struct amp_mgr *mgr, struct sk_buff *skb,
4128c2ecf20Sopenharmony_ci				struct a2mp_cmd *hdr)
4138c2ecf20Sopenharmony_ci{
4148c2ecf20Sopenharmony_ci	struct a2mp_amp_assoc_rsp *rsp = (void *) skb->data;
4158c2ecf20Sopenharmony_ci	u16 len = le16_to_cpu(hdr->len);
4168c2ecf20Sopenharmony_ci	struct hci_dev *hdev;
4178c2ecf20Sopenharmony_ci	struct amp_ctrl *ctrl;
4188c2ecf20Sopenharmony_ci	struct hci_conn *hcon;
4198c2ecf20Sopenharmony_ci	size_t assoc_len;
4208c2ecf20Sopenharmony_ci
4218c2ecf20Sopenharmony_ci	if (len < sizeof(*rsp))
4228c2ecf20Sopenharmony_ci		return -EINVAL;
4238c2ecf20Sopenharmony_ci
4248c2ecf20Sopenharmony_ci	assoc_len = len - sizeof(*rsp);
4258c2ecf20Sopenharmony_ci
4268c2ecf20Sopenharmony_ci	BT_DBG("id %d status 0x%2.2x assoc len %zu", rsp->id, rsp->status,
4278c2ecf20Sopenharmony_ci	       assoc_len);
4288c2ecf20Sopenharmony_ci
4298c2ecf20Sopenharmony_ci	if (rsp->status)
4308c2ecf20Sopenharmony_ci		return -EINVAL;
4318c2ecf20Sopenharmony_ci
4328c2ecf20Sopenharmony_ci	/* Save remote ASSOC data */
4338c2ecf20Sopenharmony_ci	ctrl = amp_ctrl_lookup(mgr, rsp->id);
4348c2ecf20Sopenharmony_ci	if (ctrl) {
4358c2ecf20Sopenharmony_ci		u8 *assoc;
4368c2ecf20Sopenharmony_ci
4378c2ecf20Sopenharmony_ci		assoc = kmemdup(rsp->amp_assoc, assoc_len, GFP_KERNEL);
4388c2ecf20Sopenharmony_ci		if (!assoc) {
4398c2ecf20Sopenharmony_ci			amp_ctrl_put(ctrl);
4408c2ecf20Sopenharmony_ci			return -ENOMEM;
4418c2ecf20Sopenharmony_ci		}
4428c2ecf20Sopenharmony_ci
4438c2ecf20Sopenharmony_ci		ctrl->assoc = assoc;
4448c2ecf20Sopenharmony_ci		ctrl->assoc_len = assoc_len;
4458c2ecf20Sopenharmony_ci		ctrl->assoc_rem_len = assoc_len;
4468c2ecf20Sopenharmony_ci		ctrl->assoc_len_so_far = 0;
4478c2ecf20Sopenharmony_ci
4488c2ecf20Sopenharmony_ci		amp_ctrl_put(ctrl);
4498c2ecf20Sopenharmony_ci	}
4508c2ecf20Sopenharmony_ci
4518c2ecf20Sopenharmony_ci	/* Create Phys Link */
4528c2ecf20Sopenharmony_ci	hdev = hci_dev_get(rsp->id);
4538c2ecf20Sopenharmony_ci	if (!hdev)
4548c2ecf20Sopenharmony_ci		return -EINVAL;
4558c2ecf20Sopenharmony_ci
4568c2ecf20Sopenharmony_ci	hcon = phylink_add(hdev, mgr, rsp->id, true);
4578c2ecf20Sopenharmony_ci	if (!hcon)
4588c2ecf20Sopenharmony_ci		goto done;
4598c2ecf20Sopenharmony_ci
4608c2ecf20Sopenharmony_ci	BT_DBG("Created hcon %p: loc:%d -> rem:%d", hcon, hdev->id, rsp->id);
4618c2ecf20Sopenharmony_ci
4628c2ecf20Sopenharmony_ci	mgr->bredr_chan->remote_amp_id = rsp->id;
4638c2ecf20Sopenharmony_ci
4648c2ecf20Sopenharmony_ci	amp_create_phylink(hdev, mgr, hcon);
4658c2ecf20Sopenharmony_ci
4668c2ecf20Sopenharmony_cidone:
4678c2ecf20Sopenharmony_ci	hci_dev_put(hdev);
4688c2ecf20Sopenharmony_ci	skb_pull(skb, len);
4698c2ecf20Sopenharmony_ci	return 0;
4708c2ecf20Sopenharmony_ci}
4718c2ecf20Sopenharmony_ci
4728c2ecf20Sopenharmony_cistatic int a2mp_createphyslink_req(struct amp_mgr *mgr, struct sk_buff *skb,
4738c2ecf20Sopenharmony_ci				   struct a2mp_cmd *hdr)
4748c2ecf20Sopenharmony_ci{
4758c2ecf20Sopenharmony_ci	struct a2mp_physlink_req *req = (void *) skb->data;
4768c2ecf20Sopenharmony_ci	struct a2mp_physlink_rsp rsp;
4778c2ecf20Sopenharmony_ci	struct hci_dev *hdev;
4788c2ecf20Sopenharmony_ci	struct hci_conn *hcon;
4798c2ecf20Sopenharmony_ci	struct amp_ctrl *ctrl;
4808c2ecf20Sopenharmony_ci
4818c2ecf20Sopenharmony_ci	if (le16_to_cpu(hdr->len) < sizeof(*req))
4828c2ecf20Sopenharmony_ci		return -EINVAL;
4838c2ecf20Sopenharmony_ci
4848c2ecf20Sopenharmony_ci	BT_DBG("local_id %d, remote_id %d", req->local_id, req->remote_id);
4858c2ecf20Sopenharmony_ci
4868c2ecf20Sopenharmony_ci	memset(&rsp, 0, sizeof(rsp));
4878c2ecf20Sopenharmony_ci
4888c2ecf20Sopenharmony_ci	rsp.local_id = req->remote_id;
4898c2ecf20Sopenharmony_ci	rsp.remote_id = req->local_id;
4908c2ecf20Sopenharmony_ci
4918c2ecf20Sopenharmony_ci	hdev = hci_dev_get(req->remote_id);
4928c2ecf20Sopenharmony_ci	if (!hdev || hdev->amp_type == AMP_TYPE_BREDR) {
4938c2ecf20Sopenharmony_ci		rsp.status = A2MP_STATUS_INVALID_CTRL_ID;
4948c2ecf20Sopenharmony_ci		goto send_rsp;
4958c2ecf20Sopenharmony_ci	}
4968c2ecf20Sopenharmony_ci
4978c2ecf20Sopenharmony_ci	ctrl = amp_ctrl_lookup(mgr, rsp.remote_id);
4988c2ecf20Sopenharmony_ci	if (!ctrl) {
4998c2ecf20Sopenharmony_ci		ctrl = amp_ctrl_add(mgr, rsp.remote_id);
5008c2ecf20Sopenharmony_ci		if (ctrl) {
5018c2ecf20Sopenharmony_ci			amp_ctrl_get(ctrl);
5028c2ecf20Sopenharmony_ci		} else {
5038c2ecf20Sopenharmony_ci			rsp.status = A2MP_STATUS_UNABLE_START_LINK_CREATION;
5048c2ecf20Sopenharmony_ci			goto send_rsp;
5058c2ecf20Sopenharmony_ci		}
5068c2ecf20Sopenharmony_ci	}
5078c2ecf20Sopenharmony_ci
5088c2ecf20Sopenharmony_ci	if (ctrl) {
5098c2ecf20Sopenharmony_ci		size_t assoc_len = le16_to_cpu(hdr->len) - sizeof(*req);
5108c2ecf20Sopenharmony_ci		u8 *assoc;
5118c2ecf20Sopenharmony_ci
5128c2ecf20Sopenharmony_ci		assoc = kmemdup(req->amp_assoc, assoc_len, GFP_KERNEL);
5138c2ecf20Sopenharmony_ci		if (!assoc) {
5148c2ecf20Sopenharmony_ci			amp_ctrl_put(ctrl);
5158c2ecf20Sopenharmony_ci			hci_dev_put(hdev);
5168c2ecf20Sopenharmony_ci			return -ENOMEM;
5178c2ecf20Sopenharmony_ci		}
5188c2ecf20Sopenharmony_ci
5198c2ecf20Sopenharmony_ci		ctrl->assoc = assoc;
5208c2ecf20Sopenharmony_ci		ctrl->assoc_len = assoc_len;
5218c2ecf20Sopenharmony_ci		ctrl->assoc_rem_len = assoc_len;
5228c2ecf20Sopenharmony_ci		ctrl->assoc_len_so_far = 0;
5238c2ecf20Sopenharmony_ci
5248c2ecf20Sopenharmony_ci		amp_ctrl_put(ctrl);
5258c2ecf20Sopenharmony_ci	}
5268c2ecf20Sopenharmony_ci
5278c2ecf20Sopenharmony_ci	hcon = phylink_add(hdev, mgr, req->local_id, false);
5288c2ecf20Sopenharmony_ci	if (hcon) {
5298c2ecf20Sopenharmony_ci		amp_accept_phylink(hdev, mgr, hcon);
5308c2ecf20Sopenharmony_ci		rsp.status = A2MP_STATUS_SUCCESS;
5318c2ecf20Sopenharmony_ci	} else {
5328c2ecf20Sopenharmony_ci		rsp.status = A2MP_STATUS_UNABLE_START_LINK_CREATION;
5338c2ecf20Sopenharmony_ci	}
5348c2ecf20Sopenharmony_ci
5358c2ecf20Sopenharmony_cisend_rsp:
5368c2ecf20Sopenharmony_ci	if (hdev)
5378c2ecf20Sopenharmony_ci		hci_dev_put(hdev);
5388c2ecf20Sopenharmony_ci
5398c2ecf20Sopenharmony_ci	/* Reply error now and success after HCI Write Remote AMP Assoc
5408c2ecf20Sopenharmony_ci	   command complete with success status
5418c2ecf20Sopenharmony_ci	 */
5428c2ecf20Sopenharmony_ci	if (rsp.status != A2MP_STATUS_SUCCESS) {
5438c2ecf20Sopenharmony_ci		a2mp_send(mgr, A2MP_CREATEPHYSLINK_RSP, hdr->ident,
5448c2ecf20Sopenharmony_ci			  sizeof(rsp), &rsp);
5458c2ecf20Sopenharmony_ci	} else {
5468c2ecf20Sopenharmony_ci		set_bit(WRITE_REMOTE_AMP_ASSOC, &mgr->state);
5478c2ecf20Sopenharmony_ci		mgr->ident = hdr->ident;
5488c2ecf20Sopenharmony_ci	}
5498c2ecf20Sopenharmony_ci
5508c2ecf20Sopenharmony_ci	skb_pull(skb, le16_to_cpu(hdr->len));
5518c2ecf20Sopenharmony_ci	return 0;
5528c2ecf20Sopenharmony_ci}
5538c2ecf20Sopenharmony_ci
5548c2ecf20Sopenharmony_cistatic int a2mp_discphyslink_req(struct amp_mgr *mgr, struct sk_buff *skb,
5558c2ecf20Sopenharmony_ci				 struct a2mp_cmd *hdr)
5568c2ecf20Sopenharmony_ci{
5578c2ecf20Sopenharmony_ci	struct a2mp_physlink_req *req = (void *) skb->data;
5588c2ecf20Sopenharmony_ci	struct a2mp_physlink_rsp rsp;
5598c2ecf20Sopenharmony_ci	struct hci_dev *hdev;
5608c2ecf20Sopenharmony_ci	struct hci_conn *hcon;
5618c2ecf20Sopenharmony_ci
5628c2ecf20Sopenharmony_ci	if (le16_to_cpu(hdr->len) < sizeof(*req))
5638c2ecf20Sopenharmony_ci		return -EINVAL;
5648c2ecf20Sopenharmony_ci
5658c2ecf20Sopenharmony_ci	BT_DBG("local_id %d remote_id %d", req->local_id, req->remote_id);
5668c2ecf20Sopenharmony_ci
5678c2ecf20Sopenharmony_ci	memset(&rsp, 0, sizeof(rsp));
5688c2ecf20Sopenharmony_ci
5698c2ecf20Sopenharmony_ci	rsp.local_id = req->remote_id;
5708c2ecf20Sopenharmony_ci	rsp.remote_id = req->local_id;
5718c2ecf20Sopenharmony_ci	rsp.status = A2MP_STATUS_SUCCESS;
5728c2ecf20Sopenharmony_ci
5738c2ecf20Sopenharmony_ci	hdev = hci_dev_get(req->remote_id);
5748c2ecf20Sopenharmony_ci	if (!hdev) {
5758c2ecf20Sopenharmony_ci		rsp.status = A2MP_STATUS_INVALID_CTRL_ID;
5768c2ecf20Sopenharmony_ci		goto send_rsp;
5778c2ecf20Sopenharmony_ci	}
5788c2ecf20Sopenharmony_ci
5798c2ecf20Sopenharmony_ci	hcon = hci_conn_hash_lookup_ba(hdev, AMP_LINK,
5808c2ecf20Sopenharmony_ci				       &mgr->l2cap_conn->hcon->dst);
5818c2ecf20Sopenharmony_ci	if (!hcon) {
5828c2ecf20Sopenharmony_ci		bt_dev_err(hdev, "no phys link exist");
5838c2ecf20Sopenharmony_ci		rsp.status = A2MP_STATUS_NO_PHYSICAL_LINK_EXISTS;
5848c2ecf20Sopenharmony_ci		goto clean;
5858c2ecf20Sopenharmony_ci	}
5868c2ecf20Sopenharmony_ci
5878c2ecf20Sopenharmony_ci	/* TODO Disconnect Phys Link here */
5888c2ecf20Sopenharmony_ci
5898c2ecf20Sopenharmony_ciclean:
5908c2ecf20Sopenharmony_ci	hci_dev_put(hdev);
5918c2ecf20Sopenharmony_ci
5928c2ecf20Sopenharmony_cisend_rsp:
5938c2ecf20Sopenharmony_ci	a2mp_send(mgr, A2MP_DISCONNPHYSLINK_RSP, hdr->ident, sizeof(rsp), &rsp);
5948c2ecf20Sopenharmony_ci
5958c2ecf20Sopenharmony_ci	skb_pull(skb, sizeof(*req));
5968c2ecf20Sopenharmony_ci	return 0;
5978c2ecf20Sopenharmony_ci}
5988c2ecf20Sopenharmony_ci
5998c2ecf20Sopenharmony_cistatic inline int a2mp_cmd_rsp(struct amp_mgr *mgr, struct sk_buff *skb,
6008c2ecf20Sopenharmony_ci			       struct a2mp_cmd *hdr)
6018c2ecf20Sopenharmony_ci{
6028c2ecf20Sopenharmony_ci	BT_DBG("ident %d code 0x%2.2x", hdr->ident, hdr->code);
6038c2ecf20Sopenharmony_ci
6048c2ecf20Sopenharmony_ci	skb_pull(skb, le16_to_cpu(hdr->len));
6058c2ecf20Sopenharmony_ci	return 0;
6068c2ecf20Sopenharmony_ci}
6078c2ecf20Sopenharmony_ci
6088c2ecf20Sopenharmony_ci/* Handle A2MP signalling */
6098c2ecf20Sopenharmony_cistatic int a2mp_chan_recv_cb(struct l2cap_chan *chan, struct sk_buff *skb)
6108c2ecf20Sopenharmony_ci{
6118c2ecf20Sopenharmony_ci	struct a2mp_cmd *hdr;
6128c2ecf20Sopenharmony_ci	struct amp_mgr *mgr = chan->data;
6138c2ecf20Sopenharmony_ci	int err = 0;
6148c2ecf20Sopenharmony_ci
6158c2ecf20Sopenharmony_ci	amp_mgr_get(mgr);
6168c2ecf20Sopenharmony_ci
6178c2ecf20Sopenharmony_ci	while (skb->len >= sizeof(*hdr)) {
6188c2ecf20Sopenharmony_ci		u16 len;
6198c2ecf20Sopenharmony_ci
6208c2ecf20Sopenharmony_ci		hdr = (void *) skb->data;
6218c2ecf20Sopenharmony_ci		len = le16_to_cpu(hdr->len);
6228c2ecf20Sopenharmony_ci
6238c2ecf20Sopenharmony_ci		BT_DBG("code 0x%2.2x id %d len %u", hdr->code, hdr->ident, len);
6248c2ecf20Sopenharmony_ci
6258c2ecf20Sopenharmony_ci		skb_pull(skb, sizeof(*hdr));
6268c2ecf20Sopenharmony_ci
6278c2ecf20Sopenharmony_ci		if (len > skb->len || !hdr->ident) {
6288c2ecf20Sopenharmony_ci			err = -EINVAL;
6298c2ecf20Sopenharmony_ci			break;
6308c2ecf20Sopenharmony_ci		}
6318c2ecf20Sopenharmony_ci
6328c2ecf20Sopenharmony_ci		mgr->ident = hdr->ident;
6338c2ecf20Sopenharmony_ci
6348c2ecf20Sopenharmony_ci		switch (hdr->code) {
6358c2ecf20Sopenharmony_ci		case A2MP_COMMAND_REJ:
6368c2ecf20Sopenharmony_ci			a2mp_command_rej(mgr, skb, hdr);
6378c2ecf20Sopenharmony_ci			break;
6388c2ecf20Sopenharmony_ci
6398c2ecf20Sopenharmony_ci		case A2MP_DISCOVER_REQ:
6408c2ecf20Sopenharmony_ci			err = a2mp_discover_req(mgr, skb, hdr);
6418c2ecf20Sopenharmony_ci			break;
6428c2ecf20Sopenharmony_ci
6438c2ecf20Sopenharmony_ci		case A2MP_CHANGE_NOTIFY:
6448c2ecf20Sopenharmony_ci			err = a2mp_change_notify(mgr, skb, hdr);
6458c2ecf20Sopenharmony_ci			break;
6468c2ecf20Sopenharmony_ci
6478c2ecf20Sopenharmony_ci		case A2MP_GETINFO_REQ:
6488c2ecf20Sopenharmony_ci			err = a2mp_getinfo_req(mgr, skb, hdr);
6498c2ecf20Sopenharmony_ci			break;
6508c2ecf20Sopenharmony_ci
6518c2ecf20Sopenharmony_ci		case A2MP_GETAMPASSOC_REQ:
6528c2ecf20Sopenharmony_ci			err = a2mp_getampassoc_req(mgr, skb, hdr);
6538c2ecf20Sopenharmony_ci			break;
6548c2ecf20Sopenharmony_ci
6558c2ecf20Sopenharmony_ci		case A2MP_CREATEPHYSLINK_REQ:
6568c2ecf20Sopenharmony_ci			err = a2mp_createphyslink_req(mgr, skb, hdr);
6578c2ecf20Sopenharmony_ci			break;
6588c2ecf20Sopenharmony_ci
6598c2ecf20Sopenharmony_ci		case A2MP_DISCONNPHYSLINK_REQ:
6608c2ecf20Sopenharmony_ci			err = a2mp_discphyslink_req(mgr, skb, hdr);
6618c2ecf20Sopenharmony_ci			break;
6628c2ecf20Sopenharmony_ci
6638c2ecf20Sopenharmony_ci		case A2MP_DISCOVER_RSP:
6648c2ecf20Sopenharmony_ci			err = a2mp_discover_rsp(mgr, skb, hdr);
6658c2ecf20Sopenharmony_ci			break;
6668c2ecf20Sopenharmony_ci
6678c2ecf20Sopenharmony_ci		case A2MP_GETINFO_RSP:
6688c2ecf20Sopenharmony_ci			err = a2mp_getinfo_rsp(mgr, skb, hdr);
6698c2ecf20Sopenharmony_ci			break;
6708c2ecf20Sopenharmony_ci
6718c2ecf20Sopenharmony_ci		case A2MP_GETAMPASSOC_RSP:
6728c2ecf20Sopenharmony_ci			err = a2mp_getampassoc_rsp(mgr, skb, hdr);
6738c2ecf20Sopenharmony_ci			break;
6748c2ecf20Sopenharmony_ci
6758c2ecf20Sopenharmony_ci		case A2MP_CHANGE_RSP:
6768c2ecf20Sopenharmony_ci		case A2MP_CREATEPHYSLINK_RSP:
6778c2ecf20Sopenharmony_ci		case A2MP_DISCONNPHYSLINK_RSP:
6788c2ecf20Sopenharmony_ci			err = a2mp_cmd_rsp(mgr, skb, hdr);
6798c2ecf20Sopenharmony_ci			break;
6808c2ecf20Sopenharmony_ci
6818c2ecf20Sopenharmony_ci		default:
6828c2ecf20Sopenharmony_ci			BT_ERR("Unknown A2MP sig cmd 0x%2.2x", hdr->code);
6838c2ecf20Sopenharmony_ci			err = -EINVAL;
6848c2ecf20Sopenharmony_ci			break;
6858c2ecf20Sopenharmony_ci		}
6868c2ecf20Sopenharmony_ci	}
6878c2ecf20Sopenharmony_ci
6888c2ecf20Sopenharmony_ci	if (err) {
6898c2ecf20Sopenharmony_ci		struct a2mp_cmd_rej rej;
6908c2ecf20Sopenharmony_ci
6918c2ecf20Sopenharmony_ci		memset(&rej, 0, sizeof(rej));
6928c2ecf20Sopenharmony_ci
6938c2ecf20Sopenharmony_ci		rej.reason = cpu_to_le16(0);
6948c2ecf20Sopenharmony_ci		hdr = (void *) skb->data;
6958c2ecf20Sopenharmony_ci
6968c2ecf20Sopenharmony_ci		BT_DBG("Send A2MP Rej: cmd 0x%2.2x err %d", hdr->code, err);
6978c2ecf20Sopenharmony_ci
6988c2ecf20Sopenharmony_ci		a2mp_send(mgr, A2MP_COMMAND_REJ, hdr->ident, sizeof(rej),
6998c2ecf20Sopenharmony_ci			  &rej);
7008c2ecf20Sopenharmony_ci	}
7018c2ecf20Sopenharmony_ci
7028c2ecf20Sopenharmony_ci	/* Always free skb and return success error code to prevent
7038c2ecf20Sopenharmony_ci	   from sending L2CAP Disconnect over A2MP channel */
7048c2ecf20Sopenharmony_ci	kfree_skb(skb);
7058c2ecf20Sopenharmony_ci
7068c2ecf20Sopenharmony_ci	amp_mgr_put(mgr);
7078c2ecf20Sopenharmony_ci
7088c2ecf20Sopenharmony_ci	return 0;
7098c2ecf20Sopenharmony_ci}
7108c2ecf20Sopenharmony_ci
7118c2ecf20Sopenharmony_cistatic void a2mp_chan_close_cb(struct l2cap_chan *chan)
7128c2ecf20Sopenharmony_ci{
7138c2ecf20Sopenharmony_ci	l2cap_chan_put(chan);
7148c2ecf20Sopenharmony_ci}
7158c2ecf20Sopenharmony_ci
7168c2ecf20Sopenharmony_cistatic void a2mp_chan_state_change_cb(struct l2cap_chan *chan, int state,
7178c2ecf20Sopenharmony_ci				      int err)
7188c2ecf20Sopenharmony_ci{
7198c2ecf20Sopenharmony_ci	struct amp_mgr *mgr = chan->data;
7208c2ecf20Sopenharmony_ci
7218c2ecf20Sopenharmony_ci	if (!mgr)
7228c2ecf20Sopenharmony_ci		return;
7238c2ecf20Sopenharmony_ci
7248c2ecf20Sopenharmony_ci	BT_DBG("chan %p state %s", chan, state_to_string(state));
7258c2ecf20Sopenharmony_ci
7268c2ecf20Sopenharmony_ci	chan->state = state;
7278c2ecf20Sopenharmony_ci
7288c2ecf20Sopenharmony_ci	switch (state) {
7298c2ecf20Sopenharmony_ci	case BT_CLOSED:
7308c2ecf20Sopenharmony_ci		if (mgr)
7318c2ecf20Sopenharmony_ci			amp_mgr_put(mgr);
7328c2ecf20Sopenharmony_ci		break;
7338c2ecf20Sopenharmony_ci	}
7348c2ecf20Sopenharmony_ci}
7358c2ecf20Sopenharmony_ci
7368c2ecf20Sopenharmony_cistatic struct sk_buff *a2mp_chan_alloc_skb_cb(struct l2cap_chan *chan,
7378c2ecf20Sopenharmony_ci					      unsigned long hdr_len,
7388c2ecf20Sopenharmony_ci					      unsigned long len, int nb)
7398c2ecf20Sopenharmony_ci{
7408c2ecf20Sopenharmony_ci	struct sk_buff *skb;
7418c2ecf20Sopenharmony_ci
7428c2ecf20Sopenharmony_ci	skb = bt_skb_alloc(hdr_len + len, GFP_KERNEL);
7438c2ecf20Sopenharmony_ci	if (!skb)
7448c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOMEM);
7458c2ecf20Sopenharmony_ci
7468c2ecf20Sopenharmony_ci	return skb;
7478c2ecf20Sopenharmony_ci}
7488c2ecf20Sopenharmony_ci
7498c2ecf20Sopenharmony_cistatic const struct l2cap_ops a2mp_chan_ops = {
7508c2ecf20Sopenharmony_ci	.name = "L2CAP A2MP channel",
7518c2ecf20Sopenharmony_ci	.recv = a2mp_chan_recv_cb,
7528c2ecf20Sopenharmony_ci	.close = a2mp_chan_close_cb,
7538c2ecf20Sopenharmony_ci	.state_change = a2mp_chan_state_change_cb,
7548c2ecf20Sopenharmony_ci	.alloc_skb = a2mp_chan_alloc_skb_cb,
7558c2ecf20Sopenharmony_ci
7568c2ecf20Sopenharmony_ci	/* Not implemented for A2MP */
7578c2ecf20Sopenharmony_ci	.new_connection = l2cap_chan_no_new_connection,
7588c2ecf20Sopenharmony_ci	.teardown = l2cap_chan_no_teardown,
7598c2ecf20Sopenharmony_ci	.ready = l2cap_chan_no_ready,
7608c2ecf20Sopenharmony_ci	.defer = l2cap_chan_no_defer,
7618c2ecf20Sopenharmony_ci	.resume = l2cap_chan_no_resume,
7628c2ecf20Sopenharmony_ci	.set_shutdown = l2cap_chan_no_set_shutdown,
7638c2ecf20Sopenharmony_ci	.get_sndtimeo = l2cap_chan_no_get_sndtimeo,
7648c2ecf20Sopenharmony_ci};
7658c2ecf20Sopenharmony_ci
7668c2ecf20Sopenharmony_cistatic struct l2cap_chan *a2mp_chan_open(struct l2cap_conn *conn, bool locked)
7678c2ecf20Sopenharmony_ci{
7688c2ecf20Sopenharmony_ci	struct l2cap_chan *chan;
7698c2ecf20Sopenharmony_ci	int err;
7708c2ecf20Sopenharmony_ci
7718c2ecf20Sopenharmony_ci	chan = l2cap_chan_create();
7728c2ecf20Sopenharmony_ci	if (!chan)
7738c2ecf20Sopenharmony_ci		return NULL;
7748c2ecf20Sopenharmony_ci
7758c2ecf20Sopenharmony_ci	BT_DBG("chan %p", chan);
7768c2ecf20Sopenharmony_ci
7778c2ecf20Sopenharmony_ci	chan->chan_type = L2CAP_CHAN_FIXED;
7788c2ecf20Sopenharmony_ci	chan->scid = L2CAP_CID_A2MP;
7798c2ecf20Sopenharmony_ci	chan->dcid = L2CAP_CID_A2MP;
7808c2ecf20Sopenharmony_ci	chan->omtu = L2CAP_A2MP_DEFAULT_MTU;
7818c2ecf20Sopenharmony_ci	chan->imtu = L2CAP_A2MP_DEFAULT_MTU;
7828c2ecf20Sopenharmony_ci	chan->flush_to = L2CAP_DEFAULT_FLUSH_TO;
7838c2ecf20Sopenharmony_ci
7848c2ecf20Sopenharmony_ci	chan->ops = &a2mp_chan_ops;
7858c2ecf20Sopenharmony_ci
7868c2ecf20Sopenharmony_ci	l2cap_chan_set_defaults(chan);
7878c2ecf20Sopenharmony_ci	chan->remote_max_tx = chan->max_tx;
7888c2ecf20Sopenharmony_ci	chan->remote_tx_win = chan->tx_win;
7898c2ecf20Sopenharmony_ci
7908c2ecf20Sopenharmony_ci	chan->retrans_timeout = L2CAP_DEFAULT_RETRANS_TO;
7918c2ecf20Sopenharmony_ci	chan->monitor_timeout = L2CAP_DEFAULT_MONITOR_TO;
7928c2ecf20Sopenharmony_ci
7938c2ecf20Sopenharmony_ci	skb_queue_head_init(&chan->tx_q);
7948c2ecf20Sopenharmony_ci
7958c2ecf20Sopenharmony_ci	chan->mode = L2CAP_MODE_ERTM;
7968c2ecf20Sopenharmony_ci
7978c2ecf20Sopenharmony_ci	err = l2cap_ertm_init(chan);
7988c2ecf20Sopenharmony_ci	if (err < 0) {
7998c2ecf20Sopenharmony_ci		l2cap_chan_del(chan, 0);
8008c2ecf20Sopenharmony_ci		return NULL;
8018c2ecf20Sopenharmony_ci	}
8028c2ecf20Sopenharmony_ci
8038c2ecf20Sopenharmony_ci	chan->conf_state = 0;
8048c2ecf20Sopenharmony_ci
8058c2ecf20Sopenharmony_ci	if (locked)
8068c2ecf20Sopenharmony_ci		__l2cap_chan_add(conn, chan);
8078c2ecf20Sopenharmony_ci	else
8088c2ecf20Sopenharmony_ci		l2cap_chan_add(conn, chan);
8098c2ecf20Sopenharmony_ci
8108c2ecf20Sopenharmony_ci	chan->remote_mps = chan->omtu;
8118c2ecf20Sopenharmony_ci	chan->mps = chan->omtu;
8128c2ecf20Sopenharmony_ci
8138c2ecf20Sopenharmony_ci	chan->state = BT_CONNECTED;
8148c2ecf20Sopenharmony_ci
8158c2ecf20Sopenharmony_ci	return chan;
8168c2ecf20Sopenharmony_ci}
8178c2ecf20Sopenharmony_ci
8188c2ecf20Sopenharmony_ci/* AMP Manager functions */
8198c2ecf20Sopenharmony_cistruct amp_mgr *amp_mgr_get(struct amp_mgr *mgr)
8208c2ecf20Sopenharmony_ci{
8218c2ecf20Sopenharmony_ci	BT_DBG("mgr %p orig refcnt %d", mgr, kref_read(&mgr->kref));
8228c2ecf20Sopenharmony_ci
8238c2ecf20Sopenharmony_ci	kref_get(&mgr->kref);
8248c2ecf20Sopenharmony_ci
8258c2ecf20Sopenharmony_ci	return mgr;
8268c2ecf20Sopenharmony_ci}
8278c2ecf20Sopenharmony_ci
8288c2ecf20Sopenharmony_cistatic void amp_mgr_destroy(struct kref *kref)
8298c2ecf20Sopenharmony_ci{
8308c2ecf20Sopenharmony_ci	struct amp_mgr *mgr = container_of(kref, struct amp_mgr, kref);
8318c2ecf20Sopenharmony_ci
8328c2ecf20Sopenharmony_ci	BT_DBG("mgr %p", mgr);
8338c2ecf20Sopenharmony_ci
8348c2ecf20Sopenharmony_ci	mutex_lock(&amp_mgr_list_lock);
8358c2ecf20Sopenharmony_ci	list_del(&mgr->list);
8368c2ecf20Sopenharmony_ci	mutex_unlock(&amp_mgr_list_lock);
8378c2ecf20Sopenharmony_ci
8388c2ecf20Sopenharmony_ci	amp_ctrl_list_flush(mgr);
8398c2ecf20Sopenharmony_ci	kfree(mgr);
8408c2ecf20Sopenharmony_ci}
8418c2ecf20Sopenharmony_ci
8428c2ecf20Sopenharmony_ciint amp_mgr_put(struct amp_mgr *mgr)
8438c2ecf20Sopenharmony_ci{
8448c2ecf20Sopenharmony_ci	BT_DBG("mgr %p orig refcnt %d", mgr, kref_read(&mgr->kref));
8458c2ecf20Sopenharmony_ci
8468c2ecf20Sopenharmony_ci	return kref_put(&mgr->kref, &amp_mgr_destroy);
8478c2ecf20Sopenharmony_ci}
8488c2ecf20Sopenharmony_ci
8498c2ecf20Sopenharmony_cistatic struct amp_mgr *amp_mgr_create(struct l2cap_conn *conn, bool locked)
8508c2ecf20Sopenharmony_ci{
8518c2ecf20Sopenharmony_ci	struct amp_mgr *mgr;
8528c2ecf20Sopenharmony_ci	struct l2cap_chan *chan;
8538c2ecf20Sopenharmony_ci
8548c2ecf20Sopenharmony_ci	mgr = kzalloc(sizeof(*mgr), GFP_KERNEL);
8558c2ecf20Sopenharmony_ci	if (!mgr)
8568c2ecf20Sopenharmony_ci		return NULL;
8578c2ecf20Sopenharmony_ci
8588c2ecf20Sopenharmony_ci	BT_DBG("conn %p mgr %p", conn, mgr);
8598c2ecf20Sopenharmony_ci
8608c2ecf20Sopenharmony_ci	mgr->l2cap_conn = conn;
8618c2ecf20Sopenharmony_ci
8628c2ecf20Sopenharmony_ci	chan = a2mp_chan_open(conn, locked);
8638c2ecf20Sopenharmony_ci	if (!chan) {
8648c2ecf20Sopenharmony_ci		kfree(mgr);
8658c2ecf20Sopenharmony_ci		return NULL;
8668c2ecf20Sopenharmony_ci	}
8678c2ecf20Sopenharmony_ci
8688c2ecf20Sopenharmony_ci	mgr->a2mp_chan = chan;
8698c2ecf20Sopenharmony_ci	chan->data = mgr;
8708c2ecf20Sopenharmony_ci
8718c2ecf20Sopenharmony_ci	conn->hcon->amp_mgr = mgr;
8728c2ecf20Sopenharmony_ci
8738c2ecf20Sopenharmony_ci	kref_init(&mgr->kref);
8748c2ecf20Sopenharmony_ci
8758c2ecf20Sopenharmony_ci	/* Remote AMP ctrl list initialization */
8768c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&mgr->amp_ctrls);
8778c2ecf20Sopenharmony_ci	mutex_init(&mgr->amp_ctrls_lock);
8788c2ecf20Sopenharmony_ci
8798c2ecf20Sopenharmony_ci	mutex_lock(&amp_mgr_list_lock);
8808c2ecf20Sopenharmony_ci	list_add(&mgr->list, &amp_mgr_list);
8818c2ecf20Sopenharmony_ci	mutex_unlock(&amp_mgr_list_lock);
8828c2ecf20Sopenharmony_ci
8838c2ecf20Sopenharmony_ci	return mgr;
8848c2ecf20Sopenharmony_ci}
8858c2ecf20Sopenharmony_ci
8868c2ecf20Sopenharmony_cistruct l2cap_chan *a2mp_channel_create(struct l2cap_conn *conn,
8878c2ecf20Sopenharmony_ci				       struct sk_buff *skb)
8888c2ecf20Sopenharmony_ci{
8898c2ecf20Sopenharmony_ci	struct amp_mgr *mgr;
8908c2ecf20Sopenharmony_ci
8918c2ecf20Sopenharmony_ci	if (conn->hcon->type != ACL_LINK)
8928c2ecf20Sopenharmony_ci		return NULL;
8938c2ecf20Sopenharmony_ci
8948c2ecf20Sopenharmony_ci	mgr = amp_mgr_create(conn, false);
8958c2ecf20Sopenharmony_ci	if (!mgr) {
8968c2ecf20Sopenharmony_ci		BT_ERR("Could not create AMP manager");
8978c2ecf20Sopenharmony_ci		return NULL;
8988c2ecf20Sopenharmony_ci	}
8998c2ecf20Sopenharmony_ci
9008c2ecf20Sopenharmony_ci	BT_DBG("mgr: %p chan %p", mgr, mgr->a2mp_chan);
9018c2ecf20Sopenharmony_ci
9028c2ecf20Sopenharmony_ci	return mgr->a2mp_chan;
9038c2ecf20Sopenharmony_ci}
9048c2ecf20Sopenharmony_ci
9058c2ecf20Sopenharmony_civoid a2mp_send_getinfo_rsp(struct hci_dev *hdev)
9068c2ecf20Sopenharmony_ci{
9078c2ecf20Sopenharmony_ci	struct amp_mgr *mgr;
9088c2ecf20Sopenharmony_ci	struct a2mp_info_rsp rsp;
9098c2ecf20Sopenharmony_ci
9108c2ecf20Sopenharmony_ci	mgr = amp_mgr_lookup_by_state(READ_LOC_AMP_INFO);
9118c2ecf20Sopenharmony_ci	if (!mgr)
9128c2ecf20Sopenharmony_ci		return;
9138c2ecf20Sopenharmony_ci
9148c2ecf20Sopenharmony_ci	BT_DBG("%s mgr %p", hdev->name, mgr);
9158c2ecf20Sopenharmony_ci
9168c2ecf20Sopenharmony_ci	memset(&rsp, 0, sizeof(rsp));
9178c2ecf20Sopenharmony_ci
9188c2ecf20Sopenharmony_ci	rsp.id = hdev->id;
9198c2ecf20Sopenharmony_ci	rsp.status = A2MP_STATUS_INVALID_CTRL_ID;
9208c2ecf20Sopenharmony_ci
9218c2ecf20Sopenharmony_ci	if (hdev->amp_type != AMP_TYPE_BREDR) {
9228c2ecf20Sopenharmony_ci		rsp.status = 0;
9238c2ecf20Sopenharmony_ci		rsp.total_bw = cpu_to_le32(hdev->amp_total_bw);
9248c2ecf20Sopenharmony_ci		rsp.max_bw = cpu_to_le32(hdev->amp_max_bw);
9258c2ecf20Sopenharmony_ci		rsp.min_latency = cpu_to_le32(hdev->amp_min_latency);
9268c2ecf20Sopenharmony_ci		rsp.pal_cap = cpu_to_le16(hdev->amp_pal_cap);
9278c2ecf20Sopenharmony_ci		rsp.assoc_size = cpu_to_le16(hdev->amp_assoc_size);
9288c2ecf20Sopenharmony_ci	}
9298c2ecf20Sopenharmony_ci
9308c2ecf20Sopenharmony_ci	a2mp_send(mgr, A2MP_GETINFO_RSP, mgr->ident, sizeof(rsp), &rsp);
9318c2ecf20Sopenharmony_ci	amp_mgr_put(mgr);
9328c2ecf20Sopenharmony_ci}
9338c2ecf20Sopenharmony_ci
9348c2ecf20Sopenharmony_civoid a2mp_send_getampassoc_rsp(struct hci_dev *hdev, u8 status)
9358c2ecf20Sopenharmony_ci{
9368c2ecf20Sopenharmony_ci	struct amp_mgr *mgr;
9378c2ecf20Sopenharmony_ci	struct amp_assoc *loc_assoc = &hdev->loc_assoc;
9388c2ecf20Sopenharmony_ci	struct a2mp_amp_assoc_rsp *rsp;
9398c2ecf20Sopenharmony_ci	size_t len;
9408c2ecf20Sopenharmony_ci
9418c2ecf20Sopenharmony_ci	mgr = amp_mgr_lookup_by_state(READ_LOC_AMP_ASSOC);
9428c2ecf20Sopenharmony_ci	if (!mgr)
9438c2ecf20Sopenharmony_ci		return;
9448c2ecf20Sopenharmony_ci
9458c2ecf20Sopenharmony_ci	BT_DBG("%s mgr %p", hdev->name, mgr);
9468c2ecf20Sopenharmony_ci
9478c2ecf20Sopenharmony_ci	len = sizeof(struct a2mp_amp_assoc_rsp) + loc_assoc->len;
9488c2ecf20Sopenharmony_ci	rsp = kzalloc(len, GFP_KERNEL);
9498c2ecf20Sopenharmony_ci	if (!rsp) {
9508c2ecf20Sopenharmony_ci		amp_mgr_put(mgr);
9518c2ecf20Sopenharmony_ci		return;
9528c2ecf20Sopenharmony_ci	}
9538c2ecf20Sopenharmony_ci
9548c2ecf20Sopenharmony_ci	rsp->id = hdev->id;
9558c2ecf20Sopenharmony_ci
9568c2ecf20Sopenharmony_ci	if (status) {
9578c2ecf20Sopenharmony_ci		rsp->status = A2MP_STATUS_INVALID_CTRL_ID;
9588c2ecf20Sopenharmony_ci	} else {
9598c2ecf20Sopenharmony_ci		rsp->status = A2MP_STATUS_SUCCESS;
9608c2ecf20Sopenharmony_ci		memcpy(rsp->amp_assoc, loc_assoc->data, loc_assoc->len);
9618c2ecf20Sopenharmony_ci	}
9628c2ecf20Sopenharmony_ci
9638c2ecf20Sopenharmony_ci	a2mp_send(mgr, A2MP_GETAMPASSOC_RSP, mgr->ident, len, rsp);
9648c2ecf20Sopenharmony_ci	amp_mgr_put(mgr);
9658c2ecf20Sopenharmony_ci	kfree(rsp);
9668c2ecf20Sopenharmony_ci}
9678c2ecf20Sopenharmony_ci
9688c2ecf20Sopenharmony_civoid a2mp_send_create_phy_link_req(struct hci_dev *hdev, u8 status)
9698c2ecf20Sopenharmony_ci{
9708c2ecf20Sopenharmony_ci	struct amp_mgr *mgr;
9718c2ecf20Sopenharmony_ci	struct amp_assoc *loc_assoc = &hdev->loc_assoc;
9728c2ecf20Sopenharmony_ci	struct a2mp_physlink_req *req;
9738c2ecf20Sopenharmony_ci	struct l2cap_chan *bredr_chan;
9748c2ecf20Sopenharmony_ci	size_t len;
9758c2ecf20Sopenharmony_ci
9768c2ecf20Sopenharmony_ci	mgr = amp_mgr_lookup_by_state(READ_LOC_AMP_ASSOC_FINAL);
9778c2ecf20Sopenharmony_ci	if (!mgr)
9788c2ecf20Sopenharmony_ci		return;
9798c2ecf20Sopenharmony_ci
9808c2ecf20Sopenharmony_ci	len = sizeof(*req) + loc_assoc->len;
9818c2ecf20Sopenharmony_ci
9828c2ecf20Sopenharmony_ci	BT_DBG("%s mgr %p assoc_len %zu", hdev->name, mgr, len);
9838c2ecf20Sopenharmony_ci
9848c2ecf20Sopenharmony_ci	req = kzalloc(len, GFP_KERNEL);
9858c2ecf20Sopenharmony_ci	if (!req) {
9868c2ecf20Sopenharmony_ci		amp_mgr_put(mgr);
9878c2ecf20Sopenharmony_ci		return;
9888c2ecf20Sopenharmony_ci	}
9898c2ecf20Sopenharmony_ci
9908c2ecf20Sopenharmony_ci	bredr_chan = mgr->bredr_chan;
9918c2ecf20Sopenharmony_ci	if (!bredr_chan)
9928c2ecf20Sopenharmony_ci		goto clean;
9938c2ecf20Sopenharmony_ci
9948c2ecf20Sopenharmony_ci	req->local_id = hdev->id;
9958c2ecf20Sopenharmony_ci	req->remote_id = bredr_chan->remote_amp_id;
9968c2ecf20Sopenharmony_ci	memcpy(req->amp_assoc, loc_assoc->data, loc_assoc->len);
9978c2ecf20Sopenharmony_ci
9988c2ecf20Sopenharmony_ci	a2mp_send(mgr, A2MP_CREATEPHYSLINK_REQ, __next_ident(mgr), len, req);
9998c2ecf20Sopenharmony_ci
10008c2ecf20Sopenharmony_ciclean:
10018c2ecf20Sopenharmony_ci	amp_mgr_put(mgr);
10028c2ecf20Sopenharmony_ci	kfree(req);
10038c2ecf20Sopenharmony_ci}
10048c2ecf20Sopenharmony_ci
10058c2ecf20Sopenharmony_civoid a2mp_send_create_phy_link_rsp(struct hci_dev *hdev, u8 status)
10068c2ecf20Sopenharmony_ci{
10078c2ecf20Sopenharmony_ci	struct amp_mgr *mgr;
10088c2ecf20Sopenharmony_ci	struct a2mp_physlink_rsp rsp;
10098c2ecf20Sopenharmony_ci	struct hci_conn *hs_hcon;
10108c2ecf20Sopenharmony_ci
10118c2ecf20Sopenharmony_ci	mgr = amp_mgr_lookup_by_state(WRITE_REMOTE_AMP_ASSOC);
10128c2ecf20Sopenharmony_ci	if (!mgr)
10138c2ecf20Sopenharmony_ci		return;
10148c2ecf20Sopenharmony_ci
10158c2ecf20Sopenharmony_ci	memset(&rsp, 0, sizeof(rsp));
10168c2ecf20Sopenharmony_ci
10178c2ecf20Sopenharmony_ci	hs_hcon = hci_conn_hash_lookup_state(hdev, AMP_LINK, BT_CONNECT);
10188c2ecf20Sopenharmony_ci	if (!hs_hcon) {
10198c2ecf20Sopenharmony_ci		rsp.status = A2MP_STATUS_UNABLE_START_LINK_CREATION;
10208c2ecf20Sopenharmony_ci	} else {
10218c2ecf20Sopenharmony_ci		rsp.remote_id = hs_hcon->remote_id;
10228c2ecf20Sopenharmony_ci		rsp.status = A2MP_STATUS_SUCCESS;
10238c2ecf20Sopenharmony_ci	}
10248c2ecf20Sopenharmony_ci
10258c2ecf20Sopenharmony_ci	BT_DBG("%s mgr %p hs_hcon %p status %u", hdev->name, mgr, hs_hcon,
10268c2ecf20Sopenharmony_ci	       status);
10278c2ecf20Sopenharmony_ci
10288c2ecf20Sopenharmony_ci	rsp.local_id = hdev->id;
10298c2ecf20Sopenharmony_ci	a2mp_send(mgr, A2MP_CREATEPHYSLINK_RSP, mgr->ident, sizeof(rsp), &rsp);
10308c2ecf20Sopenharmony_ci	amp_mgr_put(mgr);
10318c2ecf20Sopenharmony_ci}
10328c2ecf20Sopenharmony_ci
10338c2ecf20Sopenharmony_civoid a2mp_discover_amp(struct l2cap_chan *chan)
10348c2ecf20Sopenharmony_ci{
10358c2ecf20Sopenharmony_ci	struct l2cap_conn *conn = chan->conn;
10368c2ecf20Sopenharmony_ci	struct amp_mgr *mgr = conn->hcon->amp_mgr;
10378c2ecf20Sopenharmony_ci	struct a2mp_discov_req req;
10388c2ecf20Sopenharmony_ci
10398c2ecf20Sopenharmony_ci	BT_DBG("chan %p conn %p mgr %p", chan, conn, mgr);
10408c2ecf20Sopenharmony_ci
10418c2ecf20Sopenharmony_ci	if (!mgr) {
10428c2ecf20Sopenharmony_ci		mgr = amp_mgr_create(conn, true);
10438c2ecf20Sopenharmony_ci		if (!mgr)
10448c2ecf20Sopenharmony_ci			return;
10458c2ecf20Sopenharmony_ci	}
10468c2ecf20Sopenharmony_ci
10478c2ecf20Sopenharmony_ci	mgr->bredr_chan = chan;
10488c2ecf20Sopenharmony_ci
10498c2ecf20Sopenharmony_ci	memset(&req, 0, sizeof(req));
10508c2ecf20Sopenharmony_ci
10518c2ecf20Sopenharmony_ci	req.mtu = cpu_to_le16(L2CAP_A2MP_DEFAULT_MTU);
10528c2ecf20Sopenharmony_ci	req.ext_feat = 0;
10538c2ecf20Sopenharmony_ci	a2mp_send(mgr, A2MP_DISCOVER_REQ, 1, sizeof(req), &req);
10548c2ecf20Sopenharmony_ci}
1055