aboutsummaryrefslogtreecommitdiffstats
path: root/net/bluetooth
diff options
context:
space:
mode:
authorJohan Hedberg <johan.hedberg@intel.com>2015-03-17 07:48:48 -0400
committerMarcel Holtmann <marcel@holtmann.org>2015-03-17 13:03:08 -0400
commita380b6cff1a2d2139772e88219d08330f84d0381 (patch)
tree317197dc2c305b15292e6498de643fa379089165 /net/bluetooth
parent333ae95d054519f64303f0e149b4b9653cc4635b (diff)
Bluetooth: Add generic mgmt helper API
There are several mgmt protocol features that will be needed by more than just the current HCI_CHANNEL_CONTROL. These include sending generic events as well as handling pending commands. This patch moves these functions out from mgmt.c to a new mgmt_util.c file. Signed-off-by: Johan Hedberg <johan.hedberg@intel.com> Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
Diffstat (limited to 'net/bluetooth')
-rw-r--r--net/bluetooth/Makefile2
-rw-r--r--net/bluetooth/mgmt.c197
-rw-r--r--net/bluetooth/mgmt_util.c210
-rw-r--r--net/bluetooth/mgmt_util.h53
4 files changed, 265 insertions, 197 deletions
diff --git a/net/bluetooth/Makefile b/net/bluetooth/Makefile
index 5d608799717e..9a8ea232d28f 100644
--- a/net/bluetooth/Makefile
+++ b/net/bluetooth/Makefile
@@ -13,7 +13,7 @@ bluetooth_6lowpan-y := 6lowpan.o
13 13
14bluetooth-y := af_bluetooth.o hci_core.o hci_conn.o hci_event.o mgmt.o \ 14bluetooth-y := af_bluetooth.o hci_core.o hci_conn.o hci_event.o mgmt.o \
15 hci_sock.o hci_sysfs.o l2cap_core.o l2cap_sock.o smp.o sco.o lib.o \ 15 hci_sock.o hci_sysfs.o l2cap_core.o l2cap_sock.o smp.o sco.o lib.o \
16 a2mp.o amp.o ecc.o hci_request.o 16 a2mp.o amp.o ecc.o hci_request.o mgmt_util.o
17 17
18bluetooth-$(CONFIG_BT_DEBUGFS) += hci_debugfs.o 18bluetooth-$(CONFIG_BT_DEBUGFS) += hci_debugfs.o
19bluetooth-$(CONFIG_BT_SELFTEST) += selftest.o 19bluetooth-$(CONFIG_BT_SELFTEST) += selftest.o
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 3d7dbdde7008..915a2a1f0a71 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -35,6 +35,7 @@
35 35
36#include "hci_request.h" 36#include "hci_request.h"
37#include "smp.h" 37#include "smp.h"
38#include "mgmt_util.h"
38 39
39#define MGMT_VERSION 1 40#define MGMT_VERSION 1
40#define MGMT_REVISION 9 41#define MGMT_REVISION 9
@@ -141,17 +142,6 @@ static const u16 mgmt_events[] = {
141#define ZERO_KEY "\x00\x00\x00\x00\x00\x00\x00\x00" \ 142#define ZERO_KEY "\x00\x00\x00\x00\x00\x00\x00\x00" \
142 "\x00\x00\x00\x00\x00\x00\x00\x00" 143 "\x00\x00\x00\x00\x00\x00\x00\x00"
143 144
144struct mgmt_pending_cmd {
145 struct list_head list;
146 u16 opcode;
147 int index;
148 void *param;
149 size_t param_len;
150 struct sock *sk;
151 void *user_data;
152 int (*cmd_complete)(struct mgmt_pending_cmd *cmd, u8 status);
153};
154
155/* HCI to MGMT error code conversion table */ 145/* HCI to MGMT error code conversion table */
156static u8 mgmt_status_table[] = { 146static u8 mgmt_status_table[] = {
157 MGMT_STATUS_SUCCESS, 147 MGMT_STATUS_SUCCESS,
@@ -225,37 +215,6 @@ static u8 mgmt_status(u8 hci_status)
225 return MGMT_STATUS_FAILED; 215 return MGMT_STATUS_FAILED;
226} 216}
227 217
228static int mgmt_send_event(u16 event, struct hci_dev *hdev,
229 unsigned short channel, void *data, u16 data_len,
230 int flag, struct sock *skip_sk)
231{
232 struct sk_buff *skb;
233 struct mgmt_hdr *hdr;
234
235 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_KERNEL);
236 if (!skb)
237 return -ENOMEM;
238
239 hdr = (void *) skb_put(skb, sizeof(*hdr));
240 hdr->opcode = cpu_to_le16(event);
241 if (hdev)
242 hdr->index = cpu_to_le16(hdev->id);
243 else
244 hdr->index = cpu_to_le16(MGMT_INDEX_NONE);
245 hdr->len = cpu_to_le16(data_len);
246
247 if (data)
248 memcpy(skb_put(skb, data_len), data, data_len);
249
250 /* Time stamp */
251 __net_timestamp(skb);
252
253 hci_send_to_channel(channel, skb, flag, skip_sk);
254 kfree_skb(skb);
255
256 return 0;
257}
258
259static int mgmt_index_event(u16 event, struct hci_dev *hdev, void *data, 218static int mgmt_index_event(u16 event, struct hci_dev *hdev, void *data,
260 u16 len, int flag) 219 u16 len, int flag)
261{ 220{
@@ -284,70 +243,6 @@ static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, u16 len,
284 HCI_SOCK_TRUSTED, skip_sk); 243 HCI_SOCK_TRUSTED, skip_sk);
285} 244}
286 245
287static int mgmt_cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
288{
289 struct sk_buff *skb;
290 struct mgmt_hdr *hdr;
291 struct mgmt_ev_cmd_status *ev;
292 int err;
293
294 BT_DBG("sock %p, index %u, cmd %u, status %u", sk, index, cmd, status);
295
296 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_KERNEL);
297 if (!skb)
298 return -ENOMEM;
299
300 hdr = (void *) skb_put(skb, sizeof(*hdr));
301
302 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_STATUS);
303 hdr->index = cpu_to_le16(index);
304 hdr->len = cpu_to_le16(sizeof(*ev));
305
306 ev = (void *) skb_put(skb, sizeof(*ev));
307 ev->status = status;
308 ev->opcode = cpu_to_le16(cmd);
309
310 err = sock_queue_rcv_skb(sk, skb);
311 if (err < 0)
312 kfree_skb(skb);
313
314 return err;
315}
316
317static int mgmt_cmd_complete(struct sock *sk, u16 index, u16 cmd, u8 status,
318 void *rp, size_t rp_len)
319{
320 struct sk_buff *skb;
321 struct mgmt_hdr *hdr;
322 struct mgmt_ev_cmd_complete *ev;
323 int err;
324
325 BT_DBG("sock %p", sk);
326
327 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + rp_len, GFP_KERNEL);
328 if (!skb)
329 return -ENOMEM;
330
331 hdr = (void *) skb_put(skb, sizeof(*hdr));
332
333 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE);
334 hdr->index = cpu_to_le16(index);
335 hdr->len = cpu_to_le16(sizeof(*ev) + rp_len);
336
337 ev = (void *) skb_put(skb, sizeof(*ev) + rp_len);
338 ev->opcode = cpu_to_le16(cmd);
339 ev->status = status;
340
341 if (rp)
342 memcpy(ev->data, rp, rp_len);
343
344 err = sock_queue_rcv_skb(sk, skb);
345 if (err < 0)
346 kfree_skb(skb);
347
348 return err;
349}
350
351static int read_version(struct sock *sk, struct hci_dev *hdev, void *data, 246static int read_version(struct sock *sk, struct hci_dev *hdev, void *data,
352 u16 data_len) 247 u16 data_len)
353{ 248{
@@ -882,44 +777,11 @@ static u8 *create_uuid128_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
882 return ptr; 777 return ptr;
883} 778}
884 779
885static struct mgmt_pending_cmd *mgmt_pending_find(unsigned short channel,
886 u16 opcode,
887 struct hci_dev *hdev)
888{
889 struct mgmt_pending_cmd *cmd;
890
891 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
892 if (hci_sock_get_channel(cmd->sk) != channel)
893 continue;
894 if (cmd->opcode == opcode)
895 return cmd;
896 }
897
898 return NULL;
899}
900
901static struct mgmt_pending_cmd *pending_find(u16 opcode, struct hci_dev *hdev) 780static struct mgmt_pending_cmd *pending_find(u16 opcode, struct hci_dev *hdev)
902{ 781{
903 return mgmt_pending_find(HCI_CHANNEL_CONTROL, opcode, hdev); 782 return mgmt_pending_find(HCI_CHANNEL_CONTROL, opcode, hdev);
904} 783}
905 784
906static struct mgmt_pending_cmd *mgmt_pending_find_data(unsigned short channel,
907 u16 opcode,
908 struct hci_dev *hdev,
909 const void *data)
910{
911 struct mgmt_pending_cmd *cmd;
912
913 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
914 if (cmd->user_data != data)
915 continue;
916 if (cmd->opcode == opcode)
917 return cmd;
918 }
919
920 return NULL;
921}
922
923static struct mgmt_pending_cmd *pending_find_data(u16 opcode, 785static struct mgmt_pending_cmd *pending_find_data(u16 opcode,
924 struct hci_dev *hdev, 786 struct hci_dev *hdev,
925 const void *data) 787 const void *data)
@@ -1341,63 +1203,6 @@ static int read_controller_info(struct sock *sk, struct hci_dev *hdev,
1341 sizeof(rp)); 1203 sizeof(rp));
1342} 1204}
1343 1205
1344static void mgmt_pending_free(struct mgmt_pending_cmd *cmd)
1345{
1346 sock_put(cmd->sk);
1347 kfree(cmd->param);
1348 kfree(cmd);
1349}
1350
1351static struct mgmt_pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
1352 struct hci_dev *hdev,
1353 void *data, u16 len)
1354{
1355 struct mgmt_pending_cmd *cmd;
1356
1357 cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
1358 if (!cmd)
1359 return NULL;
1360
1361 cmd->opcode = opcode;
1362 cmd->index = hdev->id;
1363
1364 cmd->param = kmemdup(data, len, GFP_KERNEL);
1365 if (!cmd->param) {
1366 kfree(cmd);
1367 return NULL;
1368 }
1369
1370 cmd->param_len = len;
1371
1372 cmd->sk = sk;
1373 sock_hold(sk);
1374
1375 list_add(&cmd->list, &hdev->mgmt_pending);
1376
1377 return cmd;
1378}
1379
1380static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
1381 void (*cb)(struct mgmt_pending_cmd *cmd,
1382 void *data),
1383 void *data)
1384{
1385 struct mgmt_pending_cmd *cmd, *tmp;
1386
1387 list_for_each_entry_safe(cmd, tmp, &hdev->mgmt_pending, list) {
1388 if (opcode > 0 && cmd->opcode != opcode)
1389 continue;
1390
1391 cb(cmd, data);
1392 }
1393}
1394
1395static void mgmt_pending_remove(struct mgmt_pending_cmd *cmd)
1396{
1397 list_del(&cmd->list);
1398 mgmt_pending_free(cmd);
1399}
1400
1401static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev) 1206static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
1402{ 1207{
1403 __le32 settings = cpu_to_le32(get_current_settings(hdev)); 1208 __le32 settings = cpu_to_le32(get_current_settings(hdev));
diff --git a/net/bluetooth/mgmt_util.c b/net/bluetooth/mgmt_util.c
new file mode 100644
index 000000000000..8c30c7eb8bef
--- /dev/null
+++ b/net/bluetooth/mgmt_util.c
@@ -0,0 +1,210 @@
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}
diff --git a/net/bluetooth/mgmt_util.h b/net/bluetooth/mgmt_util.h
new file mode 100644
index 000000000000..6559f189213c
--- /dev/null
+++ b/net/bluetooth/mgmt_util.h
@@ -0,0 +1,53 @@
1/*
2 BlueZ - Bluetooth protocol stack for Linux
3 Copyright (C) 2015 Intel Coropration
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License version 2 as
7 published by the Free Software Foundation;
8
9 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
10 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
11 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
12 IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
13 CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
14 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17
18 ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
19 COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
20 SOFTWARE IS DISCLAIMED.
21*/
22
23struct mgmt_pending_cmd {
24 struct list_head list;
25 u16 opcode;
26 int index;
27 void *param;
28 size_t param_len;
29 struct sock *sk;
30 void *user_data;
31 int (*cmd_complete)(struct mgmt_pending_cmd *cmd, u8 status);
32};
33
34int mgmt_send_event(u16 event, struct hci_dev *hdev, unsigned short channel,
35 void *data, u16 data_len, int flag, struct sock *skip_sk);
36int mgmt_cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status);
37int mgmt_cmd_complete(struct sock *sk, u16 index, u16 cmd, u8 status,
38 void *rp, size_t rp_len);
39
40struct mgmt_pending_cmd *mgmt_pending_find(unsigned short channel, u16 opcode,
41 struct hci_dev *hdev);
42struct mgmt_pending_cmd *mgmt_pending_find_data(unsigned short channel,
43 u16 opcode,
44 struct hci_dev *hdev,
45 const void *data);
46void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
47 void (*cb)(struct mgmt_pending_cmd *cmd, void *data),
48 void *data);
49struct mgmt_pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
50 struct hci_dev *hdev,
51 void *data, u16 len);
52void mgmt_pending_free(struct mgmt_pending_cmd *cmd);
53void mgmt_pending_remove(struct mgmt_pending_cmd *cmd);