blob: 9d0e223855735f87b42b48e1acf657dde7920a46 [file] [log] [blame]
Johan Hedberg03811012010-12-08 00:21:06 +02001/*
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
Szymon Janc72359752011-02-17 14:16:32 +010025#include <linux/uaccess.h>
Johan Hedberg03811012010-12-08 00:21:06 +020026#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
Johan Hedberg02d98122010-12-13 21:07:04 +020032#define MGMT_VERSION 0
33#define MGMT_REVISION 1
34
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020035struct pending_cmd {
36 struct list_head list;
37 __u16 opcode;
38 int index;
Szymon Jancc68fb7f2011-03-22 13:12:19 +010039 void *param;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020040 struct sock *sk;
Johan Hedberge9a416b2011-02-19 12:05:56 -030041 void *user_data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020042};
43
Johannes Bergb5ad8b72011-06-01 08:54:45 +020044static LIST_HEAD(cmd_list);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020045
Szymon Janc4e51eae2011-02-25 19:05:48 +010046static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
Johan Hedbergf7b64e62010-12-13 21:07:06 +020047{
48 struct sk_buff *skb;
49 struct mgmt_hdr *hdr;
50 struct mgmt_ev_cmd_status *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -030051 int err;
Johan Hedbergf7b64e62010-12-13 21:07:06 +020052
Szymon Janc34eb5252011-02-28 14:10:08 +010053 BT_DBG("sock %p, index %u, cmd %u, status %u", sk, index, cmd, status);
Johan Hedbergf7b64e62010-12-13 21:07:06 +020054
55 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_ATOMIC);
56 if (!skb)
57 return -ENOMEM;
58
59 hdr = (void *) skb_put(skb, sizeof(*hdr));
60
61 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_STATUS);
Szymon Janc4e51eae2011-02-25 19:05:48 +010062 hdr->index = cpu_to_le16(index);
Johan Hedbergf7b64e62010-12-13 21:07:06 +020063 hdr->len = cpu_to_le16(sizeof(*ev));
64
65 ev = (void *) skb_put(skb, sizeof(*ev));
66 ev->status = status;
67 put_unaligned_le16(cmd, &ev->opcode);
68
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -030069 err = sock_queue_rcv_skb(sk, skb);
70 if (err < 0)
Johan Hedbergf7b64e62010-12-13 21:07:06 +020071 kfree_skb(skb);
72
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -030073 return err;
Johan Hedbergf7b64e62010-12-13 21:07:06 +020074}
75
Szymon Janc4e51eae2011-02-25 19:05:48 +010076static int cmd_complete(struct sock *sk, u16 index, u16 cmd, void *rp,
77 size_t rp_len)
Johan Hedberg02d98122010-12-13 21:07:04 +020078{
79 struct sk_buff *skb;
80 struct mgmt_hdr *hdr;
81 struct mgmt_ev_cmd_complete *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -030082 int err;
Johan Hedberg02d98122010-12-13 21:07:04 +020083
84 BT_DBG("sock %p", sk);
85
Johan Hedberga38528f2011-01-22 06:46:43 +020086 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + rp_len, GFP_ATOMIC);
Johan Hedberg02d98122010-12-13 21:07:04 +020087 if (!skb)
88 return -ENOMEM;
89
90 hdr = (void *) skb_put(skb, sizeof(*hdr));
Johan Hedberga38528f2011-01-22 06:46:43 +020091
Johan Hedberg02d98122010-12-13 21:07:04 +020092 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE);
Szymon Janc4e51eae2011-02-25 19:05:48 +010093 hdr->index = cpu_to_le16(index);
Johan Hedberga38528f2011-01-22 06:46:43 +020094 hdr->len = cpu_to_le16(sizeof(*ev) + rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +020095
Johan Hedberga38528f2011-01-22 06:46:43 +020096 ev = (void *) skb_put(skb, sizeof(*ev) + rp_len);
97 put_unaligned_le16(cmd, &ev->opcode);
Szymon Janc8020c162011-02-28 14:09:50 +010098
99 if (rp)
100 memcpy(ev->data, rp, rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200101
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300102 err = sock_queue_rcv_skb(sk, skb);
103 if (err < 0)
Johan Hedberg02d98122010-12-13 21:07:04 +0200104 kfree_skb(skb);
105
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300106 return err;;
Johan Hedberg02d98122010-12-13 21:07:04 +0200107}
108
Johan Hedberga38528f2011-01-22 06:46:43 +0200109static int read_version(struct sock *sk)
110{
111 struct mgmt_rp_read_version rp;
112
113 BT_DBG("sock %p", sk);
114
115 rp.version = MGMT_VERSION;
116 put_unaligned_le16(MGMT_REVISION, &rp.revision);
117
Szymon Janc4e51eae2011-02-25 19:05:48 +0100118 return cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, &rp,
119 sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200120}
121
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200122static int read_index_list(struct sock *sk)
123{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200124 struct mgmt_rp_read_index_list *rp;
125 struct list_head *p;
Johan Hedberga38528f2011-01-22 06:46:43 +0200126 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200127 u16 count;
Johan Hedberga38528f2011-01-22 06:46:43 +0200128 int i, err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200129
130 BT_DBG("sock %p", sk);
131
132 read_lock(&hci_dev_list_lock);
133
134 count = 0;
135 list_for_each(p, &hci_dev_list) {
136 count++;
137 }
138
Johan Hedberga38528f2011-01-22 06:46:43 +0200139 rp_len = sizeof(*rp) + (2 * count);
140 rp = kmalloc(rp_len, GFP_ATOMIC);
141 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100142 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200143 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100144 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200145
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200146 put_unaligned_le16(count, &rp->num_controllers);
147
148 i = 0;
149 list_for_each(p, &hci_dev_list) {
150 struct hci_dev *d = list_entry(p, struct hci_dev, list);
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200151
152 hci_del_off_timer(d);
153
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200154 set_bit(HCI_MGMT, &d->flags);
155
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200156 if (test_bit(HCI_SETUP, &d->flags))
157 continue;
158
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200159 put_unaligned_le16(d->id, &rp->index[i++]);
160 BT_DBG("Added hci%u", d->id);
161 }
162
163 read_unlock(&hci_dev_list_lock);
164
Szymon Janc4e51eae2011-02-25 19:05:48 +0100165 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST, rp,
166 rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200167
Johan Hedberga38528f2011-01-22 06:46:43 +0200168 kfree(rp);
169
170 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200171}
172
Szymon Janc4e51eae2011-02-25 19:05:48 +0100173static int read_controller_info(struct sock *sk, u16 index)
Johan Hedberg03811012010-12-08 00:21:06 +0200174{
Johan Hedberga38528f2011-01-22 06:46:43 +0200175 struct mgmt_rp_read_info rp;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200176 struct hci_dev *hdev;
Johan Hedberg03811012010-12-08 00:21:06 +0200177
Szymon Janc4e51eae2011-02-25 19:05:48 +0100178 BT_DBG("sock %p hci%u", sk, index);
Johan Hedberg03811012010-12-08 00:21:06 +0200179
Szymon Janc4e51eae2011-02-25 19:05:48 +0100180 hdev = hci_dev_get(index);
Johan Hedberga38528f2011-01-22 06:46:43 +0200181 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100182 return cmd_status(sk, index, MGMT_OP_READ_INFO, ENODEV);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200183
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200184 hci_del_off_timer(hdev);
185
Andre Guedes8c156c32011-07-07 10:30:36 -0300186 hci_dev_lock_bh(hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200187
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200188 set_bit(HCI_MGMT, &hdev->flags);
189
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200190 memset(&rp, 0, sizeof(rp));
191
Johan Hedberga38528f2011-01-22 06:46:43 +0200192 rp.type = hdev->dev_type;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200193
Johan Hedberga38528f2011-01-22 06:46:43 +0200194 rp.powered = test_bit(HCI_UP, &hdev->flags);
195 rp.connectable = test_bit(HCI_PSCAN, &hdev->flags);
196 rp.discoverable = test_bit(HCI_ISCAN, &hdev->flags);
197 rp.pairable = test_bit(HCI_PSCAN, &hdev->flags);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200198
199 if (test_bit(HCI_AUTH, &hdev->flags))
Johan Hedberga38528f2011-01-22 06:46:43 +0200200 rp.sec_mode = 3;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200201 else if (hdev->ssp_mode > 0)
Johan Hedberga38528f2011-01-22 06:46:43 +0200202 rp.sec_mode = 4;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200203 else
Johan Hedberga38528f2011-01-22 06:46:43 +0200204 rp.sec_mode = 2;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200205
Johan Hedberga38528f2011-01-22 06:46:43 +0200206 bacpy(&rp.bdaddr, &hdev->bdaddr);
207 memcpy(rp.features, hdev->features, 8);
208 memcpy(rp.dev_class, hdev->dev_class, 3);
209 put_unaligned_le16(hdev->manufacturer, &rp.manufacturer);
210 rp.hci_ver = hdev->hci_ver;
211 put_unaligned_le16(hdev->hci_rev, &rp.hci_rev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200212
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200213 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
214
Andre Guedes8c156c32011-07-07 10:30:36 -0300215 hci_dev_unlock_bh(hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200216 hci_dev_put(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200217
Szymon Janc4e51eae2011-02-25 19:05:48 +0100218 return cmd_complete(sk, index, MGMT_OP_READ_INFO, &rp, sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +0200219}
220
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200221static void mgmt_pending_free(struct pending_cmd *cmd)
222{
223 sock_put(cmd->sk);
Szymon Jancc68fb7f2011-03-22 13:12:19 +0100224 kfree(cmd->param);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200225 kfree(cmd);
226}
227
Johan Hedberg366a0332011-02-19 12:05:55 -0300228static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
229 u16 index, void *data, u16 len)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200230{
231 struct pending_cmd *cmd;
232
233 cmd = kmalloc(sizeof(*cmd), GFP_ATOMIC);
234 if (!cmd)
Johan Hedberg366a0332011-02-19 12:05:55 -0300235 return NULL;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200236
237 cmd->opcode = opcode;
238 cmd->index = index;
239
Szymon Jancc68fb7f2011-03-22 13:12:19 +0100240 cmd->param = kmalloc(len, GFP_ATOMIC);
241 if (!cmd->param) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200242 kfree(cmd);
Johan Hedberg366a0332011-02-19 12:05:55 -0300243 return NULL;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200244 }
245
Szymon Janc8fce6352011-03-22 13:12:20 +0100246 if (data)
247 memcpy(cmd->param, data, len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200248
249 cmd->sk = sk;
250 sock_hold(sk);
251
252 list_add(&cmd->list, &cmd_list);
253
Johan Hedberg366a0332011-02-19 12:05:55 -0300254 return cmd;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200255}
256
257static void mgmt_pending_foreach(u16 opcode, int index,
258 void (*cb)(struct pending_cmd *cmd, void *data),
259 void *data)
260{
261 struct list_head *p, *n;
262
263 list_for_each_safe(p, n, &cmd_list) {
264 struct pending_cmd *cmd;
265
266 cmd = list_entry(p, struct pending_cmd, list);
267
268 if (cmd->opcode != opcode)
269 continue;
270
271 if (index >= 0 && cmd->index != index)
272 continue;
273
274 cb(cmd, data);
275 }
276}
277
278static struct pending_cmd *mgmt_pending_find(u16 opcode, int index)
279{
280 struct list_head *p;
281
282 list_for_each(p, &cmd_list) {
283 struct pending_cmd *cmd;
284
285 cmd = list_entry(p, struct pending_cmd, list);
286
287 if (cmd->opcode != opcode)
288 continue;
289
290 if (index >= 0 && cmd->index != index)
291 continue;
292
293 return cmd;
294 }
295
296 return NULL;
297}
298
Johan Hedberga664b5b2011-02-19 12:06:02 -0300299static void mgmt_pending_remove(struct pending_cmd *cmd)
Johan Hedberg73f22f62010-12-29 16:00:25 +0200300{
Johan Hedberg73f22f62010-12-29 16:00:25 +0200301 list_del(&cmd->list);
302 mgmt_pending_free(cmd);
303}
304
Szymon Janc4e51eae2011-02-25 19:05:48 +0100305static int set_powered(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200306{
Johan Hedberg72a734e2010-12-30 00:38:22 +0200307 struct mgmt_mode *cp;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200308 struct hci_dev *hdev;
Johan Hedberg366a0332011-02-19 12:05:55 -0300309 struct pending_cmd *cmd;
Johan Hedberg366a0332011-02-19 12:05:55 -0300310 int err, up;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200311
312 cp = (void *) data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200313
Szymon Janc4e51eae2011-02-25 19:05:48 +0100314 BT_DBG("request for hci%u", index);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200315
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100316 if (len != sizeof(*cp))
317 return cmd_status(sk, index, MGMT_OP_SET_POWERED, EINVAL);
318
Szymon Janc4e51eae2011-02-25 19:05:48 +0100319 hdev = hci_dev_get(index);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200320 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100321 return cmd_status(sk, index, MGMT_OP_SET_POWERED, ENODEV);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200322
Andre Guedes8c156c32011-07-07 10:30:36 -0300323 hci_dev_lock_bh(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200324
325 up = test_bit(HCI_UP, &hdev->flags);
Johan Hedberg72a734e2010-12-30 00:38:22 +0200326 if ((cp->val && up) || (!cp->val && !up)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100327 err = cmd_status(sk, index, MGMT_OP_SET_POWERED, EALREADY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200328 goto failed;
329 }
330
Szymon Janc4e51eae2011-02-25 19:05:48 +0100331 if (mgmt_pending_find(MGMT_OP_SET_POWERED, index)) {
332 err = cmd_status(sk, index, MGMT_OP_SET_POWERED, EBUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200333 goto failed;
334 }
335
Szymon Janc4e51eae2011-02-25 19:05:48 +0100336 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -0300337 if (!cmd) {
338 err = -ENOMEM;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200339 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -0300340 }
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200341
Johan Hedberg72a734e2010-12-30 00:38:22 +0200342 if (cp->val)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200343 queue_work(hdev->workqueue, &hdev->power_on);
344 else
345 queue_work(hdev->workqueue, &hdev->power_off);
346
Johan Hedberg366a0332011-02-19 12:05:55 -0300347 err = 0;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200348
349failed:
Andre Guedes8c156c32011-07-07 10:30:36 -0300350 hci_dev_unlock_bh(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200351 hci_dev_put(hdev);
Johan Hedberg366a0332011-02-19 12:05:55 -0300352 return err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200353}
354
Szymon Janc4e51eae2011-02-25 19:05:48 +0100355static int set_discoverable(struct sock *sk, u16 index, unsigned char *data,
356 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +0200357{
Johan Hedberg72a734e2010-12-30 00:38:22 +0200358 struct mgmt_mode *cp;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200359 struct hci_dev *hdev;
Johan Hedberg366a0332011-02-19 12:05:55 -0300360 struct pending_cmd *cmd;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200361 u8 scan;
362 int err;
363
364 cp = (void *) data;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200365
Szymon Janc4e51eae2011-02-25 19:05:48 +0100366 BT_DBG("request for hci%u", index);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200367
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100368 if (len != sizeof(*cp))
369 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, EINVAL);
370
Szymon Janc4e51eae2011-02-25 19:05:48 +0100371 hdev = hci_dev_get(index);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200372 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100373 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, ENODEV);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200374
Andre Guedes8c156c32011-07-07 10:30:36 -0300375 hci_dev_lock_bh(hdev);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200376
377 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100378 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, ENETDOWN);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200379 goto failed;
380 }
381
Szymon Janc4e51eae2011-02-25 19:05:48 +0100382 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, index) ||
383 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, index)) {
384 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, EBUSY);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200385 goto failed;
386 }
387
Johan Hedberg72a734e2010-12-30 00:38:22 +0200388 if (cp->val == test_bit(HCI_ISCAN, &hdev->flags) &&
Johan Hedberg73f22f62010-12-29 16:00:25 +0200389 test_bit(HCI_PSCAN, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100390 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, EALREADY);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200391 goto failed;
392 }
393
Szymon Janc4e51eae2011-02-25 19:05:48 +0100394 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -0300395 if (!cmd) {
396 err = -ENOMEM;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200397 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -0300398 }
Johan Hedberg73f22f62010-12-29 16:00:25 +0200399
400 scan = SCAN_PAGE;
401
Johan Hedberg72a734e2010-12-30 00:38:22 +0200402 if (cp->val)
Johan Hedberg73f22f62010-12-29 16:00:25 +0200403 scan |= SCAN_INQUIRY;
404
405 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
406 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -0300407 mgmt_pending_remove(cmd);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200408
409failed:
Andre Guedes8c156c32011-07-07 10:30:36 -0300410 hci_dev_unlock_bh(hdev);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200411 hci_dev_put(hdev);
412
413 return err;
414}
415
Szymon Janc4e51eae2011-02-25 19:05:48 +0100416static int set_connectable(struct sock *sk, u16 index, unsigned char *data,
417 u16 len)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200418{
Johan Hedberg72a734e2010-12-30 00:38:22 +0200419 struct mgmt_mode *cp;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200420 struct hci_dev *hdev;
Johan Hedberg366a0332011-02-19 12:05:55 -0300421 struct pending_cmd *cmd;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200422 u8 scan;
423 int err;
424
425 cp = (void *) data;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200426
Szymon Janc4e51eae2011-02-25 19:05:48 +0100427 BT_DBG("request for hci%u", index);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200428
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100429 if (len != sizeof(*cp))
430 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, EINVAL);
431
Szymon Janc4e51eae2011-02-25 19:05:48 +0100432 hdev = hci_dev_get(index);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200433 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100434 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, ENODEV);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200435
Andre Guedes8c156c32011-07-07 10:30:36 -0300436 hci_dev_lock_bh(hdev);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200437
438 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100439 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, ENETDOWN);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200440 goto failed;
441 }
442
Szymon Janc4e51eae2011-02-25 19:05:48 +0100443 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, index) ||
444 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, index)) {
445 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, EBUSY);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200446 goto failed;
447 }
448
Johan Hedberg72a734e2010-12-30 00:38:22 +0200449 if (cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100450 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, EALREADY);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200451 goto failed;
452 }
453
Szymon Janc4e51eae2011-02-25 19:05:48 +0100454 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -0300455 if (!cmd) {
456 err = -ENOMEM;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200457 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -0300458 }
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200459
Johan Hedberg72a734e2010-12-30 00:38:22 +0200460 if (cp->val)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200461 scan = SCAN_PAGE;
462 else
463 scan = 0;
464
465 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
466 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -0300467 mgmt_pending_remove(cmd);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200468
469failed:
Andre Guedes8c156c32011-07-07 10:30:36 -0300470 hci_dev_unlock_bh(hdev);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200471 hci_dev_put(hdev);
472
473 return err;
474}
475
Szymon Janc4e51eae2011-02-25 19:05:48 +0100476static int mgmt_event(u16 event, u16 index, void *data, u16 data_len,
477 struct sock *skip_sk)
Johan Hedbergc542a062011-01-26 13:11:03 +0200478{
479 struct sk_buff *skb;
480 struct mgmt_hdr *hdr;
481
482 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_ATOMIC);
483 if (!skb)
484 return -ENOMEM;
485
486 bt_cb(skb)->channel = HCI_CHANNEL_CONTROL;
487
488 hdr = (void *) skb_put(skb, sizeof(*hdr));
489 hdr->opcode = cpu_to_le16(event);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100490 hdr->index = cpu_to_le16(index);
Johan Hedbergc542a062011-01-26 13:11:03 +0200491 hdr->len = cpu_to_le16(data_len);
492
Szymon Janc4e51eae2011-02-25 19:05:48 +0100493 if (data)
494 memcpy(skb_put(skb, data_len), data, data_len);
Johan Hedbergc542a062011-01-26 13:11:03 +0200495
496 hci_send_to_sock(NULL, skb, skip_sk);
497 kfree_skb(skb);
498
499 return 0;
500}
501
Johan Hedberg053f0212011-01-26 13:07:10 +0200502static int send_mode_rsp(struct sock *sk, u16 opcode, u16 index, u8 val)
503{
Johan Hedberga38528f2011-01-22 06:46:43 +0200504 struct mgmt_mode rp;
Johan Hedberg053f0212011-01-26 13:07:10 +0200505
Johan Hedberga38528f2011-01-22 06:46:43 +0200506 rp.val = val;
Johan Hedberg053f0212011-01-26 13:07:10 +0200507
Szymon Janc4e51eae2011-02-25 19:05:48 +0100508 return cmd_complete(sk, index, opcode, &rp, sizeof(rp));
Johan Hedberg053f0212011-01-26 13:07:10 +0200509}
510
Szymon Janc4e51eae2011-02-25 19:05:48 +0100511static int set_pairable(struct sock *sk, u16 index, unsigned char *data,
512 u16 len)
Johan Hedbergc542a062011-01-26 13:11:03 +0200513{
514 struct mgmt_mode *cp, ev;
515 struct hci_dev *hdev;
Johan Hedbergc542a062011-01-26 13:11:03 +0200516 int err;
517
518 cp = (void *) data;
Johan Hedbergc542a062011-01-26 13:11:03 +0200519
Szymon Janc4e51eae2011-02-25 19:05:48 +0100520 BT_DBG("request for hci%u", index);
Johan Hedbergc542a062011-01-26 13:11:03 +0200521
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100522 if (len != sizeof(*cp))
523 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE, EINVAL);
524
Szymon Janc4e51eae2011-02-25 19:05:48 +0100525 hdev = hci_dev_get(index);
Johan Hedbergc542a062011-01-26 13:11:03 +0200526 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100527 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE, ENODEV);
Johan Hedbergc542a062011-01-26 13:11:03 +0200528
Andre Guedes8c156c32011-07-07 10:30:36 -0300529 hci_dev_lock_bh(hdev);
Johan Hedbergc542a062011-01-26 13:11:03 +0200530
531 if (cp->val)
532 set_bit(HCI_PAIRABLE, &hdev->flags);
533 else
534 clear_bit(HCI_PAIRABLE, &hdev->flags);
535
Szymon Janc4e51eae2011-02-25 19:05:48 +0100536 err = send_mode_rsp(sk, MGMT_OP_SET_PAIRABLE, index, cp->val);
Johan Hedbergc542a062011-01-26 13:11:03 +0200537 if (err < 0)
538 goto failed;
539
Johan Hedbergc542a062011-01-26 13:11:03 +0200540 ev.val = cp->val;
541
Szymon Janc4e51eae2011-02-25 19:05:48 +0100542 err = mgmt_event(MGMT_EV_PAIRABLE, index, &ev, sizeof(ev), sk);
Johan Hedbergc542a062011-01-26 13:11:03 +0200543
544failed:
Andre Guedes8c156c32011-07-07 10:30:36 -0300545 hci_dev_unlock_bh(hdev);
Johan Hedbergc542a062011-01-26 13:11:03 +0200546 hci_dev_put(hdev);
547
548 return err;
549}
550
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300551#define EIR_FLAGS 0x01 /* flags */
552#define EIR_UUID16_SOME 0x02 /* 16-bit UUID, more available */
553#define EIR_UUID16_ALL 0x03 /* 16-bit UUID, all listed */
554#define EIR_UUID32_SOME 0x04 /* 32-bit UUID, more available */
555#define EIR_UUID32_ALL 0x05 /* 32-bit UUID, all listed */
556#define EIR_UUID128_SOME 0x06 /* 128-bit UUID, more available */
557#define EIR_UUID128_ALL 0x07 /* 128-bit UUID, all listed */
558#define EIR_NAME_SHORT 0x08 /* shortened local name */
559#define EIR_NAME_COMPLETE 0x09 /* complete local name */
560#define EIR_TX_POWER 0x0A /* transmit power level */
561#define EIR_DEVICE_ID 0x10 /* device ID */
562
563#define PNP_INFO_SVCLASS_ID 0x1200
564
565static u8 bluetooth_base_uuid[] = {
566 0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80,
567 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
568};
569
570static u16 get_uuid16(u8 *uuid128)
571{
572 u32 val;
573 int i;
574
575 for (i = 0; i < 12; i++) {
576 if (bluetooth_base_uuid[i] != uuid128[i])
577 return 0;
578 }
579
580 memcpy(&val, &uuid128[12], 4);
581
582 val = le32_to_cpu(val);
583 if (val > 0xffff)
584 return 0;
585
586 return (u16) val;
587}
588
589static void create_eir(struct hci_dev *hdev, u8 *data)
590{
591 u8 *ptr = data;
592 u16 eir_len = 0;
593 u16 uuid16_list[HCI_MAX_EIR_LENGTH / sizeof(u16)];
594 int i, truncated = 0;
595 struct list_head *p;
596 size_t name_len;
597
598 name_len = strlen(hdev->dev_name);
599
600 if (name_len > 0) {
601 /* EIR Data type */
602 if (name_len > 48) {
603 name_len = 48;
604 ptr[1] = EIR_NAME_SHORT;
605 } else
606 ptr[1] = EIR_NAME_COMPLETE;
607
608 /* EIR Data length */
609 ptr[0] = name_len + 1;
610
611 memcpy(ptr + 2, hdev->dev_name, name_len);
612
613 eir_len += (name_len + 2);
614 ptr += (name_len + 2);
615 }
616
617 memset(uuid16_list, 0, sizeof(uuid16_list));
618
619 /* Group all UUID16 types */
620 list_for_each(p, &hdev->uuids) {
621 struct bt_uuid *uuid = list_entry(p, struct bt_uuid, list);
622 u16 uuid16;
623
624 uuid16 = get_uuid16(uuid->uuid);
625 if (uuid16 == 0)
626 return;
627
628 if (uuid16 < 0x1100)
629 continue;
630
631 if (uuid16 == PNP_INFO_SVCLASS_ID)
632 continue;
633
634 /* Stop if not enough space to put next UUID */
635 if (eir_len + 2 + sizeof(u16) > HCI_MAX_EIR_LENGTH) {
636 truncated = 1;
637 break;
638 }
639
640 /* Check for duplicates */
641 for (i = 0; uuid16_list[i] != 0; i++)
642 if (uuid16_list[i] == uuid16)
643 break;
644
645 if (uuid16_list[i] == 0) {
646 uuid16_list[i] = uuid16;
647 eir_len += sizeof(u16);
648 }
649 }
650
651 if (uuid16_list[0] != 0) {
652 u8 *length = ptr;
653
654 /* EIR Data type */
655 ptr[1] = truncated ? EIR_UUID16_SOME : EIR_UUID16_ALL;
656
657 ptr += 2;
658 eir_len += 2;
659
660 for (i = 0; uuid16_list[i] != 0; i++) {
661 *ptr++ = (uuid16_list[i] & 0x00ff);
662 *ptr++ = (uuid16_list[i] & 0xff00) >> 8;
663 }
664
665 /* EIR Data length */
666 *length = (i * sizeof(u16)) + 1;
667 }
668}
669
670static int update_eir(struct hci_dev *hdev)
671{
672 struct hci_cp_write_eir cp;
673
674 if (!(hdev->features[6] & LMP_EXT_INQ))
675 return 0;
676
677 if (hdev->ssp_mode == 0)
678 return 0;
679
680 if (test_bit(HCI_SERVICE_CACHE, &hdev->flags))
681 return 0;
682
683 memset(&cp, 0, sizeof(cp));
684
685 create_eir(hdev, cp.data);
686
687 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
688 return 0;
689
690 memcpy(hdev->eir, cp.data, sizeof(cp.data));
691
692 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
693}
694
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200695static u8 get_service_classes(struct hci_dev *hdev)
696{
697 struct list_head *p;
698 u8 val = 0;
699
700 list_for_each(p, &hdev->uuids) {
701 struct bt_uuid *uuid = list_entry(p, struct bt_uuid, list);
702
703 val |= uuid->svc_hint;
704 }
705
706 return val;
707}
708
709static int update_class(struct hci_dev *hdev)
710{
711 u8 cod[3];
712
713 BT_DBG("%s", hdev->name);
714
715 if (test_bit(HCI_SERVICE_CACHE, &hdev->flags))
716 return 0;
717
718 cod[0] = hdev->minor_class;
719 cod[1] = hdev->major_class;
720 cod[2] = get_service_classes(hdev);
721
722 if (memcmp(cod, hdev->dev_class, 3) == 0)
723 return 0;
724
725 return hci_send_cmd(hdev, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
726}
727
Szymon Janc4e51eae2011-02-25 19:05:48 +0100728static int add_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200729{
730 struct mgmt_cp_add_uuid *cp;
731 struct hci_dev *hdev;
732 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200733 int err;
734
735 cp = (void *) data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200736
Szymon Janc4e51eae2011-02-25 19:05:48 +0100737 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200738
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100739 if (len != sizeof(*cp))
740 return cmd_status(sk, index, MGMT_OP_ADD_UUID, EINVAL);
741
Szymon Janc4e51eae2011-02-25 19:05:48 +0100742 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200743 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100744 return cmd_status(sk, index, MGMT_OP_ADD_UUID, ENODEV);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200745
Andre Guedes8c156c32011-07-07 10:30:36 -0300746 hci_dev_lock_bh(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200747
748 uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC);
749 if (!uuid) {
750 err = -ENOMEM;
751 goto failed;
752 }
753
754 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200755 uuid->svc_hint = cp->svc_hint;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200756
757 list_add(&uuid->list, &hdev->uuids);
758
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200759 err = update_class(hdev);
760 if (err < 0)
761 goto failed;
762
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300763 err = update_eir(hdev);
764 if (err < 0)
765 goto failed;
766
Szymon Janc4e51eae2011-02-25 19:05:48 +0100767 err = cmd_complete(sk, index, MGMT_OP_ADD_UUID, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200768
769failed:
Andre Guedes8c156c32011-07-07 10:30:36 -0300770 hci_dev_unlock_bh(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200771 hci_dev_put(hdev);
772
773 return err;
774}
775
Szymon Janc4e51eae2011-02-25 19:05:48 +0100776static int remove_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200777{
778 struct list_head *p, *n;
Szymon Janc779cb852011-02-25 19:05:47 +0100779 struct mgmt_cp_remove_uuid *cp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200780 struct hci_dev *hdev;
781 u8 bt_uuid_any[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200782 int err, found;
783
784 cp = (void *) data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200785
Szymon Janc4e51eae2011-02-25 19:05:48 +0100786 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200787
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100788 if (len != sizeof(*cp))
789 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID, EINVAL);
790
Szymon Janc4e51eae2011-02-25 19:05:48 +0100791 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200792 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100793 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID, ENODEV);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200794
Andre Guedes8c156c32011-07-07 10:30:36 -0300795 hci_dev_lock_bh(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200796
797 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
798 err = hci_uuids_clear(hdev);
799 goto unlock;
800 }
801
802 found = 0;
803
804 list_for_each_safe(p, n, &hdev->uuids) {
805 struct bt_uuid *match = list_entry(p, struct bt_uuid, list);
806
807 if (memcmp(match->uuid, cp->uuid, 16) != 0)
808 continue;
809
810 list_del(&match->list);
811 found++;
812 }
813
814 if (found == 0) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100815 err = cmd_status(sk, index, MGMT_OP_REMOVE_UUID, ENOENT);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200816 goto unlock;
817 }
818
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200819 err = update_class(hdev);
820 if (err < 0)
821 goto unlock;
822
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300823 err = update_eir(hdev);
824 if (err < 0)
825 goto unlock;
826
Szymon Janc4e51eae2011-02-25 19:05:48 +0100827 err = cmd_complete(sk, index, MGMT_OP_REMOVE_UUID, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200828
829unlock:
Andre Guedes8c156c32011-07-07 10:30:36 -0300830 hci_dev_unlock_bh(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200831 hci_dev_put(hdev);
832
833 return err;
834}
835
Szymon Janc4e51eae2011-02-25 19:05:48 +0100836static int set_dev_class(struct sock *sk, u16 index, unsigned char *data,
837 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200838{
839 struct hci_dev *hdev;
840 struct mgmt_cp_set_dev_class *cp;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200841 int err;
842
843 cp = (void *) data;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200844
Szymon Janc4e51eae2011-02-25 19:05:48 +0100845 BT_DBG("request for hci%u", index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200846
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100847 if (len != sizeof(*cp))
848 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS, EINVAL);
849
Szymon Janc4e51eae2011-02-25 19:05:48 +0100850 hdev = hci_dev_get(index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200851 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100852 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS, ENODEV);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200853
Andre Guedes8c156c32011-07-07 10:30:36 -0300854 hci_dev_lock_bh(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200855
856 hdev->major_class = cp->major;
857 hdev->minor_class = cp->minor;
858
859 err = update_class(hdev);
860
861 if (err == 0)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100862 err = cmd_complete(sk, index, MGMT_OP_SET_DEV_CLASS, NULL, 0);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200863
Andre Guedes8c156c32011-07-07 10:30:36 -0300864 hci_dev_unlock_bh(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200865 hci_dev_put(hdev);
866
867 return err;
868}
869
Szymon Janc4e51eae2011-02-25 19:05:48 +0100870static int set_service_cache(struct sock *sk, u16 index, unsigned char *data,
871 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200872{
873 struct hci_dev *hdev;
874 struct mgmt_cp_set_service_cache *cp;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200875 int err;
876
877 cp = (void *) data;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200878
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100879 if (len != sizeof(*cp))
Szymon Jancb8534e0f2011-03-01 16:55:34 +0100880 return cmd_status(sk, index, MGMT_OP_SET_SERVICE_CACHE, EINVAL);
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100881
Szymon Janc4e51eae2011-02-25 19:05:48 +0100882 hdev = hci_dev_get(index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200883 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100884 return cmd_status(sk, index, MGMT_OP_SET_SERVICE_CACHE, ENODEV);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200885
Andre Guedes8c156c32011-07-07 10:30:36 -0300886 hci_dev_lock_bh(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200887
Szymon Janc4e51eae2011-02-25 19:05:48 +0100888 BT_DBG("hci%u enable %d", index, cp->enable);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200889
890 if (cp->enable) {
891 set_bit(HCI_SERVICE_CACHE, &hdev->flags);
892 err = 0;
893 } else {
894 clear_bit(HCI_SERVICE_CACHE, &hdev->flags);
895 err = update_class(hdev);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300896 if (err == 0)
897 err = update_eir(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200898 }
899
900 if (err == 0)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100901 err = cmd_complete(sk, index, MGMT_OP_SET_SERVICE_CACHE, NULL,
902 0);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200903
Andre Guedes8c156c32011-07-07 10:30:36 -0300904 hci_dev_unlock_bh(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200905 hci_dev_put(hdev);
906
907 return err;
908}
909
Szymon Janc4e51eae2011-02-25 19:05:48 +0100910static int load_keys(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200911{
912 struct hci_dev *hdev;
913 struct mgmt_cp_load_keys *cp;
Szymon Janc4e51eae2011-02-25 19:05:48 +0100914 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -0300915 int i;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200916
917 cp = (void *) data;
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100918
919 if (len < sizeof(*cp))
Gustavo F. Padovanb7059132011-10-14 19:23:27 -0300920 return cmd_status(sk, index, MGMT_OP_LOAD_KEYS, EINVAL);
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100921
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200922 key_count = get_unaligned_le16(&cp->key_count);
923
924 expected_len = sizeof(*cp) + key_count * sizeof(struct mgmt_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -0300925 if (expected_len != len) {
926 BT_ERR("load_keys: expected %u bytes, got %u bytes",
927 len, expected_len);
Gustavo F. Padovanb7059132011-10-14 19:23:27 -0300928 return cmd_status(sk, index, MGMT_OP_LOAD_KEYS, EINVAL);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200929 }
930
Szymon Janc4e51eae2011-02-25 19:05:48 +0100931 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200932 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100933 return cmd_status(sk, index, MGMT_OP_LOAD_KEYS, ENODEV);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200934
Szymon Janc4e51eae2011-02-25 19:05:48 +0100935 BT_DBG("hci%u debug_keys %u key_count %u", index, cp->debug_keys,
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200936 key_count);
937
Andre Guedes8c156c32011-07-07 10:30:36 -0300938 hci_dev_lock_bh(hdev);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200939
940 hci_link_keys_clear(hdev);
941
942 set_bit(HCI_LINK_KEYS, &hdev->flags);
943
944 if (cp->debug_keys)
945 set_bit(HCI_DEBUG_KEYS, &hdev->flags);
946 else
947 clear_bit(HCI_DEBUG_KEYS, &hdev->flags);
948
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -0300949 for (i = 0; i < key_count; i++) {
950 struct mgmt_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200951
Johan Hedbergd25e28a2011-04-28 11:28:59 -0700952 hci_add_link_key(hdev, NULL, 0, &key->bdaddr, key->val, key->type,
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200953 key->pin_len);
954 }
955
Andre Guedes8c156c32011-07-07 10:30:36 -0300956 hci_dev_unlock_bh(hdev);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200957 hci_dev_put(hdev);
958
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -0300959 return 0;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200960}
961
Szymon Janc4e51eae2011-02-25 19:05:48 +0100962static int remove_key(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200963{
964 struct hci_dev *hdev;
965 struct mgmt_cp_remove_key *cp;
966 struct hci_conn *conn;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200967 int err;
968
969 cp = (void *) data;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200970
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100971 if (len != sizeof(*cp))
972 return cmd_status(sk, index, MGMT_OP_REMOVE_KEY, EINVAL);
973
Szymon Janc4e51eae2011-02-25 19:05:48 +0100974 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200975 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100976 return cmd_status(sk, index, MGMT_OP_REMOVE_KEY, ENODEV);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200977
Andre Guedes8c156c32011-07-07 10:30:36 -0300978 hci_dev_lock_bh(hdev);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200979
980 err = hci_remove_link_key(hdev, &cp->bdaddr);
981 if (err < 0) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100982 err = cmd_status(sk, index, MGMT_OP_REMOVE_KEY, -err);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200983 goto unlock;
984 }
985
986 err = 0;
987
988 if (!test_bit(HCI_UP, &hdev->flags) || !cp->disconnect)
989 goto unlock;
990
991 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
992 if (conn) {
993 struct hci_cp_disconnect dc;
994
995 put_unaligned_le16(conn->handle, &dc.handle);
996 dc.reason = 0x13; /* Remote User Terminated Connection */
Anderson Lizardo94ac0272011-06-13 15:42:03 -0400997 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200998 }
999
1000unlock:
Andre Guedes8c156c32011-07-07 10:30:36 -03001001 hci_dev_unlock_bh(hdev);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001002 hci_dev_put(hdev);
1003
1004 return err;
1005}
1006
Szymon Janc4e51eae2011-02-25 19:05:48 +01001007static int disconnect(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02001008{
1009 struct hci_dev *hdev;
1010 struct mgmt_cp_disconnect *cp;
1011 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03001012 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001013 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001014 int err;
1015
1016 BT_DBG("");
1017
1018 cp = (void *) data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001019
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001020 if (len != sizeof(*cp))
1021 return cmd_status(sk, index, MGMT_OP_DISCONNECT, EINVAL);
1022
Szymon Janc4e51eae2011-02-25 19:05:48 +01001023 hdev = hci_dev_get(index);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001024 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001025 return cmd_status(sk, index, MGMT_OP_DISCONNECT, ENODEV);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001026
Andre Guedes8c156c32011-07-07 10:30:36 -03001027 hci_dev_lock_bh(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001028
1029 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001030 err = cmd_status(sk, index, MGMT_OP_DISCONNECT, ENETDOWN);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001031 goto failed;
1032 }
1033
Szymon Janc4e51eae2011-02-25 19:05:48 +01001034 if (mgmt_pending_find(MGMT_OP_DISCONNECT, index)) {
1035 err = cmd_status(sk, index, MGMT_OP_DISCONNECT, EBUSY);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001036 goto failed;
1037 }
1038
1039 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03001040 if (!conn)
1041 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->bdaddr);
1042
Johan Hedberg8962ee72011-01-20 12:40:27 +02001043 if (!conn) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001044 err = cmd_status(sk, index, MGMT_OP_DISCONNECT, ENOTCONN);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001045 goto failed;
1046 }
1047
Szymon Janc4e51eae2011-02-25 19:05:48 +01001048 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001049 if (!cmd) {
1050 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001051 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001052 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001053
1054 put_unaligned_le16(conn->handle, &dc.handle);
1055 dc.reason = 0x13; /* Remote User Terminated Connection */
1056
1057 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1058 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001059 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001060
1061failed:
Andre Guedes8c156c32011-07-07 10:30:36 -03001062 hci_dev_unlock_bh(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001063 hci_dev_put(hdev);
1064
1065 return err;
1066}
1067
Szymon Janc8ce62842011-03-01 16:55:32 +01001068static int get_connections(struct sock *sk, u16 index)
Johan Hedberg2784eb42011-01-21 13:56:35 +02001069{
Johan Hedberg2784eb42011-01-21 13:56:35 +02001070 struct mgmt_rp_get_connections *rp;
1071 struct hci_dev *hdev;
1072 struct list_head *p;
Johan Hedberga38528f2011-01-22 06:46:43 +02001073 size_t rp_len;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001074 u16 count;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001075 int i, err;
1076
1077 BT_DBG("");
1078
Szymon Janc4e51eae2011-02-25 19:05:48 +01001079 hdev = hci_dev_get(index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001080 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001081 return cmd_status(sk, index, MGMT_OP_GET_CONNECTIONS, ENODEV);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001082
Andre Guedes8c156c32011-07-07 10:30:36 -03001083 hci_dev_lock_bh(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001084
1085 count = 0;
1086 list_for_each(p, &hdev->conn_hash.list) {
1087 count++;
1088 }
1089
Johan Hedberga38528f2011-01-22 06:46:43 +02001090 rp_len = sizeof(*rp) + (count * sizeof(bdaddr_t));
1091 rp = kmalloc(rp_len, GFP_ATOMIC);
1092 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02001093 err = -ENOMEM;
1094 goto unlock;
1095 }
1096
Johan Hedberg2784eb42011-01-21 13:56:35 +02001097 put_unaligned_le16(count, &rp->conn_count);
1098
Johan Hedberg2784eb42011-01-21 13:56:35 +02001099 i = 0;
1100 list_for_each(p, &hdev->conn_hash.list) {
1101 struct hci_conn *c = list_entry(p, struct hci_conn, list);
1102
1103 bacpy(&rp->conn[i++], &c->dst);
1104 }
1105
Szymon Janc4e51eae2011-02-25 19:05:48 +01001106 err = cmd_complete(sk, index, MGMT_OP_GET_CONNECTIONS, rp, rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001107
1108unlock:
Johan Hedberga38528f2011-01-22 06:46:43 +02001109 kfree(rp);
Andre Guedes8c156c32011-07-07 10:30:36 -03001110 hci_dev_unlock_bh(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001111 hci_dev_put(hdev);
1112 return err;
1113}
1114
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001115static int send_pin_code_neg_reply(struct sock *sk, u16 index,
1116 struct hci_dev *hdev, struct mgmt_cp_pin_code_neg_reply *cp)
1117{
1118 struct pending_cmd *cmd;
1119 int err;
1120
1121 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, index, cp,
1122 sizeof(*cp));
1123 if (!cmd)
1124 return -ENOMEM;
1125
1126 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY, sizeof(cp->bdaddr),
1127 &cp->bdaddr);
1128 if (err < 0)
1129 mgmt_pending_remove(cmd);
1130
1131 return err;
1132}
1133
Szymon Janc4e51eae2011-02-25 19:05:48 +01001134static int pin_code_reply(struct sock *sk, u16 index, unsigned char *data,
1135 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001136{
1137 struct hci_dev *hdev;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001138 struct hci_conn *conn;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001139 struct mgmt_cp_pin_code_reply *cp;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001140 struct mgmt_cp_pin_code_neg_reply ncp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001141 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03001142 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001143 int err;
1144
1145 BT_DBG("");
1146
1147 cp = (void *) data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001148
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001149 if (len != sizeof(*cp))
1150 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, EINVAL);
1151
Szymon Janc4e51eae2011-02-25 19:05:48 +01001152 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001153 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001154 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENODEV);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001155
Andre Guedes8c156c32011-07-07 10:30:36 -03001156 hci_dev_lock_bh(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001157
1158 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001159 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENETDOWN);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001160 goto failed;
1161 }
1162
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001163 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
1164 if (!conn) {
1165 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENOTCONN);
1166 goto failed;
1167 }
1168
1169 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
1170 bacpy(&ncp.bdaddr, &cp->bdaddr);
1171
1172 BT_ERR("PIN code is not 16 bytes long");
1173
1174 err = send_pin_code_neg_reply(sk, index, hdev, &ncp);
1175 if (err >= 0)
1176 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1177 EINVAL);
1178
1179 goto failed;
1180 }
1181
Szymon Janc4e51eae2011-02-25 19:05:48 +01001182 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001183 if (!cmd) {
1184 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001185 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001186 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02001187
1188 bacpy(&reply.bdaddr, &cp->bdaddr);
1189 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02001190 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02001191
1192 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
1193 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001194 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001195
1196failed:
Andre Guedes8c156c32011-07-07 10:30:36 -03001197 hci_dev_unlock_bh(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001198 hci_dev_put(hdev);
1199
1200 return err;
1201}
1202
Szymon Janc4e51eae2011-02-25 19:05:48 +01001203static int pin_code_neg_reply(struct sock *sk, u16 index, unsigned char *data,
1204 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001205{
1206 struct hci_dev *hdev;
1207 struct mgmt_cp_pin_code_neg_reply *cp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001208 int err;
1209
1210 BT_DBG("");
1211
1212 cp = (void *) data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001213
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001214 if (len != sizeof(*cp))
1215 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1216 EINVAL);
1217
Szymon Janc4e51eae2011-02-25 19:05:48 +01001218 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001219 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001220 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1221 ENODEV);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001222
Andre Guedes8c156c32011-07-07 10:30:36 -03001223 hci_dev_lock_bh(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001224
1225 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001226 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1227 ENETDOWN);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001228 goto failed;
1229 }
1230
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001231 err = send_pin_code_neg_reply(sk, index, hdev, cp);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001232
1233failed:
Andre Guedes8c156c32011-07-07 10:30:36 -03001234 hci_dev_unlock_bh(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001235 hci_dev_put(hdev);
1236
1237 return err;
1238}
1239
Szymon Janc4e51eae2011-02-25 19:05:48 +01001240static int set_io_capability(struct sock *sk, u16 index, unsigned char *data,
1241 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001242{
1243 struct hci_dev *hdev;
1244 struct mgmt_cp_set_io_capability *cp;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001245
1246 BT_DBG("");
1247
1248 cp = (void *) data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001249
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001250 if (len != sizeof(*cp))
Szymon Jancb8534e0f2011-03-01 16:55:34 +01001251 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY, EINVAL);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001252
Szymon Janc4e51eae2011-02-25 19:05:48 +01001253 hdev = hci_dev_get(index);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001254 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001255 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY, ENODEV);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001256
Andre Guedes8c156c32011-07-07 10:30:36 -03001257 hci_dev_lock_bh(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001258
1259 hdev->io_capability = cp->io_capability;
1260
1261 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Szymon Jancb8534e0f2011-03-01 16:55:34 +01001262 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001263
Andre Guedes8c156c32011-07-07 10:30:36 -03001264 hci_dev_unlock_bh(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001265 hci_dev_put(hdev);
1266
Szymon Janc4e51eae2011-02-25 19:05:48 +01001267 return cmd_complete(sk, index, MGMT_OP_SET_IO_CAPABILITY, NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001268}
1269
Johan Hedberge9a416b2011-02-19 12:05:56 -03001270static inline struct pending_cmd *find_pairing(struct hci_conn *conn)
1271{
1272 struct hci_dev *hdev = conn->hdev;
1273 struct list_head *p;
1274
1275 list_for_each(p, &cmd_list) {
1276 struct pending_cmd *cmd;
1277
1278 cmd = list_entry(p, struct pending_cmd, list);
1279
1280 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
1281 continue;
1282
1283 if (cmd->index != hdev->id)
1284 continue;
1285
1286 if (cmd->user_data != conn)
1287 continue;
1288
1289 return cmd;
1290 }
1291
1292 return NULL;
1293}
1294
1295static void pairing_complete(struct pending_cmd *cmd, u8 status)
1296{
1297 struct mgmt_rp_pair_device rp;
1298 struct hci_conn *conn = cmd->user_data;
1299
Johan Hedberge9a416b2011-02-19 12:05:56 -03001300 bacpy(&rp.bdaddr, &conn->dst);
1301 rp.status = status;
1302
Szymon Janc4e51eae2011-02-25 19:05:48 +01001303 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001304
1305 /* So we don't get further callbacks for this connection */
1306 conn->connect_cfm_cb = NULL;
1307 conn->security_cfm_cb = NULL;
1308 conn->disconn_cfm_cb = NULL;
1309
1310 hci_conn_put(conn);
1311
Johan Hedberga664b5b2011-02-19 12:06:02 -03001312 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001313}
1314
1315static void pairing_complete_cb(struct hci_conn *conn, u8 status)
1316{
1317 struct pending_cmd *cmd;
1318
1319 BT_DBG("status %u", status);
1320
1321 cmd = find_pairing(conn);
1322 if (!cmd) {
1323 BT_DBG("Unable to find a pending command");
1324 return;
1325 }
1326
1327 pairing_complete(cmd, status);
1328}
1329
Szymon Janc4e51eae2011-02-25 19:05:48 +01001330static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001331{
1332 struct hci_dev *hdev;
1333 struct mgmt_cp_pair_device *cp;
1334 struct pending_cmd *cmd;
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001335 struct adv_entry *entry;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001336 u8 sec_level, auth_type;
1337 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001338 int err;
1339
1340 BT_DBG("");
1341
1342 cp = (void *) data;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001343
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001344 if (len != sizeof(*cp))
1345 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, EINVAL);
1346
Szymon Janc4e51eae2011-02-25 19:05:48 +01001347 hdev = hci_dev_get(index);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001348 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001349 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, ENODEV);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001350
Andre Guedes8c156c32011-07-07 10:30:36 -03001351 hci_dev_lock_bh(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001352
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001353 sec_level = BT_SECURITY_MEDIUM;
1354 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001355 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001356 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03001357 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001358
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001359 entry = hci_find_adv_entry(hdev, &cp->bdaddr);
1360 if (entry)
1361 conn = hci_connect(hdev, LE_LINK, &cp->bdaddr, sec_level,
1362 auth_type);
1363 else
1364 conn = hci_connect(hdev, ACL_LINK, &cp->bdaddr, sec_level,
1365 auth_type);
1366
Ville Tervo30e76272011-02-22 16:10:53 -03001367 if (IS_ERR(conn)) {
1368 err = PTR_ERR(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001369 goto unlock;
1370 }
1371
1372 if (conn->connect_cfm_cb) {
1373 hci_conn_put(conn);
Szymon Janc4e51eae2011-02-25 19:05:48 +01001374 err = cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, EBUSY);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001375 goto unlock;
1376 }
1377
Szymon Janc4e51eae2011-02-25 19:05:48 +01001378 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, index, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001379 if (!cmd) {
1380 err = -ENOMEM;
1381 hci_conn_put(conn);
1382 goto unlock;
1383 }
1384
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001385 /* For LE, just connecting isn't a proof that the pairing finished */
1386 if (!entry)
1387 conn->connect_cfm_cb = pairing_complete_cb;
1388
Johan Hedberge9a416b2011-02-19 12:05:56 -03001389 conn->security_cfm_cb = pairing_complete_cb;
1390 conn->disconn_cfm_cb = pairing_complete_cb;
1391 conn->io_capability = cp->io_cap;
1392 cmd->user_data = conn;
1393
1394 if (conn->state == BT_CONNECTED &&
1395 hci_conn_security(conn, sec_level, auth_type))
1396 pairing_complete(cmd, 0);
1397
1398 err = 0;
1399
1400unlock:
Andre Guedes8c156c32011-07-07 10:30:36 -03001401 hci_dev_unlock_bh(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001402 hci_dev_put(hdev);
1403
1404 return err;
1405}
1406
Szymon Janc4e51eae2011-02-25 19:05:48 +01001407static int user_confirm_reply(struct sock *sk, u16 index, unsigned char *data,
1408 u16 len, int success)
Johan Hedberga5c29682011-02-19 12:05:57 -03001409{
1410 struct mgmt_cp_user_confirm_reply *cp = (void *) data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001411 u16 mgmt_op, hci_op;
Johan Hedberga5c29682011-02-19 12:05:57 -03001412 struct pending_cmd *cmd;
1413 struct hci_dev *hdev;
1414 int err;
1415
1416 BT_DBG("");
1417
Johan Hedberga5c29682011-02-19 12:05:57 -03001418 if (success) {
1419 mgmt_op = MGMT_OP_USER_CONFIRM_REPLY;
1420 hci_op = HCI_OP_USER_CONFIRM_REPLY;
1421 } else {
1422 mgmt_op = MGMT_OP_USER_CONFIRM_NEG_REPLY;
1423 hci_op = HCI_OP_USER_CONFIRM_NEG_REPLY;
1424 }
1425
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001426 if (len != sizeof(*cp))
1427 return cmd_status(sk, index, mgmt_op, EINVAL);
1428
Szymon Janc4e51eae2011-02-25 19:05:48 +01001429 hdev = hci_dev_get(index);
Johan Hedberga5c29682011-02-19 12:05:57 -03001430 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001431 return cmd_status(sk, index, mgmt_op, ENODEV);
Johan Hedberga5c29682011-02-19 12:05:57 -03001432
Andre Guedes8c156c32011-07-07 10:30:36 -03001433 hci_dev_lock_bh(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02001434
Johan Hedberga5c29682011-02-19 12:05:57 -03001435 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001436 err = cmd_status(sk, index, mgmt_op, ENETDOWN);
Johan Hedberga5c29682011-02-19 12:05:57 -03001437 goto failed;
1438 }
1439
Szymon Janc4e51eae2011-02-25 19:05:48 +01001440 cmd = mgmt_pending_add(sk, mgmt_op, index, data, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03001441 if (!cmd) {
1442 err = -ENOMEM;
1443 goto failed;
1444 }
1445
1446 err = hci_send_cmd(hdev, hci_op, sizeof(cp->bdaddr), &cp->bdaddr);
Johan Hedberga664b5b2011-02-19 12:06:02 -03001447 if (err < 0)
1448 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03001449
1450failed:
Andre Guedes8c156c32011-07-07 10:30:36 -03001451 hci_dev_unlock_bh(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03001452 hci_dev_put(hdev);
1453
1454 return err;
1455}
1456
Johan Hedbergb312b1612011-03-16 14:29:37 +02001457static int set_local_name(struct sock *sk, u16 index, unsigned char *data,
1458 u16 len)
1459{
1460 struct mgmt_cp_set_local_name *mgmt_cp = (void *) data;
1461 struct hci_cp_write_local_name hci_cp;
1462 struct hci_dev *hdev;
1463 struct pending_cmd *cmd;
1464 int err;
1465
1466 BT_DBG("");
1467
1468 if (len != sizeof(*mgmt_cp))
1469 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, EINVAL);
1470
1471 hdev = hci_dev_get(index);
1472 if (!hdev)
1473 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, ENODEV);
1474
Andre Guedes8c156c32011-07-07 10:30:36 -03001475 hci_dev_lock_bh(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001476
1477 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, index, data, len);
1478 if (!cmd) {
1479 err = -ENOMEM;
1480 goto failed;
1481 }
1482
1483 memcpy(hci_cp.name, mgmt_cp->name, sizeof(hci_cp.name));
1484 err = hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(hci_cp),
1485 &hci_cp);
1486 if (err < 0)
1487 mgmt_pending_remove(cmd);
1488
1489failed:
Andre Guedes8c156c32011-07-07 10:30:36 -03001490 hci_dev_unlock_bh(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001491 hci_dev_put(hdev);
1492
1493 return err;
1494}
1495
Szymon Jancc35938b2011-03-22 13:12:21 +01001496static int read_local_oob_data(struct sock *sk, u16 index)
1497{
1498 struct hci_dev *hdev;
1499 struct pending_cmd *cmd;
1500 int err;
1501
1502 BT_DBG("hci%u", index);
1503
1504 hdev = hci_dev_get(index);
1505 if (!hdev)
1506 return cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
1507 ENODEV);
1508
Andre Guedes8c156c32011-07-07 10:30:36 -03001509 hci_dev_lock_bh(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01001510
1511 if (!test_bit(HCI_UP, &hdev->flags)) {
1512 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
1513 ENETDOWN);
1514 goto unlock;
1515 }
1516
1517 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
1518 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
1519 EOPNOTSUPP);
1520 goto unlock;
1521 }
1522
1523 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, index)) {
1524 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA, EBUSY);
1525 goto unlock;
1526 }
1527
1528 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, index, NULL, 0);
1529 if (!cmd) {
1530 err = -ENOMEM;
1531 goto unlock;
1532 }
1533
1534 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
1535 if (err < 0)
1536 mgmt_pending_remove(cmd);
1537
1538unlock:
Andre Guedes8c156c32011-07-07 10:30:36 -03001539 hci_dev_unlock_bh(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01001540 hci_dev_put(hdev);
1541
1542 return err;
1543}
1544
Szymon Janc2763eda2011-03-22 13:12:22 +01001545static int add_remote_oob_data(struct sock *sk, u16 index, unsigned char *data,
1546 u16 len)
1547{
1548 struct hci_dev *hdev;
1549 struct mgmt_cp_add_remote_oob_data *cp = (void *) data;
1550 int err;
1551
1552 BT_DBG("hci%u ", index);
1553
1554 if (len != sizeof(*cp))
1555 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
1556 EINVAL);
1557
1558 hdev = hci_dev_get(index);
1559 if (!hdev)
1560 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
1561 ENODEV);
1562
Andre Guedes8c156c32011-07-07 10:30:36 -03001563 hci_dev_lock_bh(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001564
1565 err = hci_add_remote_oob_data(hdev, &cp->bdaddr, cp->hash,
1566 cp->randomizer);
1567 if (err < 0)
1568 err = cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, -err);
1569 else
1570 err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, NULL,
1571 0);
1572
Andre Guedes8c156c32011-07-07 10:30:36 -03001573 hci_dev_unlock_bh(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001574 hci_dev_put(hdev);
1575
1576 return err;
1577}
1578
1579static int remove_remote_oob_data(struct sock *sk, u16 index,
1580 unsigned char *data, u16 len)
1581{
1582 struct hci_dev *hdev;
1583 struct mgmt_cp_remove_remote_oob_data *cp = (void *) data;
1584 int err;
1585
1586 BT_DBG("hci%u ", index);
1587
1588 if (len != sizeof(*cp))
1589 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
1590 EINVAL);
1591
1592 hdev = hci_dev_get(index);
1593 if (!hdev)
1594 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
1595 ENODEV);
1596
Andre Guedes8c156c32011-07-07 10:30:36 -03001597 hci_dev_lock_bh(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001598
1599 err = hci_remove_remote_oob_data(hdev, &cp->bdaddr);
1600 if (err < 0)
1601 err = cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
1602 -err);
1603 else
1604 err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
1605 NULL, 0);
1606
Andre Guedes8c156c32011-07-07 10:30:36 -03001607 hci_dev_unlock_bh(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001608 hci_dev_put(hdev);
1609
1610 return err;
1611}
1612
Johan Hedberg14a53662011-04-27 10:29:56 -04001613static int start_discovery(struct sock *sk, u16 index)
1614{
1615 u8 lap[3] = { 0x33, 0x8b, 0x9e };
1616 struct hci_cp_inquiry cp;
1617 struct pending_cmd *cmd;
1618 struct hci_dev *hdev;
1619 int err;
1620
1621 BT_DBG("hci%u", index);
1622
1623 hdev = hci_dev_get(index);
1624 if (!hdev)
1625 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY, ENODEV);
1626
1627 hci_dev_lock_bh(hdev);
1628
1629 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, index, NULL, 0);
1630 if (!cmd) {
1631 err = -ENOMEM;
1632 goto failed;
1633 }
1634
1635 memset(&cp, 0, sizeof(cp));
1636 memcpy(&cp.lap, lap, 3);
1637 cp.length = 0x08;
1638 cp.num_rsp = 0x00;
1639
1640 err = hci_send_cmd(hdev, HCI_OP_INQUIRY, sizeof(cp), &cp);
1641 if (err < 0)
1642 mgmt_pending_remove(cmd);
1643
1644failed:
1645 hci_dev_unlock_bh(hdev);
1646 hci_dev_put(hdev);
1647
1648 return err;
1649}
1650
1651static int stop_discovery(struct sock *sk, u16 index)
1652{
1653 struct hci_dev *hdev;
1654 struct pending_cmd *cmd;
1655 int err;
1656
1657 BT_DBG("hci%u", index);
1658
1659 hdev = hci_dev_get(index);
1660 if (!hdev)
1661 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY, ENODEV);
1662
1663 hci_dev_lock_bh(hdev);
1664
1665 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, index, NULL, 0);
1666 if (!cmd) {
1667 err = -ENOMEM;
1668 goto failed;
1669 }
1670
1671 err = hci_send_cmd(hdev, HCI_OP_INQUIRY_CANCEL, 0, NULL);
1672 if (err < 0)
1673 mgmt_pending_remove(cmd);
1674
1675failed:
1676 hci_dev_unlock_bh(hdev);
1677 hci_dev_put(hdev);
1678
1679 return err;
1680}
1681
Antti Julku7fbec222011-06-15 12:01:15 +03001682static int block_device(struct sock *sk, u16 index, unsigned char *data,
1683 u16 len)
1684{
1685 struct hci_dev *hdev;
Antti Julku5e762442011-08-25 16:48:02 +03001686 struct pending_cmd *cmd;
1687 struct mgmt_cp_block_device *cp = (void *) data;
Antti Julku7fbec222011-06-15 12:01:15 +03001688 int err;
1689
1690 BT_DBG("hci%u", index);
1691
Antti Julku7fbec222011-06-15 12:01:15 +03001692 if (len != sizeof(*cp))
1693 return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
1694 EINVAL);
1695
1696 hdev = hci_dev_get(index);
1697 if (!hdev)
1698 return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
1699 ENODEV);
1700
Antti Julku5e762442011-08-25 16:48:02 +03001701 hci_dev_lock_bh(hdev);
1702
1703 cmd = mgmt_pending_add(sk, MGMT_OP_BLOCK_DEVICE, index, NULL, 0);
1704 if (!cmd) {
1705 err = -ENOMEM;
1706 goto failed;
1707 }
1708
Antti Julku7fbec222011-06-15 12:01:15 +03001709 err = hci_blacklist_add(hdev, &cp->bdaddr);
1710
1711 if (err < 0)
1712 err = cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE, -err);
1713 else
1714 err = cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE,
1715 NULL, 0);
Antti Julku5e762442011-08-25 16:48:02 +03001716
1717 mgmt_pending_remove(cmd);
1718
1719failed:
1720 hci_dev_unlock_bh(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03001721 hci_dev_put(hdev);
1722
1723 return err;
1724}
1725
1726static int unblock_device(struct sock *sk, u16 index, unsigned char *data,
1727 u16 len)
1728{
1729 struct hci_dev *hdev;
Antti Julku5e762442011-08-25 16:48:02 +03001730 struct pending_cmd *cmd;
1731 struct mgmt_cp_unblock_device *cp = (void *) data;
Antti Julku7fbec222011-06-15 12:01:15 +03001732 int err;
1733
1734 BT_DBG("hci%u", index);
1735
Antti Julku7fbec222011-06-15 12:01:15 +03001736 if (len != sizeof(*cp))
1737 return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
1738 EINVAL);
1739
1740 hdev = hci_dev_get(index);
1741 if (!hdev)
1742 return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
1743 ENODEV);
1744
Antti Julku5e762442011-08-25 16:48:02 +03001745 hci_dev_lock_bh(hdev);
1746
1747 cmd = mgmt_pending_add(sk, MGMT_OP_UNBLOCK_DEVICE, index, NULL, 0);
1748 if (!cmd) {
1749 err = -ENOMEM;
1750 goto failed;
1751 }
1752
Antti Julku7fbec222011-06-15 12:01:15 +03001753 err = hci_blacklist_del(hdev, &cp->bdaddr);
1754
1755 if (err < 0)
1756 err = cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE, -err);
1757 else
1758 err = cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE,
1759 NULL, 0);
Antti Julku5e762442011-08-25 16:48:02 +03001760
1761 mgmt_pending_remove(cmd);
1762
1763failed:
1764 hci_dev_unlock_bh(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03001765 hci_dev_put(hdev);
1766
1767 return err;
1768}
1769
Antti Julkuf6422ec2011-06-22 13:11:56 +03001770static int set_fast_connectable(struct sock *sk, u16 index,
1771 unsigned char *data, u16 len)
1772{
1773 struct hci_dev *hdev;
1774 struct mgmt_cp_set_fast_connectable *cp = (void *) data;
1775 struct hci_cp_write_page_scan_activity acp;
1776 u8 type;
1777 int err;
1778
1779 BT_DBG("hci%u", index);
1780
1781 if (len != sizeof(*cp))
1782 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
1783 EINVAL);
1784
1785 hdev = hci_dev_get(index);
1786 if (!hdev)
1787 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
1788 ENODEV);
1789
1790 hci_dev_lock(hdev);
1791
1792 if (cp->enable) {
1793 type = PAGE_SCAN_TYPE_INTERLACED;
1794 acp.interval = 0x0024; /* 22.5 msec page scan interval */
1795 } else {
1796 type = PAGE_SCAN_TYPE_STANDARD; /* default */
1797 acp.interval = 0x0800; /* default 1.28 sec page scan */
1798 }
1799
1800 acp.window = 0x0012; /* default 11.25 msec page scan window */
1801
1802 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
1803 sizeof(acp), &acp);
1804 if (err < 0) {
1805 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
1806 -err);
1807 goto done;
1808 }
1809
1810 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
1811 if (err < 0) {
1812 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
1813 -err);
1814 goto done;
1815 }
1816
1817 err = cmd_complete(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
1818 NULL, 0);
1819done:
1820 hci_dev_unlock(hdev);
1821 hci_dev_put(hdev);
1822
1823 return err;
1824}
1825
Johan Hedberg03811012010-12-08 00:21:06 +02001826int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
1827{
1828 unsigned char *buf;
1829 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001830 u16 opcode, index, len;
Johan Hedberg03811012010-12-08 00:21:06 +02001831 int err;
1832
1833 BT_DBG("got %zu bytes", msglen);
1834
1835 if (msglen < sizeof(*hdr))
1836 return -EINVAL;
1837
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03001838 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02001839 if (!buf)
1840 return -ENOMEM;
1841
1842 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
1843 err = -EFAULT;
1844 goto done;
1845 }
1846
1847 hdr = (struct mgmt_hdr *) buf;
1848 opcode = get_unaligned_le16(&hdr->opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01001849 index = get_unaligned_le16(&hdr->index);
Johan Hedberg03811012010-12-08 00:21:06 +02001850 len = get_unaligned_le16(&hdr->len);
1851
1852 if (len != msglen - sizeof(*hdr)) {
1853 err = -EINVAL;
1854 goto done;
1855 }
1856
1857 switch (opcode) {
Johan Hedberg02d98122010-12-13 21:07:04 +02001858 case MGMT_OP_READ_VERSION:
1859 err = read_version(sk);
1860 break;
Johan Hedbergfaba42e2010-12-13 21:07:05 +02001861 case MGMT_OP_READ_INDEX_LIST:
1862 err = read_index_list(sk);
1863 break;
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001864 case MGMT_OP_READ_INFO:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001865 err = read_controller_info(sk, index);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001866 break;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001867 case MGMT_OP_SET_POWERED:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001868 err = set_powered(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001869 break;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001870 case MGMT_OP_SET_DISCOVERABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001871 err = set_discoverable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001872 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001873 case MGMT_OP_SET_CONNECTABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001874 err = set_connectable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001875 break;
Johan Hedbergc542a062011-01-26 13:11:03 +02001876 case MGMT_OP_SET_PAIRABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001877 err = set_pairable(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergc542a062011-01-26 13:11:03 +02001878 break;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001879 case MGMT_OP_ADD_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001880 err = add_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001881 break;
1882 case MGMT_OP_REMOVE_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001883 err = remove_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001884 break;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001885 case MGMT_OP_SET_DEV_CLASS:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001886 err = set_dev_class(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001887 break;
1888 case MGMT_OP_SET_SERVICE_CACHE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001889 err = set_service_cache(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001890 break;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001891 case MGMT_OP_LOAD_KEYS:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001892 err = load_keys(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001893 break;
1894 case MGMT_OP_REMOVE_KEY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001895 err = remove_key(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001896 break;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001897 case MGMT_OP_DISCONNECT:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001898 err = disconnect(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001899 break;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001900 case MGMT_OP_GET_CONNECTIONS:
Szymon Janc8ce62842011-03-01 16:55:32 +01001901 err = get_connections(sk, index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001902 break;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001903 case MGMT_OP_PIN_CODE_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001904 err = pin_code_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001905 break;
1906 case MGMT_OP_PIN_CODE_NEG_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001907 err = pin_code_neg_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001908 break;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001909 case MGMT_OP_SET_IO_CAPABILITY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001910 err = set_io_capability(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001911 break;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001912 case MGMT_OP_PAIR_DEVICE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001913 err = pair_device(sk, index, buf + sizeof(*hdr), len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001914 break;
Johan Hedberga5c29682011-02-19 12:05:57 -03001915 case MGMT_OP_USER_CONFIRM_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001916 err = user_confirm_reply(sk, index, buf + sizeof(*hdr), len, 1);
Johan Hedberga5c29682011-02-19 12:05:57 -03001917 break;
1918 case MGMT_OP_USER_CONFIRM_NEG_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001919 err = user_confirm_reply(sk, index, buf + sizeof(*hdr), len, 0);
Johan Hedberga5c29682011-02-19 12:05:57 -03001920 break;
Johan Hedbergb312b1612011-03-16 14:29:37 +02001921 case MGMT_OP_SET_LOCAL_NAME:
1922 err = set_local_name(sk, index, buf + sizeof(*hdr), len);
1923 break;
Szymon Jancc35938b2011-03-22 13:12:21 +01001924 case MGMT_OP_READ_LOCAL_OOB_DATA:
1925 err = read_local_oob_data(sk, index);
1926 break;
Szymon Janc2763eda2011-03-22 13:12:22 +01001927 case MGMT_OP_ADD_REMOTE_OOB_DATA:
1928 err = add_remote_oob_data(sk, index, buf + sizeof(*hdr), len);
1929 break;
1930 case MGMT_OP_REMOVE_REMOTE_OOB_DATA:
1931 err = remove_remote_oob_data(sk, index, buf + sizeof(*hdr),
1932 len);
1933 break;
Johan Hedberg14a53662011-04-27 10:29:56 -04001934 case MGMT_OP_START_DISCOVERY:
1935 err = start_discovery(sk, index);
1936 break;
1937 case MGMT_OP_STOP_DISCOVERY:
1938 err = stop_discovery(sk, index);
1939 break;
Antti Julku7fbec222011-06-15 12:01:15 +03001940 case MGMT_OP_BLOCK_DEVICE:
1941 err = block_device(sk, index, buf + sizeof(*hdr), len);
1942 break;
1943 case MGMT_OP_UNBLOCK_DEVICE:
1944 err = unblock_device(sk, index, buf + sizeof(*hdr), len);
1945 break;
Antti Julkuf6422ec2011-06-22 13:11:56 +03001946 case MGMT_OP_SET_FAST_CONNECTABLE:
1947 err = set_fast_connectable(sk, index, buf + sizeof(*hdr),
1948 len);
1949 break;
Johan Hedberg03811012010-12-08 00:21:06 +02001950 default:
1951 BT_DBG("Unknown op %u", opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01001952 err = cmd_status(sk, index, opcode, 0x01);
Johan Hedberg03811012010-12-08 00:21:06 +02001953 break;
1954 }
1955
Johan Hedberge41d8b42010-12-13 21:07:03 +02001956 if (err < 0)
1957 goto done;
1958
Johan Hedberg03811012010-12-08 00:21:06 +02001959 err = msglen;
1960
1961done:
1962 kfree(buf);
1963 return err;
1964}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001965
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001966int mgmt_index_added(u16 index)
1967{
Szymon Janc4e51eae2011-02-25 19:05:48 +01001968 return mgmt_event(MGMT_EV_INDEX_ADDED, index, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001969}
1970
1971int mgmt_index_removed(u16 index)
1972{
Szymon Janc4e51eae2011-02-25 19:05:48 +01001973 return mgmt_event(MGMT_EV_INDEX_REMOVED, index, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001974}
1975
Johan Hedberg73f22f62010-12-29 16:00:25 +02001976struct cmd_lookup {
Johan Hedberg72a734e2010-12-30 00:38:22 +02001977 u8 val;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001978 struct sock *sk;
1979};
1980
Johan Hedberg72a734e2010-12-30 00:38:22 +02001981static void mode_rsp(struct pending_cmd *cmd, void *data)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001982{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01001983 struct mgmt_mode *cp = cmd->param;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001984 struct cmd_lookup *match = data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001985
Johan Hedberg72a734e2010-12-30 00:38:22 +02001986 if (cp->val != match->val)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001987 return;
1988
Johan Hedberg053f0212011-01-26 13:07:10 +02001989 send_mode_rsp(cmd->sk, cmd->opcode, cmd->index, cp->val);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001990
1991 list_del(&cmd->list);
1992
1993 if (match->sk == NULL) {
1994 match->sk = cmd->sk;
1995 sock_hold(match->sk);
1996 }
1997
1998 mgmt_pending_free(cmd);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001999}
Johan Hedberg5add6af2010-12-16 10:00:37 +02002000
2001int mgmt_powered(u16 index, u8 powered)
2002{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002003 struct mgmt_mode ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002004 struct cmd_lookup match = { powered, NULL };
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002005 int ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002006
Johan Hedberg72a734e2010-12-30 00:38:22 +02002007 mgmt_pending_foreach(MGMT_OP_SET_POWERED, index, mode_rsp, &match);
Johan Hedberg5add6af2010-12-16 10:00:37 +02002008
Johan Hedberg72a734e2010-12-30 00:38:22 +02002009 ev.val = powered;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002010
Szymon Janc4e51eae2011-02-25 19:05:48 +01002011 ret = mgmt_event(MGMT_EV_POWERED, index, &ev, sizeof(ev), match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002012
2013 if (match.sk)
2014 sock_put(match.sk);
2015
2016 return ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002017}
Johan Hedberg73f22f62010-12-29 16:00:25 +02002018
Johan Hedberg73f22f62010-12-29 16:00:25 +02002019int mgmt_discoverable(u16 index, u8 discoverable)
2020{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002021 struct mgmt_mode ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002022 struct cmd_lookup match = { discoverable, NULL };
2023 int ret;
2024
Szymon Jancb8534e0f2011-03-01 16:55:34 +01002025 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, index, mode_rsp, &match);
Johan Hedberg72a734e2010-12-30 00:38:22 +02002026
Johan Hedberg72a734e2010-12-30 00:38:22 +02002027 ev.val = discoverable;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002028
Szymon Janc4e51eae2011-02-25 19:05:48 +01002029 ret = mgmt_event(MGMT_EV_DISCOVERABLE, index, &ev, sizeof(ev),
2030 match.sk);
Johan Hedberg73f22f62010-12-29 16:00:25 +02002031
2032 if (match.sk)
2033 sock_put(match.sk);
2034
2035 return ret;
2036}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002037
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002038int mgmt_connectable(u16 index, u8 connectable)
2039{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002040 struct mgmt_mode ev;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002041 struct cmd_lookup match = { connectable, NULL };
2042 int ret;
2043
Johan Hedberg72a734e2010-12-30 00:38:22 +02002044 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, index, mode_rsp, &match);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002045
Johan Hedberg72a734e2010-12-30 00:38:22 +02002046 ev.val = connectable;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002047
Szymon Janc4e51eae2011-02-25 19:05:48 +01002048 ret = mgmt_event(MGMT_EV_CONNECTABLE, index, &ev, sizeof(ev), match.sk);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002049
2050 if (match.sk)
2051 sock_put(match.sk);
2052
2053 return ret;
2054}
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002055
Johan Hedberg4df378a2011-04-28 11:29:03 -07002056int mgmt_new_key(u16 index, struct link_key *key, u8 persistent)
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002057{
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002058 struct mgmt_ev_new_key ev;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002059
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002060 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002061
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002062 ev.store_hint = persistent;
2063 bacpy(&ev.key.bdaddr, &key->bdaddr);
2064 ev.key.type = key->type;
2065 memcpy(ev.key.val, key->val, 16);
2066 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002067
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002068 return mgmt_event(MGMT_EV_NEW_KEY, index, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002069}
Johan Hedbergf7520542011-01-20 12:34:39 +02002070
Vinicius Costa Gomescfafccf2011-08-19 21:06:56 -03002071int mgmt_connected(u16 index, bdaddr_t *bdaddr, u8 link_type)
Johan Hedbergf7520542011-01-20 12:34:39 +02002072{
2073 struct mgmt_ev_connected ev;
2074
Johan Hedbergf7520542011-01-20 12:34:39 +02002075 bacpy(&ev.bdaddr, bdaddr);
Vinicius Costa Gomescfafccf2011-08-19 21:06:56 -03002076 ev.link_type = link_type;
Johan Hedbergf7520542011-01-20 12:34:39 +02002077
Szymon Janc4e51eae2011-02-25 19:05:48 +01002078 return mgmt_event(MGMT_EV_CONNECTED, index, &ev, sizeof(ev), NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02002079}
2080
Johan Hedberg8962ee72011-01-20 12:40:27 +02002081static void disconnect_rsp(struct pending_cmd *cmd, void *data)
2082{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01002083 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002084 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02002085 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002086
Johan Hedberga38528f2011-01-22 06:46:43 +02002087 bacpy(&rp.bdaddr, &cp->bdaddr);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002088
Szymon Janc4e51eae2011-02-25 19:05:48 +01002089 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002090
2091 *sk = cmd->sk;
2092 sock_hold(*sk);
2093
Johan Hedberga664b5b2011-02-19 12:06:02 -03002094 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002095}
2096
Johan Hedbergf7520542011-01-20 12:34:39 +02002097int mgmt_disconnected(u16 index, bdaddr_t *bdaddr)
2098{
2099 struct mgmt_ev_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002100 struct sock *sk = NULL;
2101 int err;
2102
2103 mgmt_pending_foreach(MGMT_OP_DISCONNECT, index, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02002104
Johan Hedbergf7520542011-01-20 12:34:39 +02002105 bacpy(&ev.bdaddr, bdaddr);
2106
Szymon Janc4e51eae2011-02-25 19:05:48 +01002107 err = mgmt_event(MGMT_EV_DISCONNECTED, index, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002108
2109 if (sk)
2110 sock_put(sk);
2111
2112 return err;
2113}
2114
2115int mgmt_disconnect_failed(u16 index)
2116{
2117 struct pending_cmd *cmd;
2118 int err;
2119
2120 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, index);
2121 if (!cmd)
2122 return -ENOENT;
2123
Szymon Janc4e51eae2011-02-25 19:05:48 +01002124 err = cmd_status(cmd->sk, index, MGMT_OP_DISCONNECT, EIO);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002125
Johan Hedberga664b5b2011-02-19 12:06:02 -03002126 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002127
2128 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02002129}
Johan Hedberg17d5c042011-01-22 06:09:08 +02002130
2131int mgmt_connect_failed(u16 index, bdaddr_t *bdaddr, u8 status)
2132{
2133 struct mgmt_ev_connect_failed ev;
2134
Johan Hedberg17d5c042011-01-22 06:09:08 +02002135 bacpy(&ev.bdaddr, bdaddr);
2136 ev.status = status;
2137
Szymon Janc4e51eae2011-02-25 19:05:48 +01002138 return mgmt_event(MGMT_EV_CONNECT_FAILED, index, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02002139}
Johan Hedberg980e1a52011-01-22 06:10:07 +02002140
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02002141int mgmt_pin_code_request(u16 index, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002142{
2143 struct mgmt_ev_pin_code_request ev;
2144
Johan Hedberg980e1a52011-01-22 06:10:07 +02002145 bacpy(&ev.bdaddr, bdaddr);
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02002146 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002147
Szymon Janc4e51eae2011-02-25 19:05:48 +01002148 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, index, &ev, sizeof(ev),
2149 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002150}
2151
2152int mgmt_pin_code_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
2153{
2154 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002155 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002156 int err;
2157
2158 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, index);
2159 if (!cmd)
2160 return -ENOENT;
2161
Johan Hedbergac56fb12011-02-19 12:05:59 -03002162 bacpy(&rp.bdaddr, bdaddr);
2163 rp.status = status;
2164
Szymon Janc4e51eae2011-02-25 19:05:48 +01002165 err = cmd_complete(cmd->sk, index, MGMT_OP_PIN_CODE_REPLY, &rp,
2166 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002167
Johan Hedberga664b5b2011-02-19 12:06:02 -03002168 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002169
2170 return err;
2171}
2172
2173int mgmt_pin_code_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
2174{
2175 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002176 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002177 int err;
2178
2179 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, index);
2180 if (!cmd)
2181 return -ENOENT;
2182
Johan Hedbergac56fb12011-02-19 12:05:59 -03002183 bacpy(&rp.bdaddr, bdaddr);
2184 rp.status = status;
2185
Szymon Janc4e51eae2011-02-25 19:05:48 +01002186 err = cmd_complete(cmd->sk, index, MGMT_OP_PIN_CODE_NEG_REPLY, &rp,
2187 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002188
Johan Hedberga664b5b2011-02-19 12:06:02 -03002189 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002190
2191 return err;
2192}
Johan Hedberga5c29682011-02-19 12:05:57 -03002193
Johan Hedberg55bc1a32011-04-28 11:28:56 -07002194int mgmt_user_confirm_request(u16 index, bdaddr_t *bdaddr, __le32 value,
2195 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03002196{
2197 struct mgmt_ev_user_confirm_request ev;
2198
2199 BT_DBG("hci%u", index);
2200
Johan Hedberga5c29682011-02-19 12:05:57 -03002201 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07002202 ev.confirm_hint = confirm_hint;
Johan Hedberga5c29682011-02-19 12:05:57 -03002203 put_unaligned_le32(value, &ev.value);
2204
Szymon Janc4e51eae2011-02-25 19:05:48 +01002205 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, index, &ev, sizeof(ev),
2206 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03002207}
2208
2209static int confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status,
2210 u8 opcode)
2211{
2212 struct pending_cmd *cmd;
2213 struct mgmt_rp_user_confirm_reply rp;
2214 int err;
2215
2216 cmd = mgmt_pending_find(opcode, index);
2217 if (!cmd)
2218 return -ENOENT;
2219
Johan Hedberga5c29682011-02-19 12:05:57 -03002220 bacpy(&rp.bdaddr, bdaddr);
2221 rp.status = status;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002222 err = cmd_complete(cmd->sk, index, opcode, &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03002223
Johan Hedberga664b5b2011-02-19 12:06:02 -03002224 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002225
2226 return err;
2227}
2228
2229int mgmt_user_confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
2230{
2231 return confirm_reply_complete(index, bdaddr, status,
2232 MGMT_OP_USER_CONFIRM_REPLY);
2233}
2234
Szymon Jancb8534e0f2011-03-01 16:55:34 +01002235int mgmt_user_confirm_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03002236{
2237 return confirm_reply_complete(index, bdaddr, status,
2238 MGMT_OP_USER_CONFIRM_NEG_REPLY);
2239}
Johan Hedberg2a611692011-02-19 12:06:00 -03002240
2241int mgmt_auth_failed(u16 index, bdaddr_t *bdaddr, u8 status)
2242{
2243 struct mgmt_ev_auth_failed ev;
2244
Johan Hedberg2a611692011-02-19 12:06:00 -03002245 bacpy(&ev.bdaddr, bdaddr);
2246 ev.status = status;
2247
Szymon Janc4e51eae2011-02-25 19:05:48 +01002248 return mgmt_event(MGMT_EV_AUTH_FAILED, index, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03002249}
Johan Hedbergb312b1612011-03-16 14:29:37 +02002250
2251int mgmt_set_local_name_complete(u16 index, u8 *name, u8 status)
2252{
2253 struct pending_cmd *cmd;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002254 struct hci_dev *hdev;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002255 struct mgmt_cp_set_local_name ev;
2256 int err;
2257
2258 memset(&ev, 0, sizeof(ev));
2259 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
2260
2261 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, index);
2262 if (!cmd)
2263 goto send_event;
2264
2265 if (status) {
2266 err = cmd_status(cmd->sk, index, MGMT_OP_SET_LOCAL_NAME, EIO);
2267 goto failed;
2268 }
2269
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002270 hdev = hci_dev_get(index);
2271 if (hdev) {
2272 hci_dev_lock_bh(hdev);
2273 update_eir(hdev);
2274 hci_dev_unlock_bh(hdev);
2275 hci_dev_put(hdev);
2276 }
2277
Johan Hedbergb312b1612011-03-16 14:29:37 +02002278 err = cmd_complete(cmd->sk, index, MGMT_OP_SET_LOCAL_NAME, &ev,
2279 sizeof(ev));
2280 if (err < 0)
2281 goto failed;
2282
2283send_event:
2284 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, index, &ev, sizeof(ev),
2285 cmd ? cmd->sk : NULL);
2286
2287failed:
2288 if (cmd)
2289 mgmt_pending_remove(cmd);
2290 return err;
2291}
Szymon Jancc35938b2011-03-22 13:12:21 +01002292
2293int mgmt_read_local_oob_data_reply_complete(u16 index, u8 *hash, u8 *randomizer,
2294 u8 status)
2295{
2296 struct pending_cmd *cmd;
2297 int err;
2298
2299 BT_DBG("hci%u status %u", index, status);
2300
2301 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, index);
2302 if (!cmd)
2303 return -ENOENT;
2304
2305 if (status) {
2306 err = cmd_status(cmd->sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2307 EIO);
2308 } else {
2309 struct mgmt_rp_read_local_oob_data rp;
2310
2311 memcpy(rp.hash, hash, sizeof(rp.hash));
2312 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
2313
2314 err = cmd_complete(cmd->sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2315 &rp, sizeof(rp));
2316 }
2317
2318 mgmt_pending_remove(cmd);
2319
2320 return err;
2321}
Johan Hedberge17acd42011-03-30 23:57:16 +03002322
2323int mgmt_device_found(u16 index, bdaddr_t *bdaddr, u8 *dev_class, s8 rssi,
2324 u8 *eir)
2325{
2326 struct mgmt_ev_device_found ev;
2327
2328 memset(&ev, 0, sizeof(ev));
2329
2330 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberge17acd42011-03-30 23:57:16 +03002331 ev.rssi = rssi;
2332
2333 if (eir)
2334 memcpy(ev.eir, eir, sizeof(ev.eir));
2335
Andre Guedesf8523592011-09-09 18:56:26 -03002336 if (dev_class)
2337 memcpy(ev.dev_class, dev_class, sizeof(ev.dev_class));
2338
Johan Hedberge17acd42011-03-30 23:57:16 +03002339 return mgmt_event(MGMT_EV_DEVICE_FOUND, index, &ev, sizeof(ev), NULL);
2340}
Johan Hedberga88a9652011-03-30 13:18:12 +03002341
2342int mgmt_remote_name(u16 index, bdaddr_t *bdaddr, u8 *name)
2343{
2344 struct mgmt_ev_remote_name ev;
2345
2346 memset(&ev, 0, sizeof(ev));
2347
2348 bacpy(&ev.bdaddr, bdaddr);
2349 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
2350
2351 return mgmt_event(MGMT_EV_REMOTE_NAME, index, &ev, sizeof(ev), NULL);
2352}
Johan Hedberg314b2382011-04-27 10:29:57 -04002353
2354int mgmt_discovering(u16 index, u8 discovering)
2355{
2356 return mgmt_event(MGMT_EV_DISCOVERING, index, &discovering,
2357 sizeof(discovering), NULL);
2358}
Antti Julku5e762442011-08-25 16:48:02 +03002359
2360int mgmt_device_blocked(u16 index, bdaddr_t *bdaddr)
2361{
2362 struct pending_cmd *cmd;
2363 struct mgmt_ev_device_blocked ev;
2364
2365 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, index);
2366
2367 bacpy(&ev.bdaddr, bdaddr);
2368
2369 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, index, &ev, sizeof(ev),
2370 cmd ? cmd->sk : NULL);
2371}
2372
2373int mgmt_device_unblocked(u16 index, bdaddr_t *bdaddr)
2374{
2375 struct pending_cmd *cmd;
2376 struct mgmt_ev_device_unblocked ev;
2377
2378 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, index);
2379
2380 bacpy(&ev.bdaddr, bdaddr);
2381
2382 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, index, &ev, sizeof(ev),
2383 cmd ? cmd->sk : NULL);
2384}