xref: /linux/net/bluetooth/mgmt_util.c (revision 1a9239bb4253f9076b5b4b2a1a4e8d7defd77a95)
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 
24 #include <linux/unaligned.h>
25 
26 #include <net/bluetooth/bluetooth.h>
27 #include <net/bluetooth/hci_core.h>
28 #include <net/bluetooth/hci_mon.h>
29 #include <net/bluetooth/mgmt.h>
30 
31 #include "mgmt_util.h"
32 
create_monitor_ctrl_event(__le16 index,u32 cookie,u16 opcode,u16 len,void * buf)33 static 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)
47 		skb_put_data(skb, buf, len);
48 
49 	__net_timestamp(skb);
50 
51 	hdr = skb_push(skb, HCI_MON_HDR_SIZE);
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 
mgmt_alloc_skb(struct hci_dev * hdev,u16 opcode,unsigned int size)59 struct sk_buff *mgmt_alloc_skb(struct hci_dev *hdev, u16 opcode,
60 			       unsigned int size)
61 {
62 	struct sk_buff *skb;
63 
64 	skb = alloc_skb(sizeof(struct mgmt_hdr) + size, GFP_KERNEL);
65 	if (!skb)
66 		return skb;
67 
68 	skb_reserve(skb, sizeof(struct mgmt_hdr));
69 	bt_cb(skb)->mgmt.hdev = hdev;
70 	bt_cb(skb)->mgmt.opcode = opcode;
71 
72 	return skb;
73 }
74 
mgmt_send_event_skb(unsigned short channel,struct sk_buff * skb,int flag,struct sock * skip_sk)75 int 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;
81 
82 	if (!skb)
83 		return -EINVAL;
84 
85 	len = skb->len;
86 	hdev = bt_cb(skb)->mgmt.hdev;
87 
88 	/* Time stamp */
89 	__net_timestamp(skb);
90 
91 	/* Send just the data, without headers, to the monitor */
92 	if (channel == HCI_CHANNEL_CONTROL)
93 		hci_send_monitor_ctrl_event(hdev, bt_cb(skb)->mgmt.opcode,
94 					    skb->data, skb->len,
95 					    skb_get_ktime(skb), flag, skip_sk);
96 
97 	hdr = skb_push(skb, sizeof(*hdr));
98 	hdr->opcode = cpu_to_le16(bt_cb(skb)->mgmt.opcode);
99 	if (hdev)
100 		hdr->index = cpu_to_le16(hdev->id);
101 	else
102 		hdr->index = cpu_to_le16(MGMT_INDEX_NONE);
103 	hdr->len = cpu_to_le16(len);
104 
105 	hci_send_to_channel(channel, skb, flag, skip_sk);
106 
107 	kfree_skb(skb);
108 	return 0;
109 }
110 
mgmt_send_event(u16 event,struct hci_dev * hdev,unsigned short channel,void * data,u16 data_len,int flag,struct sock * skip_sk)111 int mgmt_send_event(u16 event, struct hci_dev *hdev, unsigned short channel,
112 		    void *data, u16 data_len, int flag, struct sock *skip_sk)
113 {
114 	struct sk_buff *skb;
115 
116 	skb = mgmt_alloc_skb(hdev, event, data_len);
117 	if (!skb)
118 		return -ENOMEM;
119 
120 	if (data)
121 		skb_put_data(skb, data, data_len);
122 
123 	return mgmt_send_event_skb(channel, skb, flag, skip_sk);
124 }
125 
mgmt_cmd_status(struct sock * sk,u16 index,u16 cmd,u8 status)126 int mgmt_cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
127 {
128 	struct sk_buff *skb, *mskb;
129 	struct mgmt_hdr *hdr;
130 	struct mgmt_ev_cmd_status *ev;
131 	int err;
132 
133 	BT_DBG("sock %p, index %u, cmd %u, status %u", sk, index, cmd, status);
134 
135 	skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_KERNEL);
136 	if (!skb)
137 		return -ENOMEM;
138 
139 	hdr = skb_put(skb, sizeof(*hdr));
140 
141 	hdr->opcode = cpu_to_le16(MGMT_EV_CMD_STATUS);
142 	hdr->index = cpu_to_le16(index);
143 	hdr->len = cpu_to_le16(sizeof(*ev));
144 
145 	ev = skb_put(skb, sizeof(*ev));
146 	ev->status = status;
147 	ev->opcode = cpu_to_le16(cmd);
148 
149 	mskb = create_monitor_ctrl_event(hdr->index, hci_sock_get_cookie(sk),
150 					 MGMT_EV_CMD_STATUS, sizeof(*ev), ev);
151 	if (mskb)
152 		skb->tstamp = mskb->tstamp;
153 	else
154 		__net_timestamp(skb);
155 
156 	err = sock_queue_rcv_skb(sk, skb);
157 	if (err < 0)
158 		kfree_skb(skb);
159 
160 	if (mskb) {
161 		hci_send_to_channel(HCI_CHANNEL_MONITOR, mskb,
162 				    HCI_SOCK_TRUSTED, NULL);
163 		kfree_skb(mskb);
164 	}
165 
166 	return err;
167 }
168 
mgmt_cmd_complete(struct sock * sk,u16 index,u16 cmd,u8 status,void * rp,size_t rp_len)169 int mgmt_cmd_complete(struct sock *sk, u16 index, u16 cmd, u8 status,
170 		      void *rp, size_t rp_len)
171 {
172 	struct sk_buff *skb, *mskb;
173 	struct mgmt_hdr *hdr;
174 	struct mgmt_ev_cmd_complete *ev;
175 	int err;
176 
177 	BT_DBG("sock %p", sk);
178 
179 	skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + rp_len, GFP_KERNEL);
180 	if (!skb)
181 		return -ENOMEM;
182 
183 	hdr = skb_put(skb, sizeof(*hdr));
184 
185 	hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE);
186 	hdr->index = cpu_to_le16(index);
187 	hdr->len = cpu_to_le16(sizeof(*ev) + rp_len);
188 
189 	ev = skb_put(skb, sizeof(*ev) + rp_len);
190 	ev->opcode = cpu_to_le16(cmd);
191 	ev->status = status;
192 
193 	if (rp)
194 		memcpy(ev->data, rp, rp_len);
195 
196 	mskb = create_monitor_ctrl_event(hdr->index, hci_sock_get_cookie(sk),
197 					 MGMT_EV_CMD_COMPLETE,
198 					 sizeof(*ev) + rp_len, ev);
199 	if (mskb)
200 		skb->tstamp = mskb->tstamp;
201 	else
202 		__net_timestamp(skb);
203 
204 	err = sock_queue_rcv_skb(sk, skb);
205 	if (err < 0)
206 		kfree_skb(skb);
207 
208 	if (mskb) {
209 		hci_send_to_channel(HCI_CHANNEL_MONITOR, mskb,
210 				    HCI_SOCK_TRUSTED, NULL);
211 		kfree_skb(mskb);
212 	}
213 
214 	return err;
215 }
216 
mgmt_pending_find(unsigned short channel,u16 opcode,struct hci_dev * hdev)217 struct mgmt_pending_cmd *mgmt_pending_find(unsigned short channel, u16 opcode,
218 					   struct hci_dev *hdev)
219 {
220 	struct mgmt_pending_cmd *cmd;
221 
222 	list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
223 		if (hci_sock_get_channel(cmd->sk) != channel)
224 			continue;
225 		if (cmd->opcode == opcode)
226 			return cmd;
227 	}
228 
229 	return NULL;
230 }
231 
mgmt_pending_foreach(u16 opcode,struct hci_dev * hdev,void (* cb)(struct mgmt_pending_cmd * cmd,void * data),void * data)232 void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
233 			  void (*cb)(struct mgmt_pending_cmd *cmd, void *data),
234 			  void *data)
235 {
236 	struct mgmt_pending_cmd *cmd, *tmp;
237 
238 	list_for_each_entry_safe(cmd, tmp, &hdev->mgmt_pending, list) {
239 		if (opcode > 0 && cmd->opcode != opcode)
240 			continue;
241 
242 		cb(cmd, data);
243 	}
244 }
245 
mgmt_pending_new(struct sock * sk,u16 opcode,struct hci_dev * hdev,void * data,u16 len)246 struct mgmt_pending_cmd *mgmt_pending_new(struct sock *sk, u16 opcode,
247 					  struct hci_dev *hdev,
248 					  void *data, u16 len)
249 {
250 	struct mgmt_pending_cmd *cmd;
251 
252 	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
253 	if (!cmd)
254 		return NULL;
255 
256 	cmd->opcode = opcode;
257 	cmd->index = hdev->id;
258 
259 	cmd->param = kmemdup(data, len, GFP_KERNEL);
260 	if (!cmd->param) {
261 		kfree(cmd);
262 		return NULL;
263 	}
264 
265 	cmd->param_len = len;
266 
267 	cmd->sk = sk;
268 	sock_hold(sk);
269 
270 	return cmd;
271 }
272 
mgmt_pending_add(struct sock * sk,u16 opcode,struct hci_dev * hdev,void * data,u16 len)273 struct mgmt_pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
274 					  struct hci_dev *hdev,
275 					  void *data, u16 len)
276 {
277 	struct mgmt_pending_cmd *cmd;
278 
279 	cmd = mgmt_pending_new(sk, opcode, hdev, data, len);
280 	if (!cmd)
281 		return NULL;
282 
283 	list_add_tail(&cmd->list, &hdev->mgmt_pending);
284 
285 	return cmd;
286 }
287 
mgmt_pending_free(struct mgmt_pending_cmd * cmd)288 void mgmt_pending_free(struct mgmt_pending_cmd *cmd)
289 {
290 	sock_put(cmd->sk);
291 	kfree(cmd->param);
292 	kfree(cmd);
293 }
294 
mgmt_pending_remove(struct mgmt_pending_cmd * cmd)295 void mgmt_pending_remove(struct mgmt_pending_cmd *cmd)
296 {
297 	list_del(&cmd->list);
298 	mgmt_pending_free(cmd);
299 }
300 
mgmt_mesh_foreach(struct hci_dev * hdev,void (* cb)(struct mgmt_mesh_tx * mesh_tx,void * data),void * data,struct sock * sk)301 void mgmt_mesh_foreach(struct hci_dev *hdev,
302 		       void (*cb)(struct mgmt_mesh_tx *mesh_tx, void *data),
303 		       void *data, struct sock *sk)
304 {
305 	struct mgmt_mesh_tx *mesh_tx, *tmp;
306 
307 	list_for_each_entry_safe(mesh_tx, tmp, &hdev->mgmt_pending, list) {
308 		if (!sk || mesh_tx->sk == sk)
309 			cb(mesh_tx, data);
310 	}
311 }
312 
mgmt_mesh_next(struct hci_dev * hdev,struct sock * sk)313 struct mgmt_mesh_tx *mgmt_mesh_next(struct hci_dev *hdev, struct sock *sk)
314 {
315 	struct mgmt_mesh_tx *mesh_tx;
316 
317 	if (list_empty(&hdev->mesh_pending))
318 		return NULL;
319 
320 	list_for_each_entry(mesh_tx, &hdev->mesh_pending, list) {
321 		if (!sk || mesh_tx->sk == sk)
322 			return mesh_tx;
323 	}
324 
325 	return NULL;
326 }
327 
mgmt_mesh_find(struct hci_dev * hdev,u8 handle)328 struct mgmt_mesh_tx *mgmt_mesh_find(struct hci_dev *hdev, u8 handle)
329 {
330 	struct mgmt_mesh_tx *mesh_tx;
331 
332 	if (list_empty(&hdev->mesh_pending))
333 		return NULL;
334 
335 	list_for_each_entry(mesh_tx, &hdev->mesh_pending, list) {
336 		if (mesh_tx->handle == handle)
337 			return mesh_tx;
338 	}
339 
340 	return NULL;
341 }
342 
mgmt_mesh_add(struct sock * sk,struct hci_dev * hdev,void * data,u16 len)343 struct mgmt_mesh_tx *mgmt_mesh_add(struct sock *sk, struct hci_dev *hdev,
344 				   void *data, u16 len)
345 {
346 	struct mgmt_mesh_tx *mesh_tx;
347 
348 	mesh_tx = kzalloc(sizeof(*mesh_tx), GFP_KERNEL);
349 	if (!mesh_tx)
350 		return NULL;
351 
352 	hdev->mesh_send_ref++;
353 	if (!hdev->mesh_send_ref)
354 		hdev->mesh_send_ref++;
355 
356 	mesh_tx->handle = hdev->mesh_send_ref;
357 	mesh_tx->index = hdev->id;
358 	memcpy(mesh_tx->param, data, len);
359 	mesh_tx->param_len = len;
360 	mesh_tx->sk = sk;
361 	sock_hold(sk);
362 
363 	list_add_tail(&mesh_tx->list, &hdev->mesh_pending);
364 
365 	return mesh_tx;
366 }
367 
mgmt_mesh_remove(struct mgmt_mesh_tx * mesh_tx)368 void mgmt_mesh_remove(struct mgmt_mesh_tx *mesh_tx)
369 {
370 	list_del(&mesh_tx->list);
371 	sock_put(mesh_tx->sk);
372 	kfree(mesh_tx);
373 }
374