Bluetooth: Implement automatic setup procedure for local adapters
[deliverable/linux.git] / net / bluetooth / mgmt.c
CommitLineData
0381101f
JH
1/*
2 BlueZ - Bluetooth protocol stack for Linux
3 Copyright (C) 2010 Nokia Corporation
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
23/* Bluetooth HCI Management interface */
24
25#include <asm/uaccess.h>
26#include <asm/unaligned.h>
27
28#include <net/bluetooth/bluetooth.h>
29#include <net/bluetooth/hci_core.h>
30#include <net/bluetooth/mgmt.h>
31
02d98129
JH
32#define MGMT_VERSION 0
33#define MGMT_REVISION 1
34
f7b64e69
JH
35static int cmd_status(struct sock *sk, u16 cmd, u8 status)
36{
37 struct sk_buff *skb;
38 struct mgmt_hdr *hdr;
39 struct mgmt_ev_cmd_status *ev;
40
41 BT_DBG("sock %p", sk);
42
43 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_ATOMIC);
44 if (!skb)
45 return -ENOMEM;
46
47 hdr = (void *) skb_put(skb, sizeof(*hdr));
48
49 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_STATUS);
50 hdr->len = cpu_to_le16(sizeof(*ev));
51
52 ev = (void *) skb_put(skb, sizeof(*ev));
53 ev->status = status;
54 put_unaligned_le16(cmd, &ev->opcode);
55
56 if (sock_queue_rcv_skb(sk, skb) < 0)
57 kfree_skb(skb);
58
59 return 0;
60}
61
02d98129
JH
62static int read_version(struct sock *sk)
63{
64 struct sk_buff *skb;
65 struct mgmt_hdr *hdr;
66 struct mgmt_ev_cmd_complete *ev;
67 struct mgmt_rp_read_version *rp;
68
69 BT_DBG("sock %p", sk);
70
71 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + sizeof(*rp), GFP_ATOMIC);
72 if (!skb)
73 return -ENOMEM;
74
75 hdr = (void *) skb_put(skb, sizeof(*hdr));
76 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE);
77 hdr->len = cpu_to_le16(sizeof(*ev) + sizeof(*rp));
78
79 ev = (void *) skb_put(skb, sizeof(*ev));
80 put_unaligned_le16(MGMT_OP_READ_VERSION, &ev->opcode);
81
82 rp = (void *) skb_put(skb, sizeof(*rp));
83 rp->version = MGMT_VERSION;
84 put_unaligned_le16(MGMT_REVISION, &rp->revision);
85
86 if (sock_queue_rcv_skb(sk, skb) < 0)
87 kfree_skb(skb);
88
89 return 0;
90}
91
faba42eb
JH
92static int read_index_list(struct sock *sk)
93{
94 struct sk_buff *skb;
95 struct mgmt_hdr *hdr;
96 struct mgmt_ev_cmd_complete *ev;
97 struct mgmt_rp_read_index_list *rp;
98 struct list_head *p;
99 size_t body_len;
100 u16 count;
101 int i;
102
103 BT_DBG("sock %p", sk);
104
105 read_lock(&hci_dev_list_lock);
106
107 count = 0;
108 list_for_each(p, &hci_dev_list) {
109 count++;
110 }
111
112 body_len = sizeof(*ev) + sizeof(*rp) + (2 * count);
113 skb = alloc_skb(sizeof(*hdr) + body_len, GFP_ATOMIC);
b2c60d42
JJ
114 if (!skb) {
115 read_unlock(&hci_dev_list_lock);
faba42eb 116 return -ENOMEM;
b2c60d42 117 }
faba42eb
JH
118
119 hdr = (void *) skb_put(skb, sizeof(*hdr));
120 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE);
121 hdr->len = cpu_to_le16(body_len);
122
123 ev = (void *) skb_put(skb, sizeof(*ev));
124 put_unaligned_le16(MGMT_OP_READ_INDEX_LIST, &ev->opcode);
125
126 rp = (void *) skb_put(skb, sizeof(*rp) + (2 * count));
127 put_unaligned_le16(count, &rp->num_controllers);
128
129 i = 0;
130 list_for_each(p, &hci_dev_list) {
131 struct hci_dev *d = list_entry(p, struct hci_dev, list);
ab81cbf9
JH
132
133 hci_del_off_timer(d);
134
135 if (test_bit(HCI_SETUP, &d->flags))
136 continue;
137
faba42eb
JH
138 put_unaligned_le16(d->id, &rp->index[i++]);
139 BT_DBG("Added hci%u", d->id);
140 }
141
142 read_unlock(&hci_dev_list_lock);
143
144 if (sock_queue_rcv_skb(sk, skb) < 0)
145 kfree_skb(skb);
146
147 return 0;
148}
149
f7b64e69 150static int read_controller_info(struct sock *sk, unsigned char *data, u16 len)
0381101f
JH
151{
152 struct sk_buff *skb;
153 struct mgmt_hdr *hdr;
f7b64e69
JH
154 struct mgmt_ev_cmd_complete *ev;
155 struct mgmt_rp_read_info *rp;
156 struct mgmt_cp_read_info *cp;
157 struct hci_dev *hdev;
158 u16 dev_id;
0381101f
JH
159
160 BT_DBG("sock %p", sk);
161
f7b64e69
JH
162 if (len != 2)
163 return cmd_status(sk, MGMT_OP_READ_INFO, EINVAL);
164
165 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + sizeof(*rp), GFP_ATOMIC);
0381101f 166 if (!skb)
e41d8b4e 167 return -ENOMEM;
0381101f
JH
168
169 hdr = (void *) skb_put(skb, sizeof(*hdr));
f7b64e69
JH
170 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE);
171 hdr->len = cpu_to_le16(sizeof(*ev) + sizeof(*rp));
0381101f
JH
172
173 ev = (void *) skb_put(skb, sizeof(*ev));
f7b64e69
JH
174 put_unaligned_le16(MGMT_OP_READ_INFO, &ev->opcode);
175
176 rp = (void *) skb_put(skb, sizeof(*rp));
177
178 cp = (void *) data;
179 dev_id = get_unaligned_le16(&cp->index);
180
181 BT_DBG("request for hci%u", dev_id);
182
183 hdev = hci_dev_get(dev_id);
184 if (!hdev) {
185 kfree_skb(skb);
186 return cmd_status(sk, MGMT_OP_READ_INFO, ENODEV);
187 }
188
ab81cbf9
JH
189 hci_del_off_timer(hdev);
190
f7b64e69
JH
191 hci_dev_lock_bh(hdev);
192
193 put_unaligned_le16(hdev->id, &rp->index);
194 rp->type = hdev->dev_type;
195
196 rp->powered = test_bit(HCI_UP, &hdev->flags);
197 rp->discoverable = test_bit(HCI_ISCAN, &hdev->flags);
198 rp->pairable = test_bit(HCI_PSCAN, &hdev->flags);
199
200 if (test_bit(HCI_AUTH, &hdev->flags))
201 rp->sec_mode = 3;
202 else if (hdev->ssp_mode > 0)
203 rp->sec_mode = 4;
204 else
205 rp->sec_mode = 2;
206
207 bacpy(&rp->bdaddr, &hdev->bdaddr);
208 memcpy(rp->features, hdev->features, 8);
209 memcpy(rp->dev_class, hdev->dev_class, 3);
210 put_unaligned_le16(hdev->manufacturer, &rp->manufacturer);
211 rp->hci_ver = hdev->hci_ver;
212 put_unaligned_le16(hdev->hci_rev, &rp->hci_rev);
213
214 hci_dev_unlock_bh(hdev);
215 hci_dev_put(hdev);
0381101f
JH
216
217 if (sock_queue_rcv_skb(sk, skb) < 0)
218 kfree_skb(skb);
e41d8b4e
JH
219
220 return 0;
0381101f
JH
221}
222
223int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
224{
225 unsigned char *buf;
226 struct mgmt_hdr *hdr;
227 u16 opcode, len;
228 int err;
229
230 BT_DBG("got %zu bytes", msglen);
231
232 if (msglen < sizeof(*hdr))
233 return -EINVAL;
234
235 buf = kmalloc(msglen, GFP_ATOMIC);
236 if (!buf)
237 return -ENOMEM;
238
239 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
240 err = -EFAULT;
241 goto done;
242 }
243
244 hdr = (struct mgmt_hdr *) buf;
245 opcode = get_unaligned_le16(&hdr->opcode);
246 len = get_unaligned_le16(&hdr->len);
247
248 if (len != msglen - sizeof(*hdr)) {
249 err = -EINVAL;
250 goto done;
251 }
252
253 switch (opcode) {
02d98129
JH
254 case MGMT_OP_READ_VERSION:
255 err = read_version(sk);
256 break;
faba42eb
JH
257 case MGMT_OP_READ_INDEX_LIST:
258 err = read_index_list(sk);
259 break;
f7b64e69
JH
260 case MGMT_OP_READ_INFO:
261 err = read_controller_info(sk, buf + sizeof(*hdr), len);
262 break;
0381101f
JH
263 default:
264 BT_DBG("Unknown op %u", opcode);
e41d8b4e 265 err = cmd_status(sk, opcode, 0x01);
0381101f
JH
266 break;
267 }
268
e41d8b4e
JH
269 if (err < 0)
270 goto done;
271
0381101f
JH
272 err = msglen;
273
274done:
275 kfree(buf);
276 return err;
277}
c71e97bf
JH
278
279static int mgmt_event(u16 event, void *data, u16 data_len)
280{
281 struct sk_buff *skb;
282 struct mgmt_hdr *hdr;
283
284 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_ATOMIC);
285 if (!skb)
286 return -ENOMEM;
287
288 bt_cb(skb)->channel = HCI_CHANNEL_CONTROL;
289
290 hdr = (void *) skb_put(skb, sizeof(*hdr));
291 hdr->opcode = cpu_to_le16(event);
292 hdr->len = cpu_to_le16(data_len);
293
294 memcpy(skb_put(skb, data_len), data, data_len);
295
296 hci_send_to_sock(NULL, skb);
297 kfree_skb(skb);
298
299 return 0;
300}
301
302int mgmt_index_added(u16 index)
303{
304 struct mgmt_ev_index_added ev;
305
306 put_unaligned_le16(index, &ev.index);
307
308 return mgmt_event(MGMT_EV_INDEX_ADDED, &ev, sizeof(ev));
309}
310
311int mgmt_index_removed(u16 index)
312{
313 struct mgmt_ev_index_added ev;
314
315 put_unaligned_le16(index, &ev.index);
316
317 return mgmt_event(MGMT_EV_INDEX_REMOVED, &ev, sizeof(ev));
318}
This page took 0.050163 seconds and 5 git commands to generate.