crypto: lrw - Add dependency on ecb
[linux-block.git] / net / bluetooth / mgmt_util.c
CommitLineData
a380b6cf
JH
1/*
2 BlueZ - Bluetooth protocol stack for Linux
3
4 Copyright (C) 2015 Intel Corporation
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License version 2 as
8 published by the Free Software Foundation;
9
10 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
11 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
12 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
13 IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
14 CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
15 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18
19 ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
20 COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
21 SOFTWARE IS DISCLAIMED.
22*/
23
38ceaa00
MH
24#include <asm/unaligned.h>
25
a380b6cf
JH
26#include <net/bluetooth/bluetooth.h>
27#include <net/bluetooth/hci_core.h>
38ceaa00 28#include <net/bluetooth/hci_mon.h>
a380b6cf
JH
29#include <net/bluetooth/mgmt.h>
30
31#include "mgmt_util.h"
32
38ceaa00
MH
33static struct sk_buff *create_monitor_ctrl_event(__le16 index, u32 cookie,
34 u16 opcode, u16 len, void *buf)
35{
36 struct hci_mon_hdr *hdr;
37 struct sk_buff *skb;
38
39 skb = bt_skb_alloc(6 + len, GFP_ATOMIC);
40 if (!skb)
41 return NULL;
42
43 put_unaligned_le32(cookie, skb_put(skb, 4));
44 put_unaligned_le16(opcode, skb_put(skb, 2));
45
46 if (buf)
59ae1d12 47 skb_put_data(skb, buf, len);
38ceaa00
MH
48
49 __net_timestamp(skb);
50
d58ff351 51 hdr = skb_push(skb, HCI_MON_HDR_SIZE);
38ceaa00
MH
52 hdr->opcode = cpu_to_le16(HCI_MON_CTRL_EVENT);
53 hdr->index = index;
54 hdr->len = cpu_to_le16(skb->len - HCI_MON_HDR_SIZE);
55
56 return skb;
57}
58
8aca46f9
LAD
59struct sk_buff *mgmt_alloc_skb(struct hci_dev *hdev, u16 opcode,
60 unsigned int size)
a380b6cf
JH
61{
62 struct sk_buff *skb;
a380b6cf 63
8aca46f9 64 skb = alloc_skb(sizeof(struct mgmt_hdr) + size, GFP_KERNEL);
a380b6cf 65 if (!skb)
8aca46f9 66 return skb;
a380b6cf 67
8aca46f9
LAD
68 skb_reserve(skb, sizeof(struct mgmt_hdr));
69 bt_cb(skb)->mgmt.hdev = hdev;
70 bt_cb(skb)->mgmt.opcode = opcode;
a380b6cf 71
8aca46f9
LAD
72 return skb;
73}
74
75int mgmt_send_event_skb(unsigned short channel, struct sk_buff *skb, int flag,
76 struct sock *skip_sk)
77{
78 struct hci_dev *hdev;
79 struct mgmt_hdr *hdr;
80 int len = skb->len;
81
82 if (!skb)
83 return -EINVAL;
84
85 hdev = bt_cb(skb)->mgmt.hdev;
a380b6cf
JH
86
87 /* Time stamp */
88 __net_timestamp(skb);
89
8aca46f9 90 /* Send just the data, without headers, to the monitor */
38ceaa00 91 if (channel == HCI_CHANNEL_CONTROL)
8aca46f9
LAD
92 hci_send_monitor_ctrl_event(hdev, bt_cb(skb)->mgmt.opcode,
93 skb->data, skb->len,
38ceaa00
MH
94 skb_get_ktime(skb), flag, skip_sk);
95
8aca46f9
LAD
96 hdr = skb_push(skb, sizeof(*hdr));
97 hdr->opcode = cpu_to_le16(bt_cb(skb)->mgmt.opcode);
98 if (hdev)
99 hdr->index = cpu_to_le16(hdev->id);
100 else
101 hdr->index = cpu_to_le16(MGMT_INDEX_NONE);
102 hdr->len = cpu_to_le16(len);
103
104 hci_send_to_channel(channel, skb, flag, skip_sk);
105
38ceaa00 106 kfree_skb(skb);
a380b6cf
JH
107 return 0;
108}
109
8aca46f9
LAD
110int mgmt_send_event(u16 event, struct hci_dev *hdev, unsigned short channel,
111 void *data, u16 data_len, int flag, struct sock *skip_sk)
112{
113 struct sk_buff *skb;
114
115 skb = mgmt_alloc_skb(hdev, event, data_len);
116 if (!skb)
117 return -ENOMEM;
118
119 if (data)
120 skb_put_data(skb, data, data_len);
121
122 return mgmt_send_event_skb(channel, skb, flag, skip_sk);
123}
124
a380b6cf
JH
125int mgmt_cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
126{
38ceaa00 127 struct sk_buff *skb, *mskb;
a380b6cf
JH
128 struct mgmt_hdr *hdr;
129 struct mgmt_ev_cmd_status *ev;
130 int err;
131
132 BT_DBG("sock %p, index %u, cmd %u, status %u", sk, index, cmd, status);
133
134 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_KERNEL);
135 if (!skb)
136 return -ENOMEM;
137
4df864c1 138 hdr = skb_put(skb, sizeof(*hdr));
a380b6cf
JH
139
140 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_STATUS);
141 hdr->index = cpu_to_le16(index);
142 hdr->len = cpu_to_le16(sizeof(*ev));
143
4df864c1 144 ev = skb_put(skb, sizeof(*ev));
a380b6cf
JH
145 ev->status = status;
146 ev->opcode = cpu_to_le16(cmd);
147
38ceaa00
MH
148 mskb = create_monitor_ctrl_event(hdr->index, hci_sock_get_cookie(sk),
149 MGMT_EV_CMD_STATUS, sizeof(*ev), ev);
150 if (mskb)
151 skb->tstamp = mskb->tstamp;
152 else
153 __net_timestamp(skb);
154
a380b6cf
JH
155 err = sock_queue_rcv_skb(sk, skb);
156 if (err < 0)
157 kfree_skb(skb);
158
38ceaa00
MH
159 if (mskb) {
160 hci_send_to_channel(HCI_CHANNEL_MONITOR, mskb,
161 HCI_SOCK_TRUSTED, NULL);
162 kfree_skb(mskb);
163 }
164
a380b6cf
JH
165 return err;
166}
167
168int mgmt_cmd_complete(struct sock *sk, u16 index, u16 cmd, u8 status,
169 void *rp, size_t rp_len)
170{
38ceaa00 171 struct sk_buff *skb, *mskb;
a380b6cf
JH
172 struct mgmt_hdr *hdr;
173 struct mgmt_ev_cmd_complete *ev;
174 int err;
175
176 BT_DBG("sock %p", sk);
177
178 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + rp_len, GFP_KERNEL);
179 if (!skb)
180 return -ENOMEM;
181
4df864c1 182 hdr = skb_put(skb, sizeof(*hdr));
a380b6cf
JH
183
184 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE);
185 hdr->index = cpu_to_le16(index);
186 hdr->len = cpu_to_le16(sizeof(*ev) + rp_len);
187
4df864c1 188 ev = skb_put(skb, sizeof(*ev) + rp_len);
a380b6cf
JH
189 ev->opcode = cpu_to_le16(cmd);
190 ev->status = status;
191
192 if (rp)
193 memcpy(ev->data, rp, rp_len);
194
38ceaa00
MH
195 mskb = create_monitor_ctrl_event(hdr->index, hci_sock_get_cookie(sk),
196 MGMT_EV_CMD_COMPLETE,
197 sizeof(*ev) + rp_len, ev);
198 if (mskb)
199 skb->tstamp = mskb->tstamp;
200 else
201 __net_timestamp(skb);
202
a380b6cf
JH
203 err = sock_queue_rcv_skb(sk, skb);
204 if (err < 0)
205 kfree_skb(skb);
206
38ceaa00
MH
207 if (mskb) {
208 hci_send_to_channel(HCI_CHANNEL_MONITOR, mskb,
209 HCI_SOCK_TRUSTED, NULL);
210 kfree_skb(mskb);
211 }
212
a380b6cf
JH
213 return err;
214}
215
216struct mgmt_pending_cmd *mgmt_pending_find(unsigned short channel, u16 opcode,
217 struct hci_dev *hdev)
218{
219 struct mgmt_pending_cmd *cmd;
220
221 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
222 if (hci_sock_get_channel(cmd->sk) != channel)
223 continue;
224 if (cmd->opcode == opcode)
225 return cmd;
226 }
227
228 return NULL;
229}
230
231struct mgmt_pending_cmd *mgmt_pending_find_data(unsigned short channel,
232 u16 opcode,
233 struct hci_dev *hdev,
234 const void *data)
235{
236 struct mgmt_pending_cmd *cmd;
237
238 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
239 if (cmd->user_data != data)
240 continue;
241 if (cmd->opcode == opcode)
242 return cmd;
243 }
244
245 return NULL;
246}
247
248void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
249 void (*cb)(struct mgmt_pending_cmd *cmd, void *data),
250 void *data)
251{
252 struct mgmt_pending_cmd *cmd, *tmp;
253
254 list_for_each_entry_safe(cmd, tmp, &hdev->mgmt_pending, list) {
255 if (opcode > 0 && cmd->opcode != opcode)
256 continue;
257
258 cb(cmd, data);
259 }
260}
261
161510cc 262struct mgmt_pending_cmd *mgmt_pending_new(struct sock *sk, u16 opcode,
a380b6cf
JH
263 struct hci_dev *hdev,
264 void *data, u16 len)
265{
266 struct mgmt_pending_cmd *cmd;
267
268 cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
269 if (!cmd)
270 return NULL;
271
272 cmd->opcode = opcode;
273 cmd->index = hdev->id;
274
275 cmd->param = kmemdup(data, len, GFP_KERNEL);
276 if (!cmd->param) {
277 kfree(cmd);
278 return NULL;
279 }
280
281 cmd->param_len = len;
282
283 cmd->sk = sk;
284 sock_hold(sk);
285
161510cc
LAD
286 return cmd;
287}
288
289struct mgmt_pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
290 struct hci_dev *hdev,
291 void *data, u16 len)
292{
293 struct mgmt_pending_cmd *cmd;
294
295 cmd = mgmt_pending_new(sk, opcode, hdev, data, len);
296 if (!cmd)
297 return NULL;
298
a380b6cf
JH
299 list_add(&cmd->list, &hdev->mgmt_pending);
300
301 return cmd;
302}
303
304void mgmt_pending_free(struct mgmt_pending_cmd *cmd)
305{
306 sock_put(cmd->sk);
307 kfree(cmd->param);
308 kfree(cmd);
309}
310
311void mgmt_pending_remove(struct mgmt_pending_cmd *cmd)
312{
313 list_del(&cmd->list);
314 mgmt_pending_free(cmd);
315}