1a380b6cfSJohan Hedberg /*
2a380b6cfSJohan Hedberg BlueZ - Bluetooth protocol stack for Linux
3a380b6cfSJohan Hedberg
4a380b6cfSJohan Hedberg Copyright (C) 2015 Intel Corporation
5a380b6cfSJohan Hedberg
6a380b6cfSJohan Hedberg This program is free software; you can redistribute it and/or modify
7a380b6cfSJohan Hedberg it under the terms of the GNU General Public License version 2 as
8a380b6cfSJohan Hedberg published by the Free Software Foundation;
9a380b6cfSJohan Hedberg
10a380b6cfSJohan Hedberg THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
11a380b6cfSJohan Hedberg OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
12a380b6cfSJohan Hedberg FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
13a380b6cfSJohan Hedberg IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
14a380b6cfSJohan Hedberg CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
15a380b6cfSJohan Hedberg WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16a380b6cfSJohan Hedberg ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17a380b6cfSJohan Hedberg OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18a380b6cfSJohan Hedberg
19a380b6cfSJohan Hedberg ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
20a380b6cfSJohan Hedberg COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
21a380b6cfSJohan Hedberg SOFTWARE IS DISCLAIMED.
22a380b6cfSJohan Hedberg */
23a380b6cfSJohan Hedberg
2438ceaa00SMarcel Holtmann #include <asm/unaligned.h>
2538ceaa00SMarcel Holtmann
26a380b6cfSJohan Hedberg #include <net/bluetooth/bluetooth.h>
27a380b6cfSJohan Hedberg #include <net/bluetooth/hci_core.h>
2838ceaa00SMarcel Holtmann #include <net/bluetooth/hci_mon.h>
29a380b6cfSJohan Hedberg #include <net/bluetooth/mgmt.h>
30a380b6cfSJohan Hedberg
31a380b6cfSJohan Hedberg #include "mgmt_util.h"
32a380b6cfSJohan Hedberg
create_monitor_ctrl_event(__le16 index,u32 cookie,u16 opcode,u16 len,void * buf)3338ceaa00SMarcel Holtmann static struct sk_buff *create_monitor_ctrl_event(__le16 index, u32 cookie,
3438ceaa00SMarcel Holtmann u16 opcode, u16 len, void *buf)
3538ceaa00SMarcel Holtmann {
3638ceaa00SMarcel Holtmann struct hci_mon_hdr *hdr;
3738ceaa00SMarcel Holtmann struct sk_buff *skb;
3838ceaa00SMarcel Holtmann
3938ceaa00SMarcel Holtmann skb = bt_skb_alloc(6 + len, GFP_ATOMIC);
4038ceaa00SMarcel Holtmann if (!skb)
4138ceaa00SMarcel Holtmann return NULL;
4238ceaa00SMarcel Holtmann
4338ceaa00SMarcel Holtmann put_unaligned_le32(cookie, skb_put(skb, 4));
4438ceaa00SMarcel Holtmann put_unaligned_le16(opcode, skb_put(skb, 2));
4538ceaa00SMarcel Holtmann
4638ceaa00SMarcel Holtmann if (buf)
4759ae1d12SJohannes Berg skb_put_data(skb, buf, len);
4838ceaa00SMarcel Holtmann
4938ceaa00SMarcel Holtmann __net_timestamp(skb);
5038ceaa00SMarcel Holtmann
51d58ff351SJohannes Berg hdr = skb_push(skb, HCI_MON_HDR_SIZE);
5238ceaa00SMarcel Holtmann hdr->opcode = cpu_to_le16(HCI_MON_CTRL_EVENT);
5338ceaa00SMarcel Holtmann hdr->index = index;
5438ceaa00SMarcel Holtmann hdr->len = cpu_to_le16(skb->len - HCI_MON_HDR_SIZE);
5538ceaa00SMarcel Holtmann
5638ceaa00SMarcel Holtmann return skb;
5738ceaa00SMarcel Holtmann }
5838ceaa00SMarcel Holtmann
mgmt_alloc_skb(struct hci_dev * hdev,u16 opcode,unsigned int size)598aca46f9SLuiz Augusto von Dentz struct sk_buff *mgmt_alloc_skb(struct hci_dev *hdev, u16 opcode,
608aca46f9SLuiz Augusto von Dentz unsigned int size)
61a380b6cfSJohan Hedberg {
62a380b6cfSJohan Hedberg struct sk_buff *skb;
63a380b6cfSJohan Hedberg
648aca46f9SLuiz Augusto von Dentz skb = alloc_skb(sizeof(struct mgmt_hdr) + size, GFP_KERNEL);
65a380b6cfSJohan Hedberg if (!skb)
668aca46f9SLuiz Augusto von Dentz return skb;
67a380b6cfSJohan Hedberg
688aca46f9SLuiz Augusto von Dentz skb_reserve(skb, sizeof(struct mgmt_hdr));
698aca46f9SLuiz Augusto von Dentz bt_cb(skb)->mgmt.hdev = hdev;
708aca46f9SLuiz Augusto von Dentz bt_cb(skb)->mgmt.opcode = opcode;
71a380b6cfSJohan Hedberg
728aca46f9SLuiz Augusto von Dentz return skb;
738aca46f9SLuiz Augusto von Dentz }
748aca46f9SLuiz Augusto von Dentz
mgmt_send_event_skb(unsigned short channel,struct sk_buff * skb,int flag,struct sock * skip_sk)758aca46f9SLuiz Augusto von Dentz int mgmt_send_event_skb(unsigned short channel, struct sk_buff *skb, int flag,
768aca46f9SLuiz Augusto von Dentz struct sock *skip_sk)
778aca46f9SLuiz Augusto von Dentz {
788aca46f9SLuiz Augusto von Dentz struct hci_dev *hdev;
798aca46f9SLuiz Augusto von Dentz struct mgmt_hdr *hdr;
802e8ecb4bSWang Qing int len;
818aca46f9SLuiz Augusto von Dentz
828aca46f9SLuiz Augusto von Dentz if (!skb)
838aca46f9SLuiz Augusto von Dentz return -EINVAL;
848aca46f9SLuiz Augusto von Dentz
852e8ecb4bSWang Qing len = skb->len;
868aca46f9SLuiz Augusto von Dentz hdev = bt_cb(skb)->mgmt.hdev;
87a380b6cfSJohan Hedberg
88a380b6cfSJohan Hedberg /* Time stamp */
89a380b6cfSJohan Hedberg __net_timestamp(skb);
90a380b6cfSJohan Hedberg
918aca46f9SLuiz Augusto von Dentz /* Send just the data, without headers, to the monitor */
9238ceaa00SMarcel Holtmann if (channel == HCI_CHANNEL_CONTROL)
938aca46f9SLuiz Augusto von Dentz hci_send_monitor_ctrl_event(hdev, bt_cb(skb)->mgmt.opcode,
948aca46f9SLuiz Augusto von Dentz skb->data, skb->len,
9538ceaa00SMarcel Holtmann skb_get_ktime(skb), flag, skip_sk);
9638ceaa00SMarcel Holtmann
978aca46f9SLuiz Augusto von Dentz hdr = skb_push(skb, sizeof(*hdr));
988aca46f9SLuiz Augusto von Dentz hdr->opcode = cpu_to_le16(bt_cb(skb)->mgmt.opcode);
998aca46f9SLuiz Augusto von Dentz if (hdev)
1008aca46f9SLuiz Augusto von Dentz hdr->index = cpu_to_le16(hdev->id);
1018aca46f9SLuiz Augusto von Dentz else
1028aca46f9SLuiz Augusto von Dentz hdr->index = cpu_to_le16(MGMT_INDEX_NONE);
1038aca46f9SLuiz Augusto von Dentz hdr->len = cpu_to_le16(len);
1048aca46f9SLuiz Augusto von Dentz
1058aca46f9SLuiz Augusto von Dentz hci_send_to_channel(channel, skb, flag, skip_sk);
1068aca46f9SLuiz Augusto von Dentz
10738ceaa00SMarcel Holtmann kfree_skb(skb);
108a380b6cfSJohan Hedberg return 0;
109a380b6cfSJohan Hedberg }
110a380b6cfSJohan Hedberg
mgmt_send_event(u16 event,struct hci_dev * hdev,unsigned short channel,void * data,u16 data_len,int flag,struct sock * skip_sk)1118aca46f9SLuiz Augusto von Dentz int mgmt_send_event(u16 event, struct hci_dev *hdev, unsigned short channel,
1128aca46f9SLuiz Augusto von Dentz void *data, u16 data_len, int flag, struct sock *skip_sk)
1138aca46f9SLuiz Augusto von Dentz {
1148aca46f9SLuiz Augusto von Dentz struct sk_buff *skb;
1158aca46f9SLuiz Augusto von Dentz
1168aca46f9SLuiz Augusto von Dentz skb = mgmt_alloc_skb(hdev, event, data_len);
1178aca46f9SLuiz Augusto von Dentz if (!skb)
1188aca46f9SLuiz Augusto von Dentz return -ENOMEM;
1198aca46f9SLuiz Augusto von Dentz
1208aca46f9SLuiz Augusto von Dentz if (data)
1218aca46f9SLuiz Augusto von Dentz skb_put_data(skb, data, data_len);
1228aca46f9SLuiz Augusto von Dentz
1238aca46f9SLuiz Augusto von Dentz return mgmt_send_event_skb(channel, skb, flag, skip_sk);
1248aca46f9SLuiz Augusto von Dentz }
1258aca46f9SLuiz Augusto von Dentz
mgmt_cmd_status(struct sock * sk,u16 index,u16 cmd,u8 status)126a380b6cfSJohan Hedberg int mgmt_cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
127a380b6cfSJohan Hedberg {
12838ceaa00SMarcel Holtmann struct sk_buff *skb, *mskb;
129a380b6cfSJohan Hedberg struct mgmt_hdr *hdr;
130a380b6cfSJohan Hedberg struct mgmt_ev_cmd_status *ev;
131a380b6cfSJohan Hedberg int err;
132a380b6cfSJohan Hedberg
133a380b6cfSJohan Hedberg BT_DBG("sock %p, index %u, cmd %u, status %u", sk, index, cmd, status);
134a380b6cfSJohan Hedberg
135a380b6cfSJohan Hedberg skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_KERNEL);
136a380b6cfSJohan Hedberg if (!skb)
137a380b6cfSJohan Hedberg return -ENOMEM;
138a380b6cfSJohan Hedberg
1394df864c1SJohannes Berg hdr = skb_put(skb, sizeof(*hdr));
140a380b6cfSJohan Hedberg
141a380b6cfSJohan Hedberg hdr->opcode = cpu_to_le16(MGMT_EV_CMD_STATUS);
142a380b6cfSJohan Hedberg hdr->index = cpu_to_le16(index);
143a380b6cfSJohan Hedberg hdr->len = cpu_to_le16(sizeof(*ev));
144a380b6cfSJohan Hedberg
1454df864c1SJohannes Berg ev = skb_put(skb, sizeof(*ev));
146a380b6cfSJohan Hedberg ev->status = status;
147a380b6cfSJohan Hedberg ev->opcode = cpu_to_le16(cmd);
148a380b6cfSJohan Hedberg
14938ceaa00SMarcel Holtmann mskb = create_monitor_ctrl_event(hdr->index, hci_sock_get_cookie(sk),
15038ceaa00SMarcel Holtmann MGMT_EV_CMD_STATUS, sizeof(*ev), ev);
15138ceaa00SMarcel Holtmann if (mskb)
15238ceaa00SMarcel Holtmann skb->tstamp = mskb->tstamp;
15338ceaa00SMarcel Holtmann else
15438ceaa00SMarcel Holtmann __net_timestamp(skb);
15538ceaa00SMarcel Holtmann
156a380b6cfSJohan Hedberg err = sock_queue_rcv_skb(sk, skb);
157a380b6cfSJohan Hedberg if (err < 0)
158a380b6cfSJohan Hedberg kfree_skb(skb);
159a380b6cfSJohan Hedberg
16038ceaa00SMarcel Holtmann if (mskb) {
16138ceaa00SMarcel Holtmann hci_send_to_channel(HCI_CHANNEL_MONITOR, mskb,
16238ceaa00SMarcel Holtmann HCI_SOCK_TRUSTED, NULL);
16338ceaa00SMarcel Holtmann kfree_skb(mskb);
16438ceaa00SMarcel Holtmann }
16538ceaa00SMarcel Holtmann
166a380b6cfSJohan Hedberg return err;
167a380b6cfSJohan Hedberg }
168a380b6cfSJohan Hedberg
mgmt_cmd_complete(struct sock * sk,u16 index,u16 cmd,u8 status,void * rp,size_t rp_len)169a380b6cfSJohan Hedberg int mgmt_cmd_complete(struct sock *sk, u16 index, u16 cmd, u8 status,
170a380b6cfSJohan Hedberg void *rp, size_t rp_len)
171a380b6cfSJohan Hedberg {
17238ceaa00SMarcel Holtmann struct sk_buff *skb, *mskb;
173a380b6cfSJohan Hedberg struct mgmt_hdr *hdr;
174a380b6cfSJohan Hedberg struct mgmt_ev_cmd_complete *ev;
175a380b6cfSJohan Hedberg int err;
176a380b6cfSJohan Hedberg
177a380b6cfSJohan Hedberg BT_DBG("sock %p", sk);
178a380b6cfSJohan Hedberg
179a380b6cfSJohan Hedberg skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + rp_len, GFP_KERNEL);
180a380b6cfSJohan Hedberg if (!skb)
181a380b6cfSJohan Hedberg return -ENOMEM;
182a380b6cfSJohan Hedberg
1834df864c1SJohannes Berg hdr = skb_put(skb, sizeof(*hdr));
184a380b6cfSJohan Hedberg
185a380b6cfSJohan Hedberg hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE);
186a380b6cfSJohan Hedberg hdr->index = cpu_to_le16(index);
187a380b6cfSJohan Hedberg hdr->len = cpu_to_le16(sizeof(*ev) + rp_len);
188a380b6cfSJohan Hedberg
1894df864c1SJohannes Berg ev = skb_put(skb, sizeof(*ev) + rp_len);
190a380b6cfSJohan Hedberg ev->opcode = cpu_to_le16(cmd);
191a380b6cfSJohan Hedberg ev->status = status;
192a380b6cfSJohan Hedberg
193a380b6cfSJohan Hedberg if (rp)
194a380b6cfSJohan Hedberg memcpy(ev->data, rp, rp_len);
195a380b6cfSJohan Hedberg
19638ceaa00SMarcel Holtmann mskb = create_monitor_ctrl_event(hdr->index, hci_sock_get_cookie(sk),
19738ceaa00SMarcel Holtmann MGMT_EV_CMD_COMPLETE,
19838ceaa00SMarcel Holtmann sizeof(*ev) + rp_len, ev);
19938ceaa00SMarcel Holtmann if (mskb)
20038ceaa00SMarcel Holtmann skb->tstamp = mskb->tstamp;
20138ceaa00SMarcel Holtmann else
20238ceaa00SMarcel Holtmann __net_timestamp(skb);
20338ceaa00SMarcel Holtmann
204a380b6cfSJohan Hedberg err = sock_queue_rcv_skb(sk, skb);
205a380b6cfSJohan Hedberg if (err < 0)
206a380b6cfSJohan Hedberg kfree_skb(skb);
207a380b6cfSJohan Hedberg
20838ceaa00SMarcel Holtmann if (mskb) {
20938ceaa00SMarcel Holtmann hci_send_to_channel(HCI_CHANNEL_MONITOR, mskb,
21038ceaa00SMarcel Holtmann HCI_SOCK_TRUSTED, NULL);
21138ceaa00SMarcel Holtmann kfree_skb(mskb);
21238ceaa00SMarcel Holtmann }
21338ceaa00SMarcel Holtmann
214a380b6cfSJohan Hedberg return err;
215a380b6cfSJohan Hedberg }
216a380b6cfSJohan Hedberg
mgmt_pending_find(unsigned short channel,u16 opcode,struct hci_dev * hdev)217a380b6cfSJohan Hedberg struct mgmt_pending_cmd *mgmt_pending_find(unsigned short channel, u16 opcode,
218a380b6cfSJohan Hedberg struct hci_dev *hdev)
219a380b6cfSJohan Hedberg {
220a380b6cfSJohan Hedberg struct mgmt_pending_cmd *cmd;
221a380b6cfSJohan Hedberg
222a380b6cfSJohan Hedberg list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
223a380b6cfSJohan Hedberg if (hci_sock_get_channel(cmd->sk) != channel)
224a380b6cfSJohan Hedberg continue;
225a380b6cfSJohan Hedberg if (cmd->opcode == opcode)
226a380b6cfSJohan Hedberg return cmd;
227a380b6cfSJohan Hedberg }
228a380b6cfSJohan Hedberg
229a380b6cfSJohan Hedberg return NULL;
230a380b6cfSJohan Hedberg }
231a380b6cfSJohan Hedberg
mgmt_pending_find_data(unsigned short channel,u16 opcode,struct hci_dev * hdev,const void * data)232a380b6cfSJohan Hedberg struct mgmt_pending_cmd *mgmt_pending_find_data(unsigned short channel,
233a380b6cfSJohan Hedberg u16 opcode,
234a380b6cfSJohan Hedberg struct hci_dev *hdev,
235a380b6cfSJohan Hedberg const void *data)
236a380b6cfSJohan Hedberg {
237a380b6cfSJohan Hedberg struct mgmt_pending_cmd *cmd;
238a380b6cfSJohan Hedberg
239a380b6cfSJohan Hedberg list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
240a380b6cfSJohan Hedberg if (cmd->user_data != data)
241a380b6cfSJohan Hedberg continue;
242a380b6cfSJohan Hedberg if (cmd->opcode == opcode)
243a380b6cfSJohan Hedberg return cmd;
244a380b6cfSJohan Hedberg }
245a380b6cfSJohan Hedberg
246a380b6cfSJohan Hedberg return NULL;
247a380b6cfSJohan Hedberg }
248a380b6cfSJohan Hedberg
mgmt_pending_foreach(u16 opcode,struct hci_dev * hdev,void (* cb)(struct mgmt_pending_cmd * cmd,void * data),void * data)249a380b6cfSJohan Hedberg void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
250a380b6cfSJohan Hedberg void (*cb)(struct mgmt_pending_cmd *cmd, void *data),
251a380b6cfSJohan Hedberg void *data)
252a380b6cfSJohan Hedberg {
253a380b6cfSJohan Hedberg struct mgmt_pending_cmd *cmd, *tmp;
254a380b6cfSJohan Hedberg
255a380b6cfSJohan Hedberg list_for_each_entry_safe(cmd, tmp, &hdev->mgmt_pending, list) {
256a380b6cfSJohan Hedberg if (opcode > 0 && cmd->opcode != opcode)
257a380b6cfSJohan Hedberg continue;
258a380b6cfSJohan Hedberg
259a380b6cfSJohan Hedberg cb(cmd, data);
260a380b6cfSJohan Hedberg }
261a380b6cfSJohan Hedberg }
262a380b6cfSJohan Hedberg
mgmt_pending_new(struct sock * sk,u16 opcode,struct hci_dev * hdev,void * data,u16 len)263161510ccSLuiz Augusto von Dentz struct mgmt_pending_cmd *mgmt_pending_new(struct sock *sk, u16 opcode,
264a380b6cfSJohan Hedberg struct hci_dev *hdev,
265a380b6cfSJohan Hedberg void *data, u16 len)
266a380b6cfSJohan Hedberg {
267a380b6cfSJohan Hedberg struct mgmt_pending_cmd *cmd;
268a380b6cfSJohan Hedberg
269a380b6cfSJohan Hedberg cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
270a380b6cfSJohan Hedberg if (!cmd)
271a380b6cfSJohan Hedberg return NULL;
272a380b6cfSJohan Hedberg
273a380b6cfSJohan Hedberg cmd->opcode = opcode;
274a380b6cfSJohan Hedberg cmd->index = hdev->id;
275a380b6cfSJohan Hedberg
276a380b6cfSJohan Hedberg cmd->param = kmemdup(data, len, GFP_KERNEL);
277a380b6cfSJohan Hedberg if (!cmd->param) {
278a380b6cfSJohan Hedberg kfree(cmd);
279a380b6cfSJohan Hedberg return NULL;
280a380b6cfSJohan Hedberg }
281a380b6cfSJohan Hedberg
282a380b6cfSJohan Hedberg cmd->param_len = len;
283a380b6cfSJohan Hedberg
284a380b6cfSJohan Hedberg cmd->sk = sk;
285a380b6cfSJohan Hedberg sock_hold(sk);
286a380b6cfSJohan Hedberg
287161510ccSLuiz Augusto von Dentz return cmd;
288161510ccSLuiz Augusto von Dentz }
289161510ccSLuiz Augusto von Dentz
mgmt_pending_add(struct sock * sk,u16 opcode,struct hci_dev * hdev,void * data,u16 len)290161510ccSLuiz Augusto von Dentz struct mgmt_pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
291161510ccSLuiz Augusto von Dentz struct hci_dev *hdev,
292161510ccSLuiz Augusto von Dentz void *data, u16 len)
293161510ccSLuiz Augusto von Dentz {
294161510ccSLuiz Augusto von Dentz struct mgmt_pending_cmd *cmd;
295161510ccSLuiz Augusto von Dentz
296161510ccSLuiz Augusto von Dentz cmd = mgmt_pending_new(sk, opcode, hdev, data, len);
297161510ccSLuiz Augusto von Dentz if (!cmd)
298161510ccSLuiz Augusto von Dentz return NULL;
299161510ccSLuiz Augusto von Dentz
30031396dd5SBrian Gix list_add_tail(&cmd->list, &hdev->mgmt_pending);
301a380b6cfSJohan Hedberg
302a380b6cfSJohan Hedberg return cmd;
303a380b6cfSJohan Hedberg }
304a380b6cfSJohan Hedberg
mgmt_pending_free(struct mgmt_pending_cmd * cmd)305a380b6cfSJohan Hedberg void mgmt_pending_free(struct mgmt_pending_cmd *cmd)
306a380b6cfSJohan Hedberg {
307a380b6cfSJohan Hedberg sock_put(cmd->sk);
308a380b6cfSJohan Hedberg kfree(cmd->param);
309a380b6cfSJohan Hedberg kfree(cmd);
310a380b6cfSJohan Hedberg }
311a380b6cfSJohan Hedberg
mgmt_pending_remove(struct mgmt_pending_cmd * cmd)312a380b6cfSJohan Hedberg void mgmt_pending_remove(struct mgmt_pending_cmd *cmd)
313a380b6cfSJohan Hedberg {
314a380b6cfSJohan Hedberg list_del(&cmd->list);
315a380b6cfSJohan Hedberg mgmt_pending_free(cmd);
316a380b6cfSJohan Hedberg }
317*b338d917SBrian Gix
mgmt_mesh_foreach(struct hci_dev * hdev,void (* cb)(struct mgmt_mesh_tx * mesh_tx,void * data),void * data,struct sock * sk)318*b338d917SBrian Gix void mgmt_mesh_foreach(struct hci_dev *hdev,
319*b338d917SBrian Gix void (*cb)(struct mgmt_mesh_tx *mesh_tx, void *data),
320*b338d917SBrian Gix void *data, struct sock *sk)
321*b338d917SBrian Gix {
322*b338d917SBrian Gix struct mgmt_mesh_tx *mesh_tx, *tmp;
323*b338d917SBrian Gix
324*b338d917SBrian Gix list_for_each_entry_safe(mesh_tx, tmp, &hdev->mgmt_pending, list) {
325*b338d917SBrian Gix if (!sk || mesh_tx->sk == sk)
326*b338d917SBrian Gix cb(mesh_tx, data);
327*b338d917SBrian Gix }
328*b338d917SBrian Gix }
329*b338d917SBrian Gix
mgmt_mesh_next(struct hci_dev * hdev,struct sock * sk)330*b338d917SBrian Gix struct mgmt_mesh_tx *mgmt_mesh_next(struct hci_dev *hdev, struct sock *sk)
331*b338d917SBrian Gix {
332*b338d917SBrian Gix struct mgmt_mesh_tx *mesh_tx;
333*b338d917SBrian Gix
334*b338d917SBrian Gix if (list_empty(&hdev->mesh_pending))
335*b338d917SBrian Gix return NULL;
336*b338d917SBrian Gix
337*b338d917SBrian Gix list_for_each_entry(mesh_tx, &hdev->mesh_pending, list) {
338*b338d917SBrian Gix if (!sk || mesh_tx->sk == sk)
339*b338d917SBrian Gix return mesh_tx;
340*b338d917SBrian Gix }
341*b338d917SBrian Gix
342*b338d917SBrian Gix return NULL;
343*b338d917SBrian Gix }
344*b338d917SBrian Gix
mgmt_mesh_find(struct hci_dev * hdev,u8 handle)345*b338d917SBrian Gix struct mgmt_mesh_tx *mgmt_mesh_find(struct hci_dev *hdev, u8 handle)
346*b338d917SBrian Gix {
347*b338d917SBrian Gix struct mgmt_mesh_tx *mesh_tx;
348*b338d917SBrian Gix
349*b338d917SBrian Gix if (list_empty(&hdev->mesh_pending))
350*b338d917SBrian Gix return NULL;
351*b338d917SBrian Gix
352*b338d917SBrian Gix list_for_each_entry(mesh_tx, &hdev->mesh_pending, list) {
353*b338d917SBrian Gix if (mesh_tx->handle == handle)
354*b338d917SBrian Gix return mesh_tx;
355*b338d917SBrian Gix }
356*b338d917SBrian Gix
357*b338d917SBrian Gix return NULL;
358*b338d917SBrian Gix }
359*b338d917SBrian Gix
mgmt_mesh_add(struct sock * sk,struct hci_dev * hdev,void * data,u16 len)360*b338d917SBrian Gix struct mgmt_mesh_tx *mgmt_mesh_add(struct sock *sk, struct hci_dev *hdev,
361*b338d917SBrian Gix void *data, u16 len)
362*b338d917SBrian Gix {
363*b338d917SBrian Gix struct mgmt_mesh_tx *mesh_tx;
364*b338d917SBrian Gix
365*b338d917SBrian Gix mesh_tx = kzalloc(sizeof(*mesh_tx), GFP_KERNEL);
366*b338d917SBrian Gix if (!mesh_tx)
367*b338d917SBrian Gix return NULL;
368*b338d917SBrian Gix
369*b338d917SBrian Gix hdev->mesh_send_ref++;
370*b338d917SBrian Gix if (!hdev->mesh_send_ref)
371*b338d917SBrian Gix hdev->mesh_send_ref++;
372*b338d917SBrian Gix
373*b338d917SBrian Gix mesh_tx->handle = hdev->mesh_send_ref;
374*b338d917SBrian Gix mesh_tx->index = hdev->id;
375*b338d917SBrian Gix memcpy(mesh_tx->param, data, len);
376*b338d917SBrian Gix mesh_tx->param_len = len;
377*b338d917SBrian Gix mesh_tx->sk = sk;
378*b338d917SBrian Gix sock_hold(sk);
379*b338d917SBrian Gix
380*b338d917SBrian Gix list_add_tail(&mesh_tx->list, &hdev->mesh_pending);
381*b338d917SBrian Gix
382*b338d917SBrian Gix return mesh_tx;
383*b338d917SBrian Gix }
384*b338d917SBrian Gix
mgmt_mesh_remove(struct mgmt_mesh_tx * mesh_tx)385*b338d917SBrian Gix void mgmt_mesh_remove(struct mgmt_mesh_tx *mesh_tx)
386*b338d917SBrian Gix {
387*b338d917SBrian Gix list_del(&mesh_tx->list);
388*b338d917SBrian Gix sock_put(mesh_tx->sk);
389*b338d917SBrian Gix kfree(mesh_tx);
390*b338d917SBrian Gix }
391