Linux Audio

Check our new training course

Loading...
v5.4
  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 <asm/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
 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)
 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
 59int mgmt_send_event(u16 event, struct hci_dev *hdev, unsigned short channel,
 60		    void *data, u16 data_len, int flag, struct sock *skip_sk)
 61{
 62	struct sk_buff *skb;
 63	struct mgmt_hdr *hdr;
 64
 65	skb = alloc_skb(sizeof(*hdr) + data_len, GFP_KERNEL);
 66	if (!skb)
 67		return -ENOMEM;
 68
 69	hdr = skb_put(skb, sizeof(*hdr));
 70	hdr->opcode = cpu_to_le16(event);
 71	if (hdev)
 72		hdr->index = cpu_to_le16(hdev->id);
 73	else
 74		hdr->index = cpu_to_le16(MGMT_INDEX_NONE);
 75	hdr->len = cpu_to_le16(data_len);
 76
 77	if (data)
 78		skb_put_data(skb, data, data_len);
 79
 80	/* Time stamp */
 81	__net_timestamp(skb);
 82
 83	hci_send_to_channel(channel, skb, flag, skip_sk);
 84
 85	if (channel == HCI_CHANNEL_CONTROL)
 86		hci_send_monitor_ctrl_event(hdev, event, data, data_len,
 87					    skb_get_ktime(skb), flag, skip_sk);
 88
 89	kfree_skb(skb);
 
 90	return 0;
 91}
 92
 93int mgmt_cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
 94{
 95	struct sk_buff *skb, *mskb;
 96	struct mgmt_hdr *hdr;
 97	struct mgmt_ev_cmd_status *ev;
 98	int err;
 99
100	BT_DBG("sock %p, index %u, cmd %u, status %u", sk, index, cmd, status);
101
102	skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_KERNEL);
103	if (!skb)
104		return -ENOMEM;
105
106	hdr = skb_put(skb, sizeof(*hdr));
107
108	hdr->opcode = cpu_to_le16(MGMT_EV_CMD_STATUS);
109	hdr->index = cpu_to_le16(index);
110	hdr->len = cpu_to_le16(sizeof(*ev));
111
112	ev = skb_put(skb, sizeof(*ev));
113	ev->status = status;
114	ev->opcode = cpu_to_le16(cmd);
115
116	mskb = create_monitor_ctrl_event(hdr->index, hci_sock_get_cookie(sk),
117					 MGMT_EV_CMD_STATUS, sizeof(*ev), ev);
118	if (mskb)
119		skb->tstamp = mskb->tstamp;
120	else
121		__net_timestamp(skb);
122
123	err = sock_queue_rcv_skb(sk, skb);
124	if (err < 0)
125		kfree_skb(skb);
126
127	if (mskb) {
128		hci_send_to_channel(HCI_CHANNEL_MONITOR, mskb,
129				    HCI_SOCK_TRUSTED, NULL);
130		kfree_skb(mskb);
131	}
132
133	return err;
134}
135
136int mgmt_cmd_complete(struct sock *sk, u16 index, u16 cmd, u8 status,
137		      void *rp, size_t rp_len)
138{
139	struct sk_buff *skb, *mskb;
140	struct mgmt_hdr *hdr;
141	struct mgmt_ev_cmd_complete *ev;
142	int err;
143
144	BT_DBG("sock %p", sk);
145
146	skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + rp_len, GFP_KERNEL);
147	if (!skb)
148		return -ENOMEM;
149
150	hdr = skb_put(skb, sizeof(*hdr));
151
152	hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE);
153	hdr->index = cpu_to_le16(index);
154	hdr->len = cpu_to_le16(sizeof(*ev) + rp_len);
155
156	ev = skb_put(skb, sizeof(*ev) + rp_len);
157	ev->opcode = cpu_to_le16(cmd);
158	ev->status = status;
159
160	if (rp)
161		memcpy(ev->data, rp, rp_len);
162
163	mskb = create_monitor_ctrl_event(hdr->index, hci_sock_get_cookie(sk),
164					 MGMT_EV_CMD_COMPLETE,
165					 sizeof(*ev) + rp_len, ev);
166	if (mskb)
167		skb->tstamp = mskb->tstamp;
168	else
169		__net_timestamp(skb);
170
171	err = sock_queue_rcv_skb(sk, skb);
172	if (err < 0)
173		kfree_skb(skb);
174
175	if (mskb) {
176		hci_send_to_channel(HCI_CHANNEL_MONITOR, mskb,
177				    HCI_SOCK_TRUSTED, NULL);
178		kfree_skb(mskb);
179	}
180
181	return err;
182}
183
184struct mgmt_pending_cmd *mgmt_pending_find(unsigned short channel, u16 opcode,
185					   struct hci_dev *hdev)
186{
187	struct mgmt_pending_cmd *cmd;
188
189	list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
190		if (hci_sock_get_channel(cmd->sk) != channel)
191			continue;
192		if (cmd->opcode == opcode)
193			return cmd;
194	}
195
196	return NULL;
197}
198
199struct mgmt_pending_cmd *mgmt_pending_find_data(unsigned short channel,
200						u16 opcode,
201						struct hci_dev *hdev,
202						const void *data)
203{
204	struct mgmt_pending_cmd *cmd;
205
206	list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
207		if (cmd->user_data != data)
208			continue;
209		if (cmd->opcode == opcode)
210			return cmd;
211	}
212
213	return NULL;
214}
215
216void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
217			  void (*cb)(struct mgmt_pending_cmd *cmd, void *data),
218			  void *data)
219{
220	struct mgmt_pending_cmd *cmd, *tmp;
221
222	list_for_each_entry_safe(cmd, tmp, &hdev->mgmt_pending, list) {
223		if (opcode > 0 && cmd->opcode != opcode)
224			continue;
225
226		cb(cmd, data);
227	}
228}
229
230struct mgmt_pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
231					  struct hci_dev *hdev,
232					  void *data, u16 len)
233{
234	struct mgmt_pending_cmd *cmd;
235
236	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
237	if (!cmd)
238		return NULL;
239
240	cmd->opcode = opcode;
241	cmd->index = hdev->id;
242
243	cmd->param = kmemdup(data, len, GFP_KERNEL);
244	if (!cmd->param) {
245		kfree(cmd);
246		return NULL;
247	}
248
249	cmd->param_len = len;
250
251	cmd->sk = sk;
252	sock_hold(sk);
253
254	list_add(&cmd->list, &hdev->mgmt_pending);
255
256	return cmd;
257}
258
259void mgmt_pending_free(struct mgmt_pending_cmd *cmd)
260{
261	sock_put(cmd->sk);
262	kfree(cmd->param);
263	kfree(cmd);
264}
265
266void mgmt_pending_remove(struct mgmt_pending_cmd *cmd)
267{
268	list_del(&cmd->list);
269	mgmt_pending_free(cmd);
270}
v4.6
  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 <net/bluetooth/bluetooth.h>
 25#include <net/bluetooth/hci_core.h>
 
 26#include <net/bluetooth/mgmt.h>
 27
 28#include "mgmt_util.h"
 29
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 30int mgmt_send_event(u16 event, struct hci_dev *hdev, unsigned short channel,
 31		    void *data, u16 data_len, int flag, struct sock *skip_sk)
 32{
 33	struct sk_buff *skb;
 34	struct mgmt_hdr *hdr;
 35
 36	skb = alloc_skb(sizeof(*hdr) + data_len, GFP_KERNEL);
 37	if (!skb)
 38		return -ENOMEM;
 39
 40	hdr = (void *) skb_put(skb, sizeof(*hdr));
 41	hdr->opcode = cpu_to_le16(event);
 42	if (hdev)
 43		hdr->index = cpu_to_le16(hdev->id);
 44	else
 45		hdr->index = cpu_to_le16(MGMT_INDEX_NONE);
 46	hdr->len = cpu_to_le16(data_len);
 47
 48	if (data)
 49		memcpy(skb_put(skb, data_len), data, data_len);
 50
 51	/* Time stamp */
 52	__net_timestamp(skb);
 53
 54	hci_send_to_channel(channel, skb, flag, skip_sk);
 
 
 
 
 
 55	kfree_skb(skb);
 56
 57	return 0;
 58}
 59
 60int mgmt_cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
 61{
 62	struct sk_buff *skb;
 63	struct mgmt_hdr *hdr;
 64	struct mgmt_ev_cmd_status *ev;
 65	int err;
 66
 67	BT_DBG("sock %p, index %u, cmd %u, status %u", sk, index, cmd, status);
 68
 69	skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_KERNEL);
 70	if (!skb)
 71		return -ENOMEM;
 72
 73	hdr = (void *) skb_put(skb, sizeof(*hdr));
 74
 75	hdr->opcode = cpu_to_le16(MGMT_EV_CMD_STATUS);
 76	hdr->index = cpu_to_le16(index);
 77	hdr->len = cpu_to_le16(sizeof(*ev));
 78
 79	ev = (void *) skb_put(skb, sizeof(*ev));
 80	ev->status = status;
 81	ev->opcode = cpu_to_le16(cmd);
 82
 
 
 
 
 
 
 
 83	err = sock_queue_rcv_skb(sk, skb);
 84	if (err < 0)
 85		kfree_skb(skb);
 86
 
 
 
 
 
 
 87	return err;
 88}
 89
 90int mgmt_cmd_complete(struct sock *sk, u16 index, u16 cmd, u8 status,
 91		      void *rp, size_t rp_len)
 92{
 93	struct sk_buff *skb;
 94	struct mgmt_hdr *hdr;
 95	struct mgmt_ev_cmd_complete *ev;
 96	int err;
 97
 98	BT_DBG("sock %p", sk);
 99
100	skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + rp_len, GFP_KERNEL);
101	if (!skb)
102		return -ENOMEM;
103
104	hdr = (void *) skb_put(skb, sizeof(*hdr));
105
106	hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE);
107	hdr->index = cpu_to_le16(index);
108	hdr->len = cpu_to_le16(sizeof(*ev) + rp_len);
109
110	ev = (void *) skb_put(skb, sizeof(*ev) + rp_len);
111	ev->opcode = cpu_to_le16(cmd);
112	ev->status = status;
113
114	if (rp)
115		memcpy(ev->data, rp, rp_len);
116
 
 
 
 
 
 
 
 
117	err = sock_queue_rcv_skb(sk, skb);
118	if (err < 0)
119		kfree_skb(skb);
 
 
 
 
 
 
120
121	return err;
122}
123
124struct mgmt_pending_cmd *mgmt_pending_find(unsigned short channel, u16 opcode,
125					   struct hci_dev *hdev)
126{
127	struct mgmt_pending_cmd *cmd;
128
129	list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
130		if (hci_sock_get_channel(cmd->sk) != channel)
131			continue;
132		if (cmd->opcode == opcode)
133			return cmd;
134	}
135
136	return NULL;
137}
138
139struct mgmt_pending_cmd *mgmt_pending_find_data(unsigned short channel,
140						u16 opcode,
141						struct hci_dev *hdev,
142						const void *data)
143{
144	struct mgmt_pending_cmd *cmd;
145
146	list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
147		if (cmd->user_data != data)
148			continue;
149		if (cmd->opcode == opcode)
150			return cmd;
151	}
152
153	return NULL;
154}
155
156void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
157			  void (*cb)(struct mgmt_pending_cmd *cmd, void *data),
158			  void *data)
159{
160	struct mgmt_pending_cmd *cmd, *tmp;
161
162	list_for_each_entry_safe(cmd, tmp, &hdev->mgmt_pending, list) {
163		if (opcode > 0 && cmd->opcode != opcode)
164			continue;
165
166		cb(cmd, data);
167	}
168}
169
170struct mgmt_pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
171					  struct hci_dev *hdev,
172					  void *data, u16 len)
173{
174	struct mgmt_pending_cmd *cmd;
175
176	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
177	if (!cmd)
178		return NULL;
179
180	cmd->opcode = opcode;
181	cmd->index = hdev->id;
182
183	cmd->param = kmemdup(data, len, GFP_KERNEL);
184	if (!cmd->param) {
185		kfree(cmd);
186		return NULL;
187	}
188
189	cmd->param_len = len;
190
191	cmd->sk = sk;
192	sock_hold(sk);
193
194	list_add(&cmd->list, &hdev->mgmt_pending);
195
196	return cmd;
197}
198
199void mgmt_pending_free(struct mgmt_pending_cmd *cmd)
200{
201	sock_put(cmd->sk);
202	kfree(cmd->param);
203	kfree(cmd);
204}
205
206void mgmt_pending_remove(struct mgmt_pending_cmd *cmd)
207{
208	list_del(&cmd->list);
209	mgmt_pending_free(cmd);
210}