Linux 4.3
[linux/fpc-iii.git] / net / bluetooth / mgmt_util.c
blob8c30c7eb8bef58ea1471f646a39c8739fa0e82c0
1 /*
2 BlueZ - Bluetooth protocol stack for Linux
4 Copyright (C) 2015 Intel Corporation
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;
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.
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.
24 #include <net/bluetooth/bluetooth.h>
25 #include <net/bluetooth/hci_core.h>
26 #include <net/bluetooth/mgmt.h>
28 #include "mgmt_util.h"
30 int mgmt_send_event(u16 event, struct hci_dev *hdev, unsigned short channel,
31 void *data, u16 data_len, int flag, struct sock *skip_sk)
33 struct sk_buff *skb;
34 struct mgmt_hdr *hdr;
36 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_KERNEL);
37 if (!skb)
38 return -ENOMEM;
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);
48 if (data)
49 memcpy(skb_put(skb, data_len), data, data_len);
51 /* Time stamp */
52 __net_timestamp(skb);
54 hci_send_to_channel(channel, skb, flag, skip_sk);
55 kfree_skb(skb);
57 return 0;
60 int mgmt_cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
62 struct sk_buff *skb;
63 struct mgmt_hdr *hdr;
64 struct mgmt_ev_cmd_status *ev;
65 int err;
67 BT_DBG("sock %p, index %u, cmd %u, status %u", sk, index, cmd, status);
69 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_KERNEL);
70 if (!skb)
71 return -ENOMEM;
73 hdr = (void *) skb_put(skb, sizeof(*hdr));
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));
79 ev = (void *) skb_put(skb, sizeof(*ev));
80 ev->status = status;
81 ev->opcode = cpu_to_le16(cmd);
83 err = sock_queue_rcv_skb(sk, skb);
84 if (err < 0)
85 kfree_skb(skb);
87 return err;
90 int mgmt_cmd_complete(struct sock *sk, u16 index, u16 cmd, u8 status,
91 void *rp, size_t rp_len)
93 struct sk_buff *skb;
94 struct mgmt_hdr *hdr;
95 struct mgmt_ev_cmd_complete *ev;
96 int err;
98 BT_DBG("sock %p", sk);
100 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + rp_len, GFP_KERNEL);
101 if (!skb)
102 return -ENOMEM;
104 hdr = (void *) skb_put(skb, sizeof(*hdr));
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);
110 ev = (void *) skb_put(skb, sizeof(*ev) + rp_len);
111 ev->opcode = cpu_to_le16(cmd);
112 ev->status = status;
114 if (rp)
115 memcpy(ev->data, rp, rp_len);
117 err = sock_queue_rcv_skb(sk, skb);
118 if (err < 0)
119 kfree_skb(skb);
121 return err;
124 struct mgmt_pending_cmd *mgmt_pending_find(unsigned short channel, u16 opcode,
125 struct hci_dev *hdev)
127 struct mgmt_pending_cmd *cmd;
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;
136 return NULL;
139 struct mgmt_pending_cmd *mgmt_pending_find_data(unsigned short channel,
140 u16 opcode,
141 struct hci_dev *hdev,
142 const void *data)
144 struct mgmt_pending_cmd *cmd;
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;
153 return NULL;
156 void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
157 void (*cb)(struct mgmt_pending_cmd *cmd, void *data),
158 void *data)
160 struct mgmt_pending_cmd *cmd, *tmp;
162 list_for_each_entry_safe(cmd, tmp, &hdev->mgmt_pending, list) {
163 if (opcode > 0 && cmd->opcode != opcode)
164 continue;
166 cb(cmd, data);
170 struct mgmt_pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
171 struct hci_dev *hdev,
172 void *data, u16 len)
174 struct mgmt_pending_cmd *cmd;
176 cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
177 if (!cmd)
178 return NULL;
180 cmd->opcode = opcode;
181 cmd->index = hdev->id;
183 cmd->param = kmemdup(data, len, GFP_KERNEL);
184 if (!cmd->param) {
185 kfree(cmd);
186 return NULL;
189 cmd->param_len = len;
191 cmd->sk = sk;
192 sock_hold(sk);
194 list_add(&cmd->list, &hdev->mgmt_pending);
196 return cmd;
199 void mgmt_pending_free(struct mgmt_pending_cmd *cmd)
201 sock_put(cmd->sk);
202 kfree(cmd->param);
203 kfree(cmd);
206 void mgmt_pending_remove(struct mgmt_pending_cmd *cmd)
208 list_del(&cmd->list);
209 mgmt_pending_free(cmd);