1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun Copyright (c) 2011,2012 Intel Corp.
4*4882a593Smuzhiyun
5*4882a593Smuzhiyun */
6*4882a593Smuzhiyun
7*4882a593Smuzhiyun #include <net/bluetooth/bluetooth.h>
8*4882a593Smuzhiyun #include <net/bluetooth/hci.h>
9*4882a593Smuzhiyun #include <net/bluetooth/hci_core.h>
10*4882a593Smuzhiyun #include <crypto/hash.h>
11*4882a593Smuzhiyun
12*4882a593Smuzhiyun #include "hci_request.h"
13*4882a593Smuzhiyun #include "a2mp.h"
14*4882a593Smuzhiyun #include "amp.h"
15*4882a593Smuzhiyun
16*4882a593Smuzhiyun /* Remote AMP Controllers interface */
amp_ctrl_get(struct amp_ctrl * ctrl)17*4882a593Smuzhiyun void amp_ctrl_get(struct amp_ctrl *ctrl)
18*4882a593Smuzhiyun {
19*4882a593Smuzhiyun BT_DBG("ctrl %p orig refcnt %d", ctrl,
20*4882a593Smuzhiyun kref_read(&ctrl->kref));
21*4882a593Smuzhiyun
22*4882a593Smuzhiyun kref_get(&ctrl->kref);
23*4882a593Smuzhiyun }
24*4882a593Smuzhiyun
amp_ctrl_destroy(struct kref * kref)25*4882a593Smuzhiyun static void amp_ctrl_destroy(struct kref *kref)
26*4882a593Smuzhiyun {
27*4882a593Smuzhiyun struct amp_ctrl *ctrl = container_of(kref, struct amp_ctrl, kref);
28*4882a593Smuzhiyun
29*4882a593Smuzhiyun BT_DBG("ctrl %p", ctrl);
30*4882a593Smuzhiyun
31*4882a593Smuzhiyun kfree(ctrl->assoc);
32*4882a593Smuzhiyun kfree(ctrl);
33*4882a593Smuzhiyun }
34*4882a593Smuzhiyun
amp_ctrl_put(struct amp_ctrl * ctrl)35*4882a593Smuzhiyun int amp_ctrl_put(struct amp_ctrl *ctrl)
36*4882a593Smuzhiyun {
37*4882a593Smuzhiyun BT_DBG("ctrl %p orig refcnt %d", ctrl,
38*4882a593Smuzhiyun kref_read(&ctrl->kref));
39*4882a593Smuzhiyun
40*4882a593Smuzhiyun return kref_put(&ctrl->kref, &_ctrl_destroy);
41*4882a593Smuzhiyun }
42*4882a593Smuzhiyun
amp_ctrl_add(struct amp_mgr * mgr,u8 id)43*4882a593Smuzhiyun struct amp_ctrl *amp_ctrl_add(struct amp_mgr *mgr, u8 id)
44*4882a593Smuzhiyun {
45*4882a593Smuzhiyun struct amp_ctrl *ctrl;
46*4882a593Smuzhiyun
47*4882a593Smuzhiyun ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL);
48*4882a593Smuzhiyun if (!ctrl)
49*4882a593Smuzhiyun return NULL;
50*4882a593Smuzhiyun
51*4882a593Smuzhiyun kref_init(&ctrl->kref);
52*4882a593Smuzhiyun ctrl->id = id;
53*4882a593Smuzhiyun
54*4882a593Smuzhiyun mutex_lock(&mgr->amp_ctrls_lock);
55*4882a593Smuzhiyun list_add(&ctrl->list, &mgr->amp_ctrls);
56*4882a593Smuzhiyun mutex_unlock(&mgr->amp_ctrls_lock);
57*4882a593Smuzhiyun
58*4882a593Smuzhiyun BT_DBG("mgr %p ctrl %p", mgr, ctrl);
59*4882a593Smuzhiyun
60*4882a593Smuzhiyun return ctrl;
61*4882a593Smuzhiyun }
62*4882a593Smuzhiyun
amp_ctrl_list_flush(struct amp_mgr * mgr)63*4882a593Smuzhiyun void amp_ctrl_list_flush(struct amp_mgr *mgr)
64*4882a593Smuzhiyun {
65*4882a593Smuzhiyun struct amp_ctrl *ctrl, *n;
66*4882a593Smuzhiyun
67*4882a593Smuzhiyun BT_DBG("mgr %p", mgr);
68*4882a593Smuzhiyun
69*4882a593Smuzhiyun mutex_lock(&mgr->amp_ctrls_lock);
70*4882a593Smuzhiyun list_for_each_entry_safe(ctrl, n, &mgr->amp_ctrls, list) {
71*4882a593Smuzhiyun list_del(&ctrl->list);
72*4882a593Smuzhiyun amp_ctrl_put(ctrl);
73*4882a593Smuzhiyun }
74*4882a593Smuzhiyun mutex_unlock(&mgr->amp_ctrls_lock);
75*4882a593Smuzhiyun }
76*4882a593Smuzhiyun
amp_ctrl_lookup(struct amp_mgr * mgr,u8 id)77*4882a593Smuzhiyun struct amp_ctrl *amp_ctrl_lookup(struct amp_mgr *mgr, u8 id)
78*4882a593Smuzhiyun {
79*4882a593Smuzhiyun struct amp_ctrl *ctrl;
80*4882a593Smuzhiyun
81*4882a593Smuzhiyun BT_DBG("mgr %p id %d", mgr, id);
82*4882a593Smuzhiyun
83*4882a593Smuzhiyun mutex_lock(&mgr->amp_ctrls_lock);
84*4882a593Smuzhiyun list_for_each_entry(ctrl, &mgr->amp_ctrls, list) {
85*4882a593Smuzhiyun if (ctrl->id == id) {
86*4882a593Smuzhiyun amp_ctrl_get(ctrl);
87*4882a593Smuzhiyun mutex_unlock(&mgr->amp_ctrls_lock);
88*4882a593Smuzhiyun return ctrl;
89*4882a593Smuzhiyun }
90*4882a593Smuzhiyun }
91*4882a593Smuzhiyun mutex_unlock(&mgr->amp_ctrls_lock);
92*4882a593Smuzhiyun
93*4882a593Smuzhiyun return NULL;
94*4882a593Smuzhiyun }
95*4882a593Smuzhiyun
96*4882a593Smuzhiyun /* Physical Link interface */
__next_handle(struct amp_mgr * mgr)97*4882a593Smuzhiyun static u8 __next_handle(struct amp_mgr *mgr)
98*4882a593Smuzhiyun {
99*4882a593Smuzhiyun if (++mgr->handle == 0)
100*4882a593Smuzhiyun mgr->handle = 1;
101*4882a593Smuzhiyun
102*4882a593Smuzhiyun return mgr->handle;
103*4882a593Smuzhiyun }
104*4882a593Smuzhiyun
phylink_add(struct hci_dev * hdev,struct amp_mgr * mgr,u8 remote_id,bool out)105*4882a593Smuzhiyun struct hci_conn *phylink_add(struct hci_dev *hdev, struct amp_mgr *mgr,
106*4882a593Smuzhiyun u8 remote_id, bool out)
107*4882a593Smuzhiyun {
108*4882a593Smuzhiyun bdaddr_t *dst = &mgr->l2cap_conn->hcon->dst;
109*4882a593Smuzhiyun struct hci_conn *hcon;
110*4882a593Smuzhiyun u8 role = out ? HCI_ROLE_MASTER : HCI_ROLE_SLAVE;
111*4882a593Smuzhiyun
112*4882a593Smuzhiyun hcon = hci_conn_add(hdev, AMP_LINK, dst, role);
113*4882a593Smuzhiyun if (!hcon)
114*4882a593Smuzhiyun return NULL;
115*4882a593Smuzhiyun
116*4882a593Smuzhiyun BT_DBG("hcon %p dst %pMR", hcon, dst);
117*4882a593Smuzhiyun
118*4882a593Smuzhiyun hcon->state = BT_CONNECT;
119*4882a593Smuzhiyun hcon->attempt++;
120*4882a593Smuzhiyun hcon->handle = __next_handle(mgr);
121*4882a593Smuzhiyun hcon->remote_id = remote_id;
122*4882a593Smuzhiyun hcon->amp_mgr = amp_mgr_get(mgr);
123*4882a593Smuzhiyun
124*4882a593Smuzhiyun return hcon;
125*4882a593Smuzhiyun }
126*4882a593Smuzhiyun
127*4882a593Smuzhiyun /* AMP crypto key generation interface */
hmac_sha256(u8 * key,u8 ksize,char * plaintext,u8 psize,u8 * output)128*4882a593Smuzhiyun static int hmac_sha256(u8 *key, u8 ksize, char *plaintext, u8 psize, u8 *output)
129*4882a593Smuzhiyun {
130*4882a593Smuzhiyun struct crypto_shash *tfm;
131*4882a593Smuzhiyun struct shash_desc *shash;
132*4882a593Smuzhiyun int ret;
133*4882a593Smuzhiyun
134*4882a593Smuzhiyun if (!ksize)
135*4882a593Smuzhiyun return -EINVAL;
136*4882a593Smuzhiyun
137*4882a593Smuzhiyun tfm = crypto_alloc_shash("hmac(sha256)", 0, 0);
138*4882a593Smuzhiyun if (IS_ERR(tfm)) {
139*4882a593Smuzhiyun BT_DBG("crypto_alloc_ahash failed: err %ld", PTR_ERR(tfm));
140*4882a593Smuzhiyun return PTR_ERR(tfm);
141*4882a593Smuzhiyun }
142*4882a593Smuzhiyun
143*4882a593Smuzhiyun ret = crypto_shash_setkey(tfm, key, ksize);
144*4882a593Smuzhiyun if (ret) {
145*4882a593Smuzhiyun BT_DBG("crypto_ahash_setkey failed: err %d", ret);
146*4882a593Smuzhiyun goto failed;
147*4882a593Smuzhiyun }
148*4882a593Smuzhiyun
149*4882a593Smuzhiyun shash = kzalloc(sizeof(*shash) + crypto_shash_descsize(tfm),
150*4882a593Smuzhiyun GFP_KERNEL);
151*4882a593Smuzhiyun if (!shash) {
152*4882a593Smuzhiyun ret = -ENOMEM;
153*4882a593Smuzhiyun goto failed;
154*4882a593Smuzhiyun }
155*4882a593Smuzhiyun
156*4882a593Smuzhiyun shash->tfm = tfm;
157*4882a593Smuzhiyun
158*4882a593Smuzhiyun ret = crypto_shash_digest(shash, plaintext, psize, output);
159*4882a593Smuzhiyun
160*4882a593Smuzhiyun kfree(shash);
161*4882a593Smuzhiyun
162*4882a593Smuzhiyun failed:
163*4882a593Smuzhiyun crypto_free_shash(tfm);
164*4882a593Smuzhiyun return ret;
165*4882a593Smuzhiyun }
166*4882a593Smuzhiyun
phylink_gen_key(struct hci_conn * conn,u8 * data,u8 * len,u8 * type)167*4882a593Smuzhiyun int phylink_gen_key(struct hci_conn *conn, u8 *data, u8 *len, u8 *type)
168*4882a593Smuzhiyun {
169*4882a593Smuzhiyun struct hci_dev *hdev = conn->hdev;
170*4882a593Smuzhiyun struct link_key *key;
171*4882a593Smuzhiyun u8 keybuf[HCI_AMP_LINK_KEY_SIZE];
172*4882a593Smuzhiyun u8 gamp_key[HCI_AMP_LINK_KEY_SIZE];
173*4882a593Smuzhiyun int err;
174*4882a593Smuzhiyun
175*4882a593Smuzhiyun if (!hci_conn_check_link_mode(conn))
176*4882a593Smuzhiyun return -EACCES;
177*4882a593Smuzhiyun
178*4882a593Smuzhiyun BT_DBG("conn %p key_type %d", conn, conn->key_type);
179*4882a593Smuzhiyun
180*4882a593Smuzhiyun /* Legacy key */
181*4882a593Smuzhiyun if (conn->key_type < 3) {
182*4882a593Smuzhiyun bt_dev_err(hdev, "legacy key type %d", conn->key_type);
183*4882a593Smuzhiyun return -EACCES;
184*4882a593Smuzhiyun }
185*4882a593Smuzhiyun
186*4882a593Smuzhiyun *type = conn->key_type;
187*4882a593Smuzhiyun *len = HCI_AMP_LINK_KEY_SIZE;
188*4882a593Smuzhiyun
189*4882a593Smuzhiyun key = hci_find_link_key(hdev, &conn->dst);
190*4882a593Smuzhiyun if (!key) {
191*4882a593Smuzhiyun BT_DBG("No Link key for conn %p dst %pMR", conn, &conn->dst);
192*4882a593Smuzhiyun return -EACCES;
193*4882a593Smuzhiyun }
194*4882a593Smuzhiyun
195*4882a593Smuzhiyun /* BR/EDR Link Key concatenated together with itself */
196*4882a593Smuzhiyun memcpy(&keybuf[0], key->val, HCI_LINK_KEY_SIZE);
197*4882a593Smuzhiyun memcpy(&keybuf[HCI_LINK_KEY_SIZE], key->val, HCI_LINK_KEY_SIZE);
198*4882a593Smuzhiyun
199*4882a593Smuzhiyun /* Derive Generic AMP Link Key (gamp) */
200*4882a593Smuzhiyun err = hmac_sha256(keybuf, HCI_AMP_LINK_KEY_SIZE, "gamp", 4, gamp_key);
201*4882a593Smuzhiyun if (err) {
202*4882a593Smuzhiyun bt_dev_err(hdev, "could not derive Generic AMP Key: err %d", err);
203*4882a593Smuzhiyun return err;
204*4882a593Smuzhiyun }
205*4882a593Smuzhiyun
206*4882a593Smuzhiyun if (conn->key_type == HCI_LK_DEBUG_COMBINATION) {
207*4882a593Smuzhiyun BT_DBG("Use Generic AMP Key (gamp)");
208*4882a593Smuzhiyun memcpy(data, gamp_key, HCI_AMP_LINK_KEY_SIZE);
209*4882a593Smuzhiyun return err;
210*4882a593Smuzhiyun }
211*4882a593Smuzhiyun
212*4882a593Smuzhiyun /* Derive Dedicated AMP Link Key: "802b" is 802.11 PAL keyID */
213*4882a593Smuzhiyun return hmac_sha256(gamp_key, HCI_AMP_LINK_KEY_SIZE, "802b", 4, data);
214*4882a593Smuzhiyun }
215*4882a593Smuzhiyun
read_local_amp_assoc_complete(struct hci_dev * hdev,u8 status,u16 opcode,struct sk_buff * skb)216*4882a593Smuzhiyun static void read_local_amp_assoc_complete(struct hci_dev *hdev, u8 status,
217*4882a593Smuzhiyun u16 opcode, struct sk_buff *skb)
218*4882a593Smuzhiyun {
219*4882a593Smuzhiyun struct hci_rp_read_local_amp_assoc *rp = (void *)skb->data;
220*4882a593Smuzhiyun struct amp_assoc *assoc = &hdev->loc_assoc;
221*4882a593Smuzhiyun size_t rem_len, frag_len;
222*4882a593Smuzhiyun
223*4882a593Smuzhiyun BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
224*4882a593Smuzhiyun
225*4882a593Smuzhiyun if (rp->status)
226*4882a593Smuzhiyun goto send_rsp;
227*4882a593Smuzhiyun
228*4882a593Smuzhiyun frag_len = skb->len - sizeof(*rp);
229*4882a593Smuzhiyun rem_len = __le16_to_cpu(rp->rem_len);
230*4882a593Smuzhiyun
231*4882a593Smuzhiyun if (rem_len > frag_len) {
232*4882a593Smuzhiyun BT_DBG("frag_len %zu rem_len %zu", frag_len, rem_len);
233*4882a593Smuzhiyun
234*4882a593Smuzhiyun memcpy(assoc->data + assoc->offset, rp->frag, frag_len);
235*4882a593Smuzhiyun assoc->offset += frag_len;
236*4882a593Smuzhiyun
237*4882a593Smuzhiyun /* Read other fragments */
238*4882a593Smuzhiyun amp_read_loc_assoc_frag(hdev, rp->phy_handle);
239*4882a593Smuzhiyun
240*4882a593Smuzhiyun return;
241*4882a593Smuzhiyun }
242*4882a593Smuzhiyun
243*4882a593Smuzhiyun memcpy(assoc->data + assoc->offset, rp->frag, rem_len);
244*4882a593Smuzhiyun assoc->len = assoc->offset + rem_len;
245*4882a593Smuzhiyun assoc->offset = 0;
246*4882a593Smuzhiyun
247*4882a593Smuzhiyun send_rsp:
248*4882a593Smuzhiyun /* Send A2MP Rsp when all fragments are received */
249*4882a593Smuzhiyun a2mp_send_getampassoc_rsp(hdev, rp->status);
250*4882a593Smuzhiyun a2mp_send_create_phy_link_req(hdev, rp->status);
251*4882a593Smuzhiyun }
252*4882a593Smuzhiyun
amp_read_loc_assoc_frag(struct hci_dev * hdev,u8 phy_handle)253*4882a593Smuzhiyun void amp_read_loc_assoc_frag(struct hci_dev *hdev, u8 phy_handle)
254*4882a593Smuzhiyun {
255*4882a593Smuzhiyun struct hci_cp_read_local_amp_assoc cp;
256*4882a593Smuzhiyun struct amp_assoc *loc_assoc = &hdev->loc_assoc;
257*4882a593Smuzhiyun struct hci_request req;
258*4882a593Smuzhiyun int err;
259*4882a593Smuzhiyun
260*4882a593Smuzhiyun BT_DBG("%s handle %d", hdev->name, phy_handle);
261*4882a593Smuzhiyun
262*4882a593Smuzhiyun cp.phy_handle = phy_handle;
263*4882a593Smuzhiyun cp.max_len = cpu_to_le16(hdev->amp_assoc_size);
264*4882a593Smuzhiyun cp.len_so_far = cpu_to_le16(loc_assoc->offset);
265*4882a593Smuzhiyun
266*4882a593Smuzhiyun hci_req_init(&req, hdev);
267*4882a593Smuzhiyun hci_req_add(&req, HCI_OP_READ_LOCAL_AMP_ASSOC, sizeof(cp), &cp);
268*4882a593Smuzhiyun err = hci_req_run_skb(&req, read_local_amp_assoc_complete);
269*4882a593Smuzhiyun if (err < 0)
270*4882a593Smuzhiyun a2mp_send_getampassoc_rsp(hdev, A2MP_STATUS_INVALID_CTRL_ID);
271*4882a593Smuzhiyun }
272*4882a593Smuzhiyun
amp_read_loc_assoc(struct hci_dev * hdev,struct amp_mgr * mgr)273*4882a593Smuzhiyun void amp_read_loc_assoc(struct hci_dev *hdev, struct amp_mgr *mgr)
274*4882a593Smuzhiyun {
275*4882a593Smuzhiyun struct hci_cp_read_local_amp_assoc cp;
276*4882a593Smuzhiyun struct hci_request req;
277*4882a593Smuzhiyun int err;
278*4882a593Smuzhiyun
279*4882a593Smuzhiyun memset(&hdev->loc_assoc, 0, sizeof(struct amp_assoc));
280*4882a593Smuzhiyun memset(&cp, 0, sizeof(cp));
281*4882a593Smuzhiyun
282*4882a593Smuzhiyun cp.max_len = cpu_to_le16(hdev->amp_assoc_size);
283*4882a593Smuzhiyun
284*4882a593Smuzhiyun set_bit(READ_LOC_AMP_ASSOC, &mgr->state);
285*4882a593Smuzhiyun hci_req_init(&req, hdev);
286*4882a593Smuzhiyun hci_req_add(&req, HCI_OP_READ_LOCAL_AMP_ASSOC, sizeof(cp), &cp);
287*4882a593Smuzhiyun err = hci_req_run_skb(&req, read_local_amp_assoc_complete);
288*4882a593Smuzhiyun if (err < 0)
289*4882a593Smuzhiyun a2mp_send_getampassoc_rsp(hdev, A2MP_STATUS_INVALID_CTRL_ID);
290*4882a593Smuzhiyun }
291*4882a593Smuzhiyun
amp_read_loc_assoc_final_data(struct hci_dev * hdev,struct hci_conn * hcon)292*4882a593Smuzhiyun void amp_read_loc_assoc_final_data(struct hci_dev *hdev,
293*4882a593Smuzhiyun struct hci_conn *hcon)
294*4882a593Smuzhiyun {
295*4882a593Smuzhiyun struct hci_cp_read_local_amp_assoc cp;
296*4882a593Smuzhiyun struct amp_mgr *mgr = hcon->amp_mgr;
297*4882a593Smuzhiyun struct hci_request req;
298*4882a593Smuzhiyun int err;
299*4882a593Smuzhiyun
300*4882a593Smuzhiyun if (!mgr)
301*4882a593Smuzhiyun return;
302*4882a593Smuzhiyun
303*4882a593Smuzhiyun cp.phy_handle = hcon->handle;
304*4882a593Smuzhiyun cp.len_so_far = cpu_to_le16(0);
305*4882a593Smuzhiyun cp.max_len = cpu_to_le16(hdev->amp_assoc_size);
306*4882a593Smuzhiyun
307*4882a593Smuzhiyun set_bit(READ_LOC_AMP_ASSOC_FINAL, &mgr->state);
308*4882a593Smuzhiyun
309*4882a593Smuzhiyun /* Read Local AMP Assoc final link information data */
310*4882a593Smuzhiyun hci_req_init(&req, hdev);
311*4882a593Smuzhiyun hci_req_add(&req, HCI_OP_READ_LOCAL_AMP_ASSOC, sizeof(cp), &cp);
312*4882a593Smuzhiyun err = hci_req_run_skb(&req, read_local_amp_assoc_complete);
313*4882a593Smuzhiyun if (err < 0)
314*4882a593Smuzhiyun a2mp_send_getampassoc_rsp(hdev, A2MP_STATUS_INVALID_CTRL_ID);
315*4882a593Smuzhiyun }
316*4882a593Smuzhiyun
write_remote_amp_assoc_complete(struct hci_dev * hdev,u8 status,u16 opcode,struct sk_buff * skb)317*4882a593Smuzhiyun static void write_remote_amp_assoc_complete(struct hci_dev *hdev, u8 status,
318*4882a593Smuzhiyun u16 opcode, struct sk_buff *skb)
319*4882a593Smuzhiyun {
320*4882a593Smuzhiyun struct hci_rp_write_remote_amp_assoc *rp = (void *)skb->data;
321*4882a593Smuzhiyun
322*4882a593Smuzhiyun BT_DBG("%s status 0x%2.2x phy_handle 0x%2.2x",
323*4882a593Smuzhiyun hdev->name, rp->status, rp->phy_handle);
324*4882a593Smuzhiyun
325*4882a593Smuzhiyun if (rp->status)
326*4882a593Smuzhiyun return;
327*4882a593Smuzhiyun
328*4882a593Smuzhiyun amp_write_rem_assoc_continue(hdev, rp->phy_handle);
329*4882a593Smuzhiyun }
330*4882a593Smuzhiyun
331*4882a593Smuzhiyun /* Write AMP Assoc data fragments, returns true with last fragment written*/
amp_write_rem_assoc_frag(struct hci_dev * hdev,struct hci_conn * hcon)332*4882a593Smuzhiyun static bool amp_write_rem_assoc_frag(struct hci_dev *hdev,
333*4882a593Smuzhiyun struct hci_conn *hcon)
334*4882a593Smuzhiyun {
335*4882a593Smuzhiyun struct hci_cp_write_remote_amp_assoc *cp;
336*4882a593Smuzhiyun struct amp_mgr *mgr = hcon->amp_mgr;
337*4882a593Smuzhiyun struct amp_ctrl *ctrl;
338*4882a593Smuzhiyun struct hci_request req;
339*4882a593Smuzhiyun u16 frag_len, len;
340*4882a593Smuzhiyun
341*4882a593Smuzhiyun ctrl = amp_ctrl_lookup(mgr, hcon->remote_id);
342*4882a593Smuzhiyun if (!ctrl)
343*4882a593Smuzhiyun return false;
344*4882a593Smuzhiyun
345*4882a593Smuzhiyun if (!ctrl->assoc_rem_len) {
346*4882a593Smuzhiyun BT_DBG("all fragments are written");
347*4882a593Smuzhiyun ctrl->assoc_rem_len = ctrl->assoc_len;
348*4882a593Smuzhiyun ctrl->assoc_len_so_far = 0;
349*4882a593Smuzhiyun
350*4882a593Smuzhiyun amp_ctrl_put(ctrl);
351*4882a593Smuzhiyun return true;
352*4882a593Smuzhiyun }
353*4882a593Smuzhiyun
354*4882a593Smuzhiyun frag_len = min_t(u16, 248, ctrl->assoc_rem_len);
355*4882a593Smuzhiyun len = frag_len + sizeof(*cp);
356*4882a593Smuzhiyun
357*4882a593Smuzhiyun cp = kzalloc(len, GFP_KERNEL);
358*4882a593Smuzhiyun if (!cp) {
359*4882a593Smuzhiyun amp_ctrl_put(ctrl);
360*4882a593Smuzhiyun return false;
361*4882a593Smuzhiyun }
362*4882a593Smuzhiyun
363*4882a593Smuzhiyun BT_DBG("hcon %p ctrl %p frag_len %u assoc_len %u rem_len %u",
364*4882a593Smuzhiyun hcon, ctrl, frag_len, ctrl->assoc_len, ctrl->assoc_rem_len);
365*4882a593Smuzhiyun
366*4882a593Smuzhiyun cp->phy_handle = hcon->handle;
367*4882a593Smuzhiyun cp->len_so_far = cpu_to_le16(ctrl->assoc_len_so_far);
368*4882a593Smuzhiyun cp->rem_len = cpu_to_le16(ctrl->assoc_rem_len);
369*4882a593Smuzhiyun memcpy(cp->frag, ctrl->assoc, frag_len);
370*4882a593Smuzhiyun
371*4882a593Smuzhiyun ctrl->assoc_len_so_far += frag_len;
372*4882a593Smuzhiyun ctrl->assoc_rem_len -= frag_len;
373*4882a593Smuzhiyun
374*4882a593Smuzhiyun amp_ctrl_put(ctrl);
375*4882a593Smuzhiyun
376*4882a593Smuzhiyun hci_req_init(&req, hdev);
377*4882a593Smuzhiyun hci_req_add(&req, HCI_OP_WRITE_REMOTE_AMP_ASSOC, len, cp);
378*4882a593Smuzhiyun hci_req_run_skb(&req, write_remote_amp_assoc_complete);
379*4882a593Smuzhiyun
380*4882a593Smuzhiyun kfree(cp);
381*4882a593Smuzhiyun
382*4882a593Smuzhiyun return false;
383*4882a593Smuzhiyun }
384*4882a593Smuzhiyun
amp_write_rem_assoc_continue(struct hci_dev * hdev,u8 handle)385*4882a593Smuzhiyun void amp_write_rem_assoc_continue(struct hci_dev *hdev, u8 handle)
386*4882a593Smuzhiyun {
387*4882a593Smuzhiyun struct hci_conn *hcon;
388*4882a593Smuzhiyun
389*4882a593Smuzhiyun BT_DBG("%s phy handle 0x%2.2x", hdev->name, handle);
390*4882a593Smuzhiyun
391*4882a593Smuzhiyun hcon = hci_conn_hash_lookup_handle(hdev, handle);
392*4882a593Smuzhiyun if (!hcon)
393*4882a593Smuzhiyun return;
394*4882a593Smuzhiyun
395*4882a593Smuzhiyun /* Send A2MP create phylink rsp when all fragments are written */
396*4882a593Smuzhiyun if (amp_write_rem_assoc_frag(hdev, hcon))
397*4882a593Smuzhiyun a2mp_send_create_phy_link_rsp(hdev, 0);
398*4882a593Smuzhiyun }
399*4882a593Smuzhiyun
amp_write_remote_assoc(struct hci_dev * hdev,u8 handle)400*4882a593Smuzhiyun void amp_write_remote_assoc(struct hci_dev *hdev, u8 handle)
401*4882a593Smuzhiyun {
402*4882a593Smuzhiyun struct hci_conn *hcon;
403*4882a593Smuzhiyun
404*4882a593Smuzhiyun BT_DBG("%s phy handle 0x%2.2x", hdev->name, handle);
405*4882a593Smuzhiyun
406*4882a593Smuzhiyun hcon = hci_conn_hash_lookup_handle(hdev, handle);
407*4882a593Smuzhiyun if (!hcon)
408*4882a593Smuzhiyun return;
409*4882a593Smuzhiyun
410*4882a593Smuzhiyun BT_DBG("%s phy handle 0x%2.2x hcon %p", hdev->name, handle, hcon);
411*4882a593Smuzhiyun
412*4882a593Smuzhiyun amp_write_rem_assoc_frag(hdev, hcon);
413*4882a593Smuzhiyun }
414*4882a593Smuzhiyun
create_phylink_complete(struct hci_dev * hdev,u8 status,u16 opcode)415*4882a593Smuzhiyun static void create_phylink_complete(struct hci_dev *hdev, u8 status,
416*4882a593Smuzhiyun u16 opcode)
417*4882a593Smuzhiyun {
418*4882a593Smuzhiyun struct hci_cp_create_phy_link *cp;
419*4882a593Smuzhiyun
420*4882a593Smuzhiyun BT_DBG("%s status 0x%2.2x", hdev->name, status);
421*4882a593Smuzhiyun
422*4882a593Smuzhiyun cp = hci_sent_cmd_data(hdev, HCI_OP_CREATE_PHY_LINK);
423*4882a593Smuzhiyun if (!cp)
424*4882a593Smuzhiyun return;
425*4882a593Smuzhiyun
426*4882a593Smuzhiyun hci_dev_lock(hdev);
427*4882a593Smuzhiyun
428*4882a593Smuzhiyun if (status) {
429*4882a593Smuzhiyun struct hci_conn *hcon;
430*4882a593Smuzhiyun
431*4882a593Smuzhiyun hcon = hci_conn_hash_lookup_handle(hdev, cp->phy_handle);
432*4882a593Smuzhiyun if (hcon)
433*4882a593Smuzhiyun hci_conn_del(hcon);
434*4882a593Smuzhiyun } else {
435*4882a593Smuzhiyun amp_write_remote_assoc(hdev, cp->phy_handle);
436*4882a593Smuzhiyun }
437*4882a593Smuzhiyun
438*4882a593Smuzhiyun hci_dev_unlock(hdev);
439*4882a593Smuzhiyun }
440*4882a593Smuzhiyun
amp_create_phylink(struct hci_dev * hdev,struct amp_mgr * mgr,struct hci_conn * hcon)441*4882a593Smuzhiyun void amp_create_phylink(struct hci_dev *hdev, struct amp_mgr *mgr,
442*4882a593Smuzhiyun struct hci_conn *hcon)
443*4882a593Smuzhiyun {
444*4882a593Smuzhiyun struct hci_cp_create_phy_link cp;
445*4882a593Smuzhiyun struct hci_request req;
446*4882a593Smuzhiyun
447*4882a593Smuzhiyun cp.phy_handle = hcon->handle;
448*4882a593Smuzhiyun
449*4882a593Smuzhiyun BT_DBG("%s hcon %p phy handle 0x%2.2x", hdev->name, hcon,
450*4882a593Smuzhiyun hcon->handle);
451*4882a593Smuzhiyun
452*4882a593Smuzhiyun if (phylink_gen_key(mgr->l2cap_conn->hcon, cp.key, &cp.key_len,
453*4882a593Smuzhiyun &cp.key_type)) {
454*4882a593Smuzhiyun BT_DBG("Cannot create link key");
455*4882a593Smuzhiyun return;
456*4882a593Smuzhiyun }
457*4882a593Smuzhiyun
458*4882a593Smuzhiyun hci_req_init(&req, hdev);
459*4882a593Smuzhiyun hci_req_add(&req, HCI_OP_CREATE_PHY_LINK, sizeof(cp), &cp);
460*4882a593Smuzhiyun hci_req_run(&req, create_phylink_complete);
461*4882a593Smuzhiyun }
462*4882a593Smuzhiyun
accept_phylink_complete(struct hci_dev * hdev,u8 status,u16 opcode)463*4882a593Smuzhiyun static void accept_phylink_complete(struct hci_dev *hdev, u8 status,
464*4882a593Smuzhiyun u16 opcode)
465*4882a593Smuzhiyun {
466*4882a593Smuzhiyun struct hci_cp_accept_phy_link *cp;
467*4882a593Smuzhiyun
468*4882a593Smuzhiyun BT_DBG("%s status 0x%2.2x", hdev->name, status);
469*4882a593Smuzhiyun
470*4882a593Smuzhiyun if (status)
471*4882a593Smuzhiyun return;
472*4882a593Smuzhiyun
473*4882a593Smuzhiyun cp = hci_sent_cmd_data(hdev, HCI_OP_ACCEPT_PHY_LINK);
474*4882a593Smuzhiyun if (!cp)
475*4882a593Smuzhiyun return;
476*4882a593Smuzhiyun
477*4882a593Smuzhiyun amp_write_remote_assoc(hdev, cp->phy_handle);
478*4882a593Smuzhiyun }
479*4882a593Smuzhiyun
amp_accept_phylink(struct hci_dev * hdev,struct amp_mgr * mgr,struct hci_conn * hcon)480*4882a593Smuzhiyun void amp_accept_phylink(struct hci_dev *hdev, struct amp_mgr *mgr,
481*4882a593Smuzhiyun struct hci_conn *hcon)
482*4882a593Smuzhiyun {
483*4882a593Smuzhiyun struct hci_cp_accept_phy_link cp;
484*4882a593Smuzhiyun struct hci_request req;
485*4882a593Smuzhiyun
486*4882a593Smuzhiyun cp.phy_handle = hcon->handle;
487*4882a593Smuzhiyun
488*4882a593Smuzhiyun BT_DBG("%s hcon %p phy handle 0x%2.2x", hdev->name, hcon,
489*4882a593Smuzhiyun hcon->handle);
490*4882a593Smuzhiyun
491*4882a593Smuzhiyun if (phylink_gen_key(mgr->l2cap_conn->hcon, cp.key, &cp.key_len,
492*4882a593Smuzhiyun &cp.key_type)) {
493*4882a593Smuzhiyun BT_DBG("Cannot create link key");
494*4882a593Smuzhiyun return;
495*4882a593Smuzhiyun }
496*4882a593Smuzhiyun
497*4882a593Smuzhiyun hci_req_init(&req, hdev);
498*4882a593Smuzhiyun hci_req_add(&req, HCI_OP_ACCEPT_PHY_LINK, sizeof(cp), &cp);
499*4882a593Smuzhiyun hci_req_run(&req, accept_phylink_complete);
500*4882a593Smuzhiyun }
501*4882a593Smuzhiyun
amp_physical_cfm(struct hci_conn * bredr_hcon,struct hci_conn * hs_hcon)502*4882a593Smuzhiyun void amp_physical_cfm(struct hci_conn *bredr_hcon, struct hci_conn *hs_hcon)
503*4882a593Smuzhiyun {
504*4882a593Smuzhiyun struct hci_dev *bredr_hdev = hci_dev_hold(bredr_hcon->hdev);
505*4882a593Smuzhiyun struct amp_mgr *mgr = hs_hcon->amp_mgr;
506*4882a593Smuzhiyun struct l2cap_chan *bredr_chan;
507*4882a593Smuzhiyun
508*4882a593Smuzhiyun BT_DBG("bredr_hcon %p hs_hcon %p mgr %p", bredr_hcon, hs_hcon, mgr);
509*4882a593Smuzhiyun
510*4882a593Smuzhiyun if (!bredr_hdev || !mgr || !mgr->bredr_chan)
511*4882a593Smuzhiyun return;
512*4882a593Smuzhiyun
513*4882a593Smuzhiyun bredr_chan = mgr->bredr_chan;
514*4882a593Smuzhiyun
515*4882a593Smuzhiyun l2cap_chan_lock(bredr_chan);
516*4882a593Smuzhiyun
517*4882a593Smuzhiyun set_bit(FLAG_EFS_ENABLE, &bredr_chan->flags);
518*4882a593Smuzhiyun bredr_chan->remote_amp_id = hs_hcon->remote_id;
519*4882a593Smuzhiyun bredr_chan->local_amp_id = hs_hcon->hdev->id;
520*4882a593Smuzhiyun bredr_chan->hs_hcon = hs_hcon;
521*4882a593Smuzhiyun bredr_chan->conn->mtu = hs_hcon->hdev->block_mtu;
522*4882a593Smuzhiyun
523*4882a593Smuzhiyun __l2cap_physical_cfm(bredr_chan, 0);
524*4882a593Smuzhiyun
525*4882a593Smuzhiyun l2cap_chan_unlock(bredr_chan);
526*4882a593Smuzhiyun
527*4882a593Smuzhiyun hci_dev_put(bredr_hdev);
528*4882a593Smuzhiyun }
529*4882a593Smuzhiyun
amp_create_logical_link(struct l2cap_chan * chan)530*4882a593Smuzhiyun void amp_create_logical_link(struct l2cap_chan *chan)
531*4882a593Smuzhiyun {
532*4882a593Smuzhiyun struct hci_conn *hs_hcon = chan->hs_hcon;
533*4882a593Smuzhiyun struct hci_cp_create_accept_logical_link cp;
534*4882a593Smuzhiyun struct hci_dev *hdev;
535*4882a593Smuzhiyun
536*4882a593Smuzhiyun BT_DBG("chan %p hs_hcon %p dst %pMR", chan, hs_hcon,
537*4882a593Smuzhiyun &chan->conn->hcon->dst);
538*4882a593Smuzhiyun
539*4882a593Smuzhiyun if (!hs_hcon)
540*4882a593Smuzhiyun return;
541*4882a593Smuzhiyun
542*4882a593Smuzhiyun hdev = hci_dev_hold(chan->hs_hcon->hdev);
543*4882a593Smuzhiyun if (!hdev)
544*4882a593Smuzhiyun return;
545*4882a593Smuzhiyun
546*4882a593Smuzhiyun cp.phy_handle = hs_hcon->handle;
547*4882a593Smuzhiyun
548*4882a593Smuzhiyun cp.tx_flow_spec.id = chan->local_id;
549*4882a593Smuzhiyun cp.tx_flow_spec.stype = chan->local_stype;
550*4882a593Smuzhiyun cp.tx_flow_spec.msdu = cpu_to_le16(chan->local_msdu);
551*4882a593Smuzhiyun cp.tx_flow_spec.sdu_itime = cpu_to_le32(chan->local_sdu_itime);
552*4882a593Smuzhiyun cp.tx_flow_spec.acc_lat = cpu_to_le32(chan->local_acc_lat);
553*4882a593Smuzhiyun cp.tx_flow_spec.flush_to = cpu_to_le32(chan->local_flush_to);
554*4882a593Smuzhiyun
555*4882a593Smuzhiyun cp.rx_flow_spec.id = chan->remote_id;
556*4882a593Smuzhiyun cp.rx_flow_spec.stype = chan->remote_stype;
557*4882a593Smuzhiyun cp.rx_flow_spec.msdu = cpu_to_le16(chan->remote_msdu);
558*4882a593Smuzhiyun cp.rx_flow_spec.sdu_itime = cpu_to_le32(chan->remote_sdu_itime);
559*4882a593Smuzhiyun cp.rx_flow_spec.acc_lat = cpu_to_le32(chan->remote_acc_lat);
560*4882a593Smuzhiyun cp.rx_flow_spec.flush_to = cpu_to_le32(chan->remote_flush_to);
561*4882a593Smuzhiyun
562*4882a593Smuzhiyun if (hs_hcon->out)
563*4882a593Smuzhiyun hci_send_cmd(hdev, HCI_OP_CREATE_LOGICAL_LINK, sizeof(cp),
564*4882a593Smuzhiyun &cp);
565*4882a593Smuzhiyun else
566*4882a593Smuzhiyun hci_send_cmd(hdev, HCI_OP_ACCEPT_LOGICAL_LINK, sizeof(cp),
567*4882a593Smuzhiyun &cp);
568*4882a593Smuzhiyun
569*4882a593Smuzhiyun hci_dev_put(hdev);
570*4882a593Smuzhiyun }
571*4882a593Smuzhiyun
amp_disconnect_logical_link(struct hci_chan * hchan)572*4882a593Smuzhiyun void amp_disconnect_logical_link(struct hci_chan *hchan)
573*4882a593Smuzhiyun {
574*4882a593Smuzhiyun struct hci_conn *hcon = hchan->conn;
575*4882a593Smuzhiyun struct hci_cp_disconn_logical_link cp;
576*4882a593Smuzhiyun
577*4882a593Smuzhiyun if (hcon->state != BT_CONNECTED) {
578*4882a593Smuzhiyun BT_DBG("hchan %p not connected", hchan);
579*4882a593Smuzhiyun return;
580*4882a593Smuzhiyun }
581*4882a593Smuzhiyun
582*4882a593Smuzhiyun cp.log_handle = cpu_to_le16(hchan->handle);
583*4882a593Smuzhiyun hci_send_cmd(hcon->hdev, HCI_OP_DISCONN_LOGICAL_LINK, sizeof(cp), &cp);
584*4882a593Smuzhiyun }
585*4882a593Smuzhiyun
amp_destroy_logical_link(struct hci_chan * hchan,u8 reason)586*4882a593Smuzhiyun void amp_destroy_logical_link(struct hci_chan *hchan, u8 reason)
587*4882a593Smuzhiyun {
588*4882a593Smuzhiyun BT_DBG("hchan %p", hchan);
589*4882a593Smuzhiyun
590*4882a593Smuzhiyun hci_chan_del(hchan);
591*4882a593Smuzhiyun }
592