blob: 080cfb6347e8b9dabfa24cd9b188612f1c4b457d [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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-12-13 21:07:06 +020071 kfree_skb(skb);
72
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -030073 return err;
Johan Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-12-13 21:07:06 +0200203 else
Johan Hedberga38528f2011-01-22 06:46:43 +0200204 rp.sec_mode = 2;
Johan Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-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{
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300697 struct bt_uuid *uuid;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200698 u8 val = 0;
699
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300700 list_for_each_entry(uuid, &hdev->uuids, list)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200701 val |= uuid->svc_hint;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200702
703 return val;
704}
705
706static int update_class(struct hci_dev *hdev)
707{
708 u8 cod[3];
709
710 BT_DBG("%s", hdev->name);
711
712 if (test_bit(HCI_SERVICE_CACHE, &hdev->flags))
713 return 0;
714
715 cod[0] = hdev->minor_class;
716 cod[1] = hdev->major_class;
717 cod[2] = get_service_classes(hdev);
718
719 if (memcmp(cod, hdev->dev_class, 3) == 0)
720 return 0;
721
722 return hci_send_cmd(hdev, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
723}
724
Szymon Janc4e51eae2011-02-25 19:05:48 +0100725static int add_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200726{
727 struct mgmt_cp_add_uuid *cp;
728 struct hci_dev *hdev;
729 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200730 int err;
731
732 cp = (void *) data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200733
Szymon Janc4e51eae2011-02-25 19:05:48 +0100734 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200735
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100736 if (len != sizeof(*cp))
737 return cmd_status(sk, index, MGMT_OP_ADD_UUID, EINVAL);
738
Szymon Janc4e51eae2011-02-25 19:05:48 +0100739 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200740 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100741 return cmd_status(sk, index, MGMT_OP_ADD_UUID, ENODEV);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200742
Andre Guedes8c156c32011-07-07 10:30:36 -0300743 hci_dev_lock_bh(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200744
745 uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC);
746 if (!uuid) {
747 err = -ENOMEM;
748 goto failed;
749 }
750
751 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200752 uuid->svc_hint = cp->svc_hint;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200753
754 list_add(&uuid->list, &hdev->uuids);
755
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200756 err = update_class(hdev);
757 if (err < 0)
758 goto failed;
759
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300760 err = update_eir(hdev);
761 if (err < 0)
762 goto failed;
763
Szymon Janc4e51eae2011-02-25 19:05:48 +0100764 err = cmd_complete(sk, index, MGMT_OP_ADD_UUID, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200765
766failed:
Andre Guedes8c156c32011-07-07 10:30:36 -0300767 hci_dev_unlock_bh(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200768 hci_dev_put(hdev);
769
770 return err;
771}
772
Szymon Janc4e51eae2011-02-25 19:05:48 +0100773static int remove_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200774{
775 struct list_head *p, *n;
Szymon Janc779cb852011-02-25 19:05:47 +0100776 struct mgmt_cp_remove_uuid *cp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200777 struct hci_dev *hdev;
778 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 +0200779 int err, found;
780
781 cp = (void *) data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200782
Szymon Janc4e51eae2011-02-25 19:05:48 +0100783 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200784
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100785 if (len != sizeof(*cp))
786 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID, EINVAL);
787
Szymon Janc4e51eae2011-02-25 19:05:48 +0100788 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200789 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100790 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID, ENODEV);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200791
Andre Guedes8c156c32011-07-07 10:30:36 -0300792 hci_dev_lock_bh(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200793
794 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
795 err = hci_uuids_clear(hdev);
796 goto unlock;
797 }
798
799 found = 0;
800
801 list_for_each_safe(p, n, &hdev->uuids) {
802 struct bt_uuid *match = list_entry(p, struct bt_uuid, list);
803
804 if (memcmp(match->uuid, cp->uuid, 16) != 0)
805 continue;
806
807 list_del(&match->list);
808 found++;
809 }
810
811 if (found == 0) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100812 err = cmd_status(sk, index, MGMT_OP_REMOVE_UUID, ENOENT);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200813 goto unlock;
814 }
815
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200816 err = update_class(hdev);
817 if (err < 0)
818 goto unlock;
819
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300820 err = update_eir(hdev);
821 if (err < 0)
822 goto unlock;
823
Szymon Janc4e51eae2011-02-25 19:05:48 +0100824 err = cmd_complete(sk, index, MGMT_OP_REMOVE_UUID, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200825
826unlock:
Andre Guedes8c156c32011-07-07 10:30:36 -0300827 hci_dev_unlock_bh(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200828 hci_dev_put(hdev);
829
830 return err;
831}
832
Szymon Janc4e51eae2011-02-25 19:05:48 +0100833static int set_dev_class(struct sock *sk, u16 index, unsigned char *data,
834 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200835{
836 struct hci_dev *hdev;
837 struct mgmt_cp_set_dev_class *cp;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200838 int err;
839
840 cp = (void *) data;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200841
Szymon Janc4e51eae2011-02-25 19:05:48 +0100842 BT_DBG("request for hci%u", index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200843
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100844 if (len != sizeof(*cp))
845 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS, EINVAL);
846
Szymon Janc4e51eae2011-02-25 19:05:48 +0100847 hdev = hci_dev_get(index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200848 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100849 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS, ENODEV);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200850
Andre Guedes8c156c32011-07-07 10:30:36 -0300851 hci_dev_lock_bh(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200852
853 hdev->major_class = cp->major;
854 hdev->minor_class = cp->minor;
855
856 err = update_class(hdev);
857
858 if (err == 0)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100859 err = cmd_complete(sk, index, MGMT_OP_SET_DEV_CLASS, NULL, 0);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200860
Andre Guedes8c156c32011-07-07 10:30:36 -0300861 hci_dev_unlock_bh(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200862 hci_dev_put(hdev);
863
864 return err;
865}
866
Szymon Janc4e51eae2011-02-25 19:05:48 +0100867static int set_service_cache(struct sock *sk, u16 index, unsigned char *data,
868 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200869{
870 struct hci_dev *hdev;
871 struct mgmt_cp_set_service_cache *cp;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200872 int err;
873
874 cp = (void *) data;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200875
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100876 if (len != sizeof(*cp))
Szymon Jancb8534e02011-03-01 16:55:34 +0100877 return cmd_status(sk, index, MGMT_OP_SET_SERVICE_CACHE, EINVAL);
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100878
Szymon Janc4e51eae2011-02-25 19:05:48 +0100879 hdev = hci_dev_get(index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200880 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100881 return cmd_status(sk, index, MGMT_OP_SET_SERVICE_CACHE, ENODEV);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200882
Andre Guedes8c156c32011-07-07 10:30:36 -0300883 hci_dev_lock_bh(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200884
Szymon Janc4e51eae2011-02-25 19:05:48 +0100885 BT_DBG("hci%u enable %d", index, cp->enable);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200886
887 if (cp->enable) {
888 set_bit(HCI_SERVICE_CACHE, &hdev->flags);
889 err = 0;
890 } else {
891 clear_bit(HCI_SERVICE_CACHE, &hdev->flags);
892 err = update_class(hdev);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300893 if (err == 0)
894 err = update_eir(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200895 }
896
897 if (err == 0)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100898 err = cmd_complete(sk, index, MGMT_OP_SET_SERVICE_CACHE, NULL,
899 0);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200900
Andre Guedes8c156c32011-07-07 10:30:36 -0300901 hci_dev_unlock_bh(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200902 hci_dev_put(hdev);
903
904 return err;
905}
906
Szymon Janc4e51eae2011-02-25 19:05:48 +0100907static int load_keys(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200908{
909 struct hci_dev *hdev;
910 struct mgmt_cp_load_keys *cp;
Szymon Janc4e51eae2011-02-25 19:05:48 +0100911 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -0300912 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200913
914 cp = (void *) data;
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100915
916 if (len < sizeof(*cp))
Gustavo F. Padovanb7059132011-10-14 19:23:27 -0300917 return cmd_status(sk, index, MGMT_OP_LOAD_KEYS, EINVAL);
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100918
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200919 key_count = get_unaligned_le16(&cp->key_count);
920
921 expected_len = sizeof(*cp) + key_count * sizeof(struct mgmt_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -0300922 if (expected_len != len) {
923 BT_ERR("load_keys: expected %u bytes, got %u bytes",
924 len, expected_len);
Gustavo F. Padovanb7059132011-10-14 19:23:27 -0300925 return cmd_status(sk, index, MGMT_OP_LOAD_KEYS, EINVAL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200926 }
927
Szymon Janc4e51eae2011-02-25 19:05:48 +0100928 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200929 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100930 return cmd_status(sk, index, MGMT_OP_LOAD_KEYS, ENODEV);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200931
Szymon Janc4e51eae2011-02-25 19:05:48 +0100932 BT_DBG("hci%u debug_keys %u key_count %u", index, cp->debug_keys,
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200933 key_count);
934
Andre Guedes8c156c32011-07-07 10:30:36 -0300935 hci_dev_lock_bh(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200936
937 hci_link_keys_clear(hdev);
938
939 set_bit(HCI_LINK_KEYS, &hdev->flags);
940
941 if (cp->debug_keys)
942 set_bit(HCI_DEBUG_KEYS, &hdev->flags);
943 else
944 clear_bit(HCI_DEBUG_KEYS, &hdev->flags);
945
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -0300946 for (i = 0; i < key_count; i++) {
947 struct mgmt_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200948
Johan Hedbergd25e28a2011-04-28 11:28:59 -0700949 hci_add_link_key(hdev, NULL, 0, &key->bdaddr, key->val, key->type,
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200950 key->pin_len);
951 }
952
Andre Guedes8c156c32011-07-07 10:30:36 -0300953 hci_dev_unlock_bh(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200954 hci_dev_put(hdev);
955
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -0300956 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200957}
958
Szymon Janc4e51eae2011-02-25 19:05:48 +0100959static int remove_key(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200960{
961 struct hci_dev *hdev;
962 struct mgmt_cp_remove_key *cp;
963 struct hci_conn *conn;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200964 int err;
965
966 cp = (void *) data;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200967
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100968 if (len != sizeof(*cp))
969 return cmd_status(sk, index, MGMT_OP_REMOVE_KEY, EINVAL);
970
Szymon Janc4e51eae2011-02-25 19:05:48 +0100971 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200972 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100973 return cmd_status(sk, index, MGMT_OP_REMOVE_KEY, ENODEV);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200974
Andre Guedes8c156c32011-07-07 10:30:36 -0300975 hci_dev_lock_bh(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200976
977 err = hci_remove_link_key(hdev, &cp->bdaddr);
978 if (err < 0) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100979 err = cmd_status(sk, index, MGMT_OP_REMOVE_KEY, -err);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200980 goto unlock;
981 }
982
983 err = 0;
984
985 if (!test_bit(HCI_UP, &hdev->flags) || !cp->disconnect)
986 goto unlock;
987
988 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
989 if (conn) {
990 struct hci_cp_disconnect dc;
991
992 put_unaligned_le16(conn->handle, &dc.handle);
993 dc.reason = 0x13; /* Remote User Terminated Connection */
Anderson Lizardo94ac0272011-06-13 15:42:03 -0400994 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200995 }
996
997unlock:
Andre Guedes8c156c32011-07-07 10:30:36 -0300998 hci_dev_unlock_bh(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200999 hci_dev_put(hdev);
1000
1001 return err;
1002}
1003
Szymon Janc4e51eae2011-02-25 19:05:48 +01001004static int disconnect(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02001005{
1006 struct hci_dev *hdev;
1007 struct mgmt_cp_disconnect *cp;
1008 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03001009 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001010 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001011 int err;
1012
1013 BT_DBG("");
1014
1015 cp = (void *) data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001016
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001017 if (len != sizeof(*cp))
1018 return cmd_status(sk, index, MGMT_OP_DISCONNECT, EINVAL);
1019
Szymon Janc4e51eae2011-02-25 19:05:48 +01001020 hdev = hci_dev_get(index);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001021 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001022 return cmd_status(sk, index, MGMT_OP_DISCONNECT, ENODEV);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001023
Andre Guedes8c156c32011-07-07 10:30:36 -03001024 hci_dev_lock_bh(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001025
1026 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001027 err = cmd_status(sk, index, MGMT_OP_DISCONNECT, ENETDOWN);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001028 goto failed;
1029 }
1030
Szymon Janc4e51eae2011-02-25 19:05:48 +01001031 if (mgmt_pending_find(MGMT_OP_DISCONNECT, index)) {
1032 err = cmd_status(sk, index, MGMT_OP_DISCONNECT, EBUSY);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001033 goto failed;
1034 }
1035
1036 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03001037 if (!conn)
1038 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->bdaddr);
1039
Johan Hedberg8962ee72011-01-20 12:40:27 +02001040 if (!conn) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001041 err = cmd_status(sk, index, MGMT_OP_DISCONNECT, ENOTCONN);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001042 goto failed;
1043 }
1044
Szymon Janc4e51eae2011-02-25 19:05:48 +01001045 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001046 if (!cmd) {
1047 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001048 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001049 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001050
1051 put_unaligned_le16(conn->handle, &dc.handle);
1052 dc.reason = 0x13; /* Remote User Terminated Connection */
1053
1054 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1055 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001056 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001057
1058failed:
Andre Guedes8c156c32011-07-07 10:30:36 -03001059 hci_dev_unlock_bh(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001060 hci_dev_put(hdev);
1061
1062 return err;
1063}
1064
Szymon Janc8ce62842011-03-01 16:55:32 +01001065static int get_connections(struct sock *sk, u16 index)
Johan Hedberg2784eb42011-01-21 13:56:35 +02001066{
Johan Hedberg2784eb42011-01-21 13:56:35 +02001067 struct mgmt_rp_get_connections *rp;
1068 struct hci_dev *hdev;
1069 struct list_head *p;
Johan Hedberga38528f2011-01-22 06:46:43 +02001070 size_t rp_len;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001071 u16 count;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001072 int i, err;
1073
1074 BT_DBG("");
1075
Szymon Janc4e51eae2011-02-25 19:05:48 +01001076 hdev = hci_dev_get(index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001077 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001078 return cmd_status(sk, index, MGMT_OP_GET_CONNECTIONS, ENODEV);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001079
Andre Guedes8c156c32011-07-07 10:30:36 -03001080 hci_dev_lock_bh(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001081
1082 count = 0;
1083 list_for_each(p, &hdev->conn_hash.list) {
1084 count++;
1085 }
1086
Johan Hedberga38528f2011-01-22 06:46:43 +02001087 rp_len = sizeof(*rp) + (count * sizeof(bdaddr_t));
1088 rp = kmalloc(rp_len, GFP_ATOMIC);
1089 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02001090 err = -ENOMEM;
1091 goto unlock;
1092 }
1093
Johan Hedberg2784eb42011-01-21 13:56:35 +02001094 put_unaligned_le16(count, &rp->conn_count);
1095
Johan Hedberg2784eb42011-01-21 13:56:35 +02001096 i = 0;
1097 list_for_each(p, &hdev->conn_hash.list) {
1098 struct hci_conn *c = list_entry(p, struct hci_conn, list);
1099
1100 bacpy(&rp->conn[i++], &c->dst);
1101 }
1102
Szymon Janc4e51eae2011-02-25 19:05:48 +01001103 err = cmd_complete(sk, index, MGMT_OP_GET_CONNECTIONS, rp, rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001104
1105unlock:
Johan Hedberga38528f2011-01-22 06:46:43 +02001106 kfree(rp);
Andre Guedes8c156c32011-07-07 10:30:36 -03001107 hci_dev_unlock_bh(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001108 hci_dev_put(hdev);
1109 return err;
1110}
1111
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001112static int send_pin_code_neg_reply(struct sock *sk, u16 index,
1113 struct hci_dev *hdev, struct mgmt_cp_pin_code_neg_reply *cp)
1114{
1115 struct pending_cmd *cmd;
1116 int err;
1117
1118 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, index, cp,
1119 sizeof(*cp));
1120 if (!cmd)
1121 return -ENOMEM;
1122
1123 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY, sizeof(cp->bdaddr),
1124 &cp->bdaddr);
1125 if (err < 0)
1126 mgmt_pending_remove(cmd);
1127
1128 return err;
1129}
1130
Szymon Janc4e51eae2011-02-25 19:05:48 +01001131static int pin_code_reply(struct sock *sk, u16 index, unsigned char *data,
1132 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001133{
1134 struct hci_dev *hdev;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001135 struct hci_conn *conn;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001136 struct mgmt_cp_pin_code_reply *cp;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001137 struct mgmt_cp_pin_code_neg_reply ncp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001138 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03001139 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001140 int err;
1141
1142 BT_DBG("");
1143
1144 cp = (void *) data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001145
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001146 if (len != sizeof(*cp))
1147 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, EINVAL);
1148
Szymon Janc4e51eae2011-02-25 19:05:48 +01001149 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001150 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001151 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENODEV);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001152
Andre Guedes8c156c32011-07-07 10:30:36 -03001153 hci_dev_lock_bh(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001154
1155 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001156 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENETDOWN);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001157 goto failed;
1158 }
1159
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001160 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
1161 if (!conn) {
1162 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENOTCONN);
1163 goto failed;
1164 }
1165
1166 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
1167 bacpy(&ncp.bdaddr, &cp->bdaddr);
1168
1169 BT_ERR("PIN code is not 16 bytes long");
1170
1171 err = send_pin_code_neg_reply(sk, index, hdev, &ncp);
1172 if (err >= 0)
1173 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1174 EINVAL);
1175
1176 goto failed;
1177 }
1178
Szymon Janc4e51eae2011-02-25 19:05:48 +01001179 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001180 if (!cmd) {
1181 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001182 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001183 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02001184
1185 bacpy(&reply.bdaddr, &cp->bdaddr);
1186 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02001187 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02001188
1189 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
1190 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001191 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001192
1193failed:
Andre Guedes8c156c32011-07-07 10:30:36 -03001194 hci_dev_unlock_bh(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001195 hci_dev_put(hdev);
1196
1197 return err;
1198}
1199
Szymon Janc4e51eae2011-02-25 19:05:48 +01001200static int pin_code_neg_reply(struct sock *sk, u16 index, unsigned char *data,
1201 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001202{
1203 struct hci_dev *hdev;
1204 struct mgmt_cp_pin_code_neg_reply *cp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001205 int err;
1206
1207 BT_DBG("");
1208
1209 cp = (void *) data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001210
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001211 if (len != sizeof(*cp))
1212 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1213 EINVAL);
1214
Szymon Janc4e51eae2011-02-25 19:05:48 +01001215 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001216 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001217 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1218 ENODEV);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001219
Andre Guedes8c156c32011-07-07 10:30:36 -03001220 hci_dev_lock_bh(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001221
1222 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001223 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1224 ENETDOWN);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001225 goto failed;
1226 }
1227
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001228 err = send_pin_code_neg_reply(sk, index, hdev, cp);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001229
1230failed:
Andre Guedes8c156c32011-07-07 10:30:36 -03001231 hci_dev_unlock_bh(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001232 hci_dev_put(hdev);
1233
1234 return err;
1235}
1236
Szymon Janc4e51eae2011-02-25 19:05:48 +01001237static int set_io_capability(struct sock *sk, u16 index, unsigned char *data,
1238 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001239{
1240 struct hci_dev *hdev;
1241 struct mgmt_cp_set_io_capability *cp;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001242
1243 BT_DBG("");
1244
1245 cp = (void *) data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001246
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001247 if (len != sizeof(*cp))
Szymon Jancb8534e02011-03-01 16:55:34 +01001248 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY, EINVAL);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001249
Szymon Janc4e51eae2011-02-25 19:05:48 +01001250 hdev = hci_dev_get(index);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001251 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001252 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY, ENODEV);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001253
Andre Guedes8c156c32011-07-07 10:30:36 -03001254 hci_dev_lock_bh(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001255
1256 hdev->io_capability = cp->io_capability;
1257
1258 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Szymon Jancb8534e02011-03-01 16:55:34 +01001259 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001260
Andre Guedes8c156c32011-07-07 10:30:36 -03001261 hci_dev_unlock_bh(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001262 hci_dev_put(hdev);
1263
Szymon Janc4e51eae2011-02-25 19:05:48 +01001264 return cmd_complete(sk, index, MGMT_OP_SET_IO_CAPABILITY, NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001265}
1266
Johan Hedberge9a416b2011-02-19 12:05:56 -03001267static inline struct pending_cmd *find_pairing(struct hci_conn *conn)
1268{
1269 struct hci_dev *hdev = conn->hdev;
1270 struct list_head *p;
1271
1272 list_for_each(p, &cmd_list) {
1273 struct pending_cmd *cmd;
1274
1275 cmd = list_entry(p, struct pending_cmd, list);
1276
1277 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
1278 continue;
1279
1280 if (cmd->index != hdev->id)
1281 continue;
1282
1283 if (cmd->user_data != conn)
1284 continue;
1285
1286 return cmd;
1287 }
1288
1289 return NULL;
1290}
1291
1292static void pairing_complete(struct pending_cmd *cmd, u8 status)
1293{
1294 struct mgmt_rp_pair_device rp;
1295 struct hci_conn *conn = cmd->user_data;
1296
Johan Hedberge9a416b2011-02-19 12:05:56 -03001297 bacpy(&rp.bdaddr, &conn->dst);
1298 rp.status = status;
1299
Szymon Janc4e51eae2011-02-25 19:05:48 +01001300 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001301
1302 /* So we don't get further callbacks for this connection */
1303 conn->connect_cfm_cb = NULL;
1304 conn->security_cfm_cb = NULL;
1305 conn->disconn_cfm_cb = NULL;
1306
1307 hci_conn_put(conn);
1308
Johan Hedberga664b5b2011-02-19 12:06:02 -03001309 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001310}
1311
1312static void pairing_complete_cb(struct hci_conn *conn, u8 status)
1313{
1314 struct pending_cmd *cmd;
1315
1316 BT_DBG("status %u", status);
1317
1318 cmd = find_pairing(conn);
1319 if (!cmd) {
1320 BT_DBG("Unable to find a pending command");
1321 return;
1322 }
1323
1324 pairing_complete(cmd, status);
1325}
1326
Szymon Janc4e51eae2011-02-25 19:05:48 +01001327static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001328{
1329 struct hci_dev *hdev;
1330 struct mgmt_cp_pair_device *cp;
1331 struct pending_cmd *cmd;
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001332 struct adv_entry *entry;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001333 u8 sec_level, auth_type;
1334 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001335 int err;
1336
1337 BT_DBG("");
1338
1339 cp = (void *) data;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001340
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001341 if (len != sizeof(*cp))
1342 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, EINVAL);
1343
Szymon Janc4e51eae2011-02-25 19:05:48 +01001344 hdev = hci_dev_get(index);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001345 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001346 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, ENODEV);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001347
Andre Guedes8c156c32011-07-07 10:30:36 -03001348 hci_dev_lock_bh(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001349
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001350 sec_level = BT_SECURITY_MEDIUM;
1351 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001352 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001353 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03001354 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001355
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001356 entry = hci_find_adv_entry(hdev, &cp->bdaddr);
1357 if (entry)
1358 conn = hci_connect(hdev, LE_LINK, &cp->bdaddr, sec_level,
1359 auth_type);
1360 else
1361 conn = hci_connect(hdev, ACL_LINK, &cp->bdaddr, sec_level,
1362 auth_type);
1363
Ville Tervo30e76272011-02-22 16:10:53 -03001364 if (IS_ERR(conn)) {
1365 err = PTR_ERR(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001366 goto unlock;
1367 }
1368
1369 if (conn->connect_cfm_cb) {
1370 hci_conn_put(conn);
Szymon Janc4e51eae2011-02-25 19:05:48 +01001371 err = cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, EBUSY);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001372 goto unlock;
1373 }
1374
Szymon Janc4e51eae2011-02-25 19:05:48 +01001375 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, index, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001376 if (!cmd) {
1377 err = -ENOMEM;
1378 hci_conn_put(conn);
1379 goto unlock;
1380 }
1381
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001382 /* For LE, just connecting isn't a proof that the pairing finished */
1383 if (!entry)
1384 conn->connect_cfm_cb = pairing_complete_cb;
1385
Johan Hedberge9a416b2011-02-19 12:05:56 -03001386 conn->security_cfm_cb = pairing_complete_cb;
1387 conn->disconn_cfm_cb = pairing_complete_cb;
1388 conn->io_capability = cp->io_cap;
1389 cmd->user_data = conn;
1390
1391 if (conn->state == BT_CONNECTED &&
1392 hci_conn_security(conn, sec_level, auth_type))
1393 pairing_complete(cmd, 0);
1394
1395 err = 0;
1396
1397unlock:
Andre Guedes8c156c32011-07-07 10:30:36 -03001398 hci_dev_unlock_bh(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001399 hci_dev_put(hdev);
1400
1401 return err;
1402}
1403
Szymon Janc4e51eae2011-02-25 19:05:48 +01001404static int user_confirm_reply(struct sock *sk, u16 index, unsigned char *data,
1405 u16 len, int success)
Johan Hedberga5c29682011-02-19 12:05:57 -03001406{
1407 struct mgmt_cp_user_confirm_reply *cp = (void *) data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001408 u16 mgmt_op, hci_op;
Johan Hedberga5c29682011-02-19 12:05:57 -03001409 struct pending_cmd *cmd;
1410 struct hci_dev *hdev;
1411 int err;
1412
1413 BT_DBG("");
1414
Johan Hedberga5c29682011-02-19 12:05:57 -03001415 if (success) {
1416 mgmt_op = MGMT_OP_USER_CONFIRM_REPLY;
1417 hci_op = HCI_OP_USER_CONFIRM_REPLY;
1418 } else {
1419 mgmt_op = MGMT_OP_USER_CONFIRM_NEG_REPLY;
1420 hci_op = HCI_OP_USER_CONFIRM_NEG_REPLY;
1421 }
1422
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001423 if (len != sizeof(*cp))
1424 return cmd_status(sk, index, mgmt_op, EINVAL);
1425
Szymon Janc4e51eae2011-02-25 19:05:48 +01001426 hdev = hci_dev_get(index);
Johan Hedberga5c29682011-02-19 12:05:57 -03001427 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001428 return cmd_status(sk, index, mgmt_op, ENODEV);
Johan Hedberga5c29682011-02-19 12:05:57 -03001429
Andre Guedes8c156c32011-07-07 10:30:36 -03001430 hci_dev_lock_bh(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02001431
Johan Hedberga5c29682011-02-19 12:05:57 -03001432 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001433 err = cmd_status(sk, index, mgmt_op, ENETDOWN);
Johan Hedberga5c29682011-02-19 12:05:57 -03001434 goto failed;
1435 }
1436
Szymon Janc4e51eae2011-02-25 19:05:48 +01001437 cmd = mgmt_pending_add(sk, mgmt_op, index, data, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03001438 if (!cmd) {
1439 err = -ENOMEM;
1440 goto failed;
1441 }
1442
1443 err = hci_send_cmd(hdev, hci_op, sizeof(cp->bdaddr), &cp->bdaddr);
Johan Hedberga664b5b2011-02-19 12:06:02 -03001444 if (err < 0)
1445 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03001446
1447failed:
Andre Guedes8c156c32011-07-07 10:30:36 -03001448 hci_dev_unlock_bh(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03001449 hci_dev_put(hdev);
1450
1451 return err;
1452}
1453
Johan Hedbergb312b1612011-03-16 14:29:37 +02001454static int set_local_name(struct sock *sk, u16 index, unsigned char *data,
1455 u16 len)
1456{
1457 struct mgmt_cp_set_local_name *mgmt_cp = (void *) data;
1458 struct hci_cp_write_local_name hci_cp;
1459 struct hci_dev *hdev;
1460 struct pending_cmd *cmd;
1461 int err;
1462
1463 BT_DBG("");
1464
1465 if (len != sizeof(*mgmt_cp))
1466 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, EINVAL);
1467
1468 hdev = hci_dev_get(index);
1469 if (!hdev)
1470 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, ENODEV);
1471
Andre Guedes8c156c32011-07-07 10:30:36 -03001472 hci_dev_lock_bh(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001473
1474 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, index, data, len);
1475 if (!cmd) {
1476 err = -ENOMEM;
1477 goto failed;
1478 }
1479
1480 memcpy(hci_cp.name, mgmt_cp->name, sizeof(hci_cp.name));
1481 err = hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(hci_cp),
1482 &hci_cp);
1483 if (err < 0)
1484 mgmt_pending_remove(cmd);
1485
1486failed:
Andre Guedes8c156c32011-07-07 10:30:36 -03001487 hci_dev_unlock_bh(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001488 hci_dev_put(hdev);
1489
1490 return err;
1491}
1492
Szymon Jancc35938b2011-03-22 13:12:21 +01001493static int read_local_oob_data(struct sock *sk, u16 index)
1494{
1495 struct hci_dev *hdev;
1496 struct pending_cmd *cmd;
1497 int err;
1498
1499 BT_DBG("hci%u", index);
1500
1501 hdev = hci_dev_get(index);
1502 if (!hdev)
1503 return cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
1504 ENODEV);
1505
Andre Guedes8c156c32011-07-07 10:30:36 -03001506 hci_dev_lock_bh(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01001507
1508 if (!test_bit(HCI_UP, &hdev->flags)) {
1509 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
1510 ENETDOWN);
1511 goto unlock;
1512 }
1513
1514 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
1515 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
1516 EOPNOTSUPP);
1517 goto unlock;
1518 }
1519
1520 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, index)) {
1521 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA, EBUSY);
1522 goto unlock;
1523 }
1524
1525 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, index, NULL, 0);
1526 if (!cmd) {
1527 err = -ENOMEM;
1528 goto unlock;
1529 }
1530
1531 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
1532 if (err < 0)
1533 mgmt_pending_remove(cmd);
1534
1535unlock:
Andre Guedes8c156c32011-07-07 10:30:36 -03001536 hci_dev_unlock_bh(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01001537 hci_dev_put(hdev);
1538
1539 return err;
1540}
1541
Szymon Janc2763eda2011-03-22 13:12:22 +01001542static int add_remote_oob_data(struct sock *sk, u16 index, unsigned char *data,
1543 u16 len)
1544{
1545 struct hci_dev *hdev;
1546 struct mgmt_cp_add_remote_oob_data *cp = (void *) data;
1547 int err;
1548
1549 BT_DBG("hci%u ", index);
1550
1551 if (len != sizeof(*cp))
1552 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
1553 EINVAL);
1554
1555 hdev = hci_dev_get(index);
1556 if (!hdev)
1557 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
1558 ENODEV);
1559
Andre Guedes8c156c32011-07-07 10:30:36 -03001560 hci_dev_lock_bh(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001561
1562 err = hci_add_remote_oob_data(hdev, &cp->bdaddr, cp->hash,
1563 cp->randomizer);
1564 if (err < 0)
1565 err = cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, -err);
1566 else
1567 err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, NULL,
1568 0);
1569
Andre Guedes8c156c32011-07-07 10:30:36 -03001570 hci_dev_unlock_bh(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001571 hci_dev_put(hdev);
1572
1573 return err;
1574}
1575
1576static int remove_remote_oob_data(struct sock *sk, u16 index,
1577 unsigned char *data, u16 len)
1578{
1579 struct hci_dev *hdev;
1580 struct mgmt_cp_remove_remote_oob_data *cp = (void *) data;
1581 int err;
1582
1583 BT_DBG("hci%u ", index);
1584
1585 if (len != sizeof(*cp))
1586 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
1587 EINVAL);
1588
1589 hdev = hci_dev_get(index);
1590 if (!hdev)
1591 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
1592 ENODEV);
1593
Andre Guedes8c156c32011-07-07 10:30:36 -03001594 hci_dev_lock_bh(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001595
1596 err = hci_remove_remote_oob_data(hdev, &cp->bdaddr);
1597 if (err < 0)
1598 err = cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
1599 -err);
1600 else
1601 err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
1602 NULL, 0);
1603
Andre Guedes8c156c32011-07-07 10:30:36 -03001604 hci_dev_unlock_bh(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001605 hci_dev_put(hdev);
1606
1607 return err;
1608}
1609
Johan Hedberg14a53662011-04-27 10:29:56 -04001610static int start_discovery(struct sock *sk, u16 index)
1611{
1612 u8 lap[3] = { 0x33, 0x8b, 0x9e };
1613 struct hci_cp_inquiry cp;
1614 struct pending_cmd *cmd;
1615 struct hci_dev *hdev;
1616 int err;
1617
1618 BT_DBG("hci%u", index);
1619
1620 hdev = hci_dev_get(index);
1621 if (!hdev)
1622 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY, ENODEV);
1623
1624 hci_dev_lock_bh(hdev);
1625
1626 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, index, NULL, 0);
1627 if (!cmd) {
1628 err = -ENOMEM;
1629 goto failed;
1630 }
1631
1632 memset(&cp, 0, sizeof(cp));
1633 memcpy(&cp.lap, lap, 3);
1634 cp.length = 0x08;
1635 cp.num_rsp = 0x00;
1636
1637 err = hci_send_cmd(hdev, HCI_OP_INQUIRY, sizeof(cp), &cp);
1638 if (err < 0)
1639 mgmt_pending_remove(cmd);
1640
1641failed:
1642 hci_dev_unlock_bh(hdev);
1643 hci_dev_put(hdev);
1644
1645 return err;
1646}
1647
1648static int stop_discovery(struct sock *sk, u16 index)
1649{
1650 struct hci_dev *hdev;
1651 struct pending_cmd *cmd;
1652 int err;
1653
1654 BT_DBG("hci%u", index);
1655
1656 hdev = hci_dev_get(index);
1657 if (!hdev)
1658 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY, ENODEV);
1659
1660 hci_dev_lock_bh(hdev);
1661
1662 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, index, NULL, 0);
1663 if (!cmd) {
1664 err = -ENOMEM;
1665 goto failed;
1666 }
1667
1668 err = hci_send_cmd(hdev, HCI_OP_INQUIRY_CANCEL, 0, NULL);
1669 if (err < 0)
1670 mgmt_pending_remove(cmd);
1671
1672failed:
1673 hci_dev_unlock_bh(hdev);
1674 hci_dev_put(hdev);
1675
1676 return err;
1677}
1678
Antti Julku7fbec222011-06-15 12:01:15 +03001679static int block_device(struct sock *sk, u16 index, unsigned char *data,
1680 u16 len)
1681{
1682 struct hci_dev *hdev;
Antti Julku5e762442011-08-25 16:48:02 +03001683 struct pending_cmd *cmd;
1684 struct mgmt_cp_block_device *cp = (void *) data;
Antti Julku7fbec222011-06-15 12:01:15 +03001685 int err;
1686
1687 BT_DBG("hci%u", index);
1688
Antti Julku7fbec222011-06-15 12:01:15 +03001689 if (len != sizeof(*cp))
1690 return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
1691 EINVAL);
1692
1693 hdev = hci_dev_get(index);
1694 if (!hdev)
1695 return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
1696 ENODEV);
1697
Antti Julku5e762442011-08-25 16:48:02 +03001698 hci_dev_lock_bh(hdev);
1699
1700 cmd = mgmt_pending_add(sk, MGMT_OP_BLOCK_DEVICE, index, NULL, 0);
1701 if (!cmd) {
1702 err = -ENOMEM;
1703 goto failed;
1704 }
1705
Antti Julku7fbec222011-06-15 12:01:15 +03001706 err = hci_blacklist_add(hdev, &cp->bdaddr);
1707
1708 if (err < 0)
1709 err = cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE, -err);
1710 else
1711 err = cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE,
1712 NULL, 0);
Antti Julku5e762442011-08-25 16:48:02 +03001713
1714 mgmt_pending_remove(cmd);
1715
1716failed:
1717 hci_dev_unlock_bh(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03001718 hci_dev_put(hdev);
1719
1720 return err;
1721}
1722
1723static int unblock_device(struct sock *sk, u16 index, unsigned char *data,
1724 u16 len)
1725{
1726 struct hci_dev *hdev;
Antti Julku5e762442011-08-25 16:48:02 +03001727 struct pending_cmd *cmd;
1728 struct mgmt_cp_unblock_device *cp = (void *) data;
Antti Julku7fbec222011-06-15 12:01:15 +03001729 int err;
1730
1731 BT_DBG("hci%u", index);
1732
Antti Julku7fbec222011-06-15 12:01:15 +03001733 if (len != sizeof(*cp))
1734 return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
1735 EINVAL);
1736
1737 hdev = hci_dev_get(index);
1738 if (!hdev)
1739 return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
1740 ENODEV);
1741
Antti Julku5e762442011-08-25 16:48:02 +03001742 hci_dev_lock_bh(hdev);
1743
1744 cmd = mgmt_pending_add(sk, MGMT_OP_UNBLOCK_DEVICE, index, NULL, 0);
1745 if (!cmd) {
1746 err = -ENOMEM;
1747 goto failed;
1748 }
1749
Antti Julku7fbec222011-06-15 12:01:15 +03001750 err = hci_blacklist_del(hdev, &cp->bdaddr);
1751
1752 if (err < 0)
1753 err = cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE, -err);
1754 else
1755 err = cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE,
1756 NULL, 0);
Antti Julku5e762442011-08-25 16:48:02 +03001757
1758 mgmt_pending_remove(cmd);
1759
1760failed:
1761 hci_dev_unlock_bh(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03001762 hci_dev_put(hdev);
1763
1764 return err;
1765}
1766
Antti Julkuf6422ec2011-06-22 13:11:56 +03001767static int set_fast_connectable(struct sock *sk, u16 index,
1768 unsigned char *data, u16 len)
1769{
1770 struct hci_dev *hdev;
1771 struct mgmt_cp_set_fast_connectable *cp = (void *) data;
1772 struct hci_cp_write_page_scan_activity acp;
1773 u8 type;
1774 int err;
1775
1776 BT_DBG("hci%u", index);
1777
1778 if (len != sizeof(*cp))
1779 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
1780 EINVAL);
1781
1782 hdev = hci_dev_get(index);
1783 if (!hdev)
1784 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
1785 ENODEV);
1786
1787 hci_dev_lock(hdev);
1788
1789 if (cp->enable) {
1790 type = PAGE_SCAN_TYPE_INTERLACED;
1791 acp.interval = 0x0024; /* 22.5 msec page scan interval */
1792 } else {
1793 type = PAGE_SCAN_TYPE_STANDARD; /* default */
1794 acp.interval = 0x0800; /* default 1.28 sec page scan */
1795 }
1796
1797 acp.window = 0x0012; /* default 11.25 msec page scan window */
1798
1799 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
1800 sizeof(acp), &acp);
1801 if (err < 0) {
1802 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
1803 -err);
1804 goto done;
1805 }
1806
1807 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
1808 if (err < 0) {
1809 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
1810 -err);
1811 goto done;
1812 }
1813
1814 err = cmd_complete(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
1815 NULL, 0);
1816done:
1817 hci_dev_unlock(hdev);
1818 hci_dev_put(hdev);
1819
1820 return err;
1821}
1822
Johan Hedberg03811012010-12-08 00:21:06 +02001823int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
1824{
1825 unsigned char *buf;
1826 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001827 u16 opcode, index, len;
Johan Hedberg03811012010-12-08 00:21:06 +02001828 int err;
1829
1830 BT_DBG("got %zu bytes", msglen);
1831
1832 if (msglen < sizeof(*hdr))
1833 return -EINVAL;
1834
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03001835 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02001836 if (!buf)
1837 return -ENOMEM;
1838
1839 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
1840 err = -EFAULT;
1841 goto done;
1842 }
1843
1844 hdr = (struct mgmt_hdr *) buf;
1845 opcode = get_unaligned_le16(&hdr->opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01001846 index = get_unaligned_le16(&hdr->index);
Johan Hedberg03811012010-12-08 00:21:06 +02001847 len = get_unaligned_le16(&hdr->len);
1848
1849 if (len != msglen - sizeof(*hdr)) {
1850 err = -EINVAL;
1851 goto done;
1852 }
1853
1854 switch (opcode) {
Johan Hedberg02d98122010-12-13 21:07:04 +02001855 case MGMT_OP_READ_VERSION:
1856 err = read_version(sk);
1857 break;
Johan Hedbergfaba42e2010-12-13 21:07:05 +02001858 case MGMT_OP_READ_INDEX_LIST:
1859 err = read_index_list(sk);
1860 break;
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001861 case MGMT_OP_READ_INFO:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001862 err = read_controller_info(sk, index);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001863 break;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001864 case MGMT_OP_SET_POWERED:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001865 err = set_powered(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001866 break;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001867 case MGMT_OP_SET_DISCOVERABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001868 err = set_discoverable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001869 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001870 case MGMT_OP_SET_CONNECTABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001871 err = set_connectable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001872 break;
Johan Hedbergc542a062011-01-26 13:11:03 +02001873 case MGMT_OP_SET_PAIRABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001874 err = set_pairable(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergc542a062011-01-26 13:11:03 +02001875 break;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001876 case MGMT_OP_ADD_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001877 err = add_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001878 break;
1879 case MGMT_OP_REMOVE_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001880 err = remove_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001881 break;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001882 case MGMT_OP_SET_DEV_CLASS:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001883 err = set_dev_class(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001884 break;
1885 case MGMT_OP_SET_SERVICE_CACHE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001886 err = set_service_cache(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001887 break;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001888 case MGMT_OP_LOAD_KEYS:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001889 err = load_keys(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001890 break;
1891 case MGMT_OP_REMOVE_KEY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001892 err = remove_key(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001893 break;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001894 case MGMT_OP_DISCONNECT:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001895 err = disconnect(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001896 break;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001897 case MGMT_OP_GET_CONNECTIONS:
Szymon Janc8ce62842011-03-01 16:55:32 +01001898 err = get_connections(sk, index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001899 break;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001900 case MGMT_OP_PIN_CODE_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001901 err = pin_code_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001902 break;
1903 case MGMT_OP_PIN_CODE_NEG_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001904 err = pin_code_neg_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001905 break;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001906 case MGMT_OP_SET_IO_CAPABILITY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001907 err = set_io_capability(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001908 break;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001909 case MGMT_OP_PAIR_DEVICE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001910 err = pair_device(sk, index, buf + sizeof(*hdr), len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001911 break;
Johan Hedberga5c29682011-02-19 12:05:57 -03001912 case MGMT_OP_USER_CONFIRM_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001913 err = user_confirm_reply(sk, index, buf + sizeof(*hdr), len, 1);
Johan Hedberga5c29682011-02-19 12:05:57 -03001914 break;
1915 case MGMT_OP_USER_CONFIRM_NEG_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001916 err = user_confirm_reply(sk, index, buf + sizeof(*hdr), len, 0);
Johan Hedberga5c29682011-02-19 12:05:57 -03001917 break;
Johan Hedbergb312b1612011-03-16 14:29:37 +02001918 case MGMT_OP_SET_LOCAL_NAME:
1919 err = set_local_name(sk, index, buf + sizeof(*hdr), len);
1920 break;
Szymon Jancc35938b2011-03-22 13:12:21 +01001921 case MGMT_OP_READ_LOCAL_OOB_DATA:
1922 err = read_local_oob_data(sk, index);
1923 break;
Szymon Janc2763eda2011-03-22 13:12:22 +01001924 case MGMT_OP_ADD_REMOTE_OOB_DATA:
1925 err = add_remote_oob_data(sk, index, buf + sizeof(*hdr), len);
1926 break;
1927 case MGMT_OP_REMOVE_REMOTE_OOB_DATA:
1928 err = remove_remote_oob_data(sk, index, buf + sizeof(*hdr),
1929 len);
1930 break;
Johan Hedberg14a53662011-04-27 10:29:56 -04001931 case MGMT_OP_START_DISCOVERY:
1932 err = start_discovery(sk, index);
1933 break;
1934 case MGMT_OP_STOP_DISCOVERY:
1935 err = stop_discovery(sk, index);
1936 break;
Antti Julku7fbec222011-06-15 12:01:15 +03001937 case MGMT_OP_BLOCK_DEVICE:
1938 err = block_device(sk, index, buf + sizeof(*hdr), len);
1939 break;
1940 case MGMT_OP_UNBLOCK_DEVICE:
1941 err = unblock_device(sk, index, buf + sizeof(*hdr), len);
1942 break;
Antti Julkuf6422ec2011-06-22 13:11:56 +03001943 case MGMT_OP_SET_FAST_CONNECTABLE:
1944 err = set_fast_connectable(sk, index, buf + sizeof(*hdr),
1945 len);
1946 break;
Johan Hedberg03811012010-12-08 00:21:06 +02001947 default:
1948 BT_DBG("Unknown op %u", opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01001949 err = cmd_status(sk, index, opcode, 0x01);
Johan Hedberg03811012010-12-08 00:21:06 +02001950 break;
1951 }
1952
Johan Hedberge41d8b42010-12-13 21:07:03 +02001953 if (err < 0)
1954 goto done;
1955
Johan Hedberg03811012010-12-08 00:21:06 +02001956 err = msglen;
1957
1958done:
1959 kfree(buf);
1960 return err;
1961}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001962
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001963int mgmt_index_added(u16 index)
1964{
Szymon Janc4e51eae2011-02-25 19:05:48 +01001965 return mgmt_event(MGMT_EV_INDEX_ADDED, index, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001966}
1967
1968int mgmt_index_removed(u16 index)
1969{
Szymon Janc4e51eae2011-02-25 19:05:48 +01001970 return mgmt_event(MGMT_EV_INDEX_REMOVED, index, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001971}
1972
Johan Hedberg73f22f62010-12-29 16:00:25 +02001973struct cmd_lookup {
Johan Hedberg72a734e2010-12-30 00:38:22 +02001974 u8 val;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001975 struct sock *sk;
1976};
1977
Johan Hedberg72a734e2010-12-30 00:38:22 +02001978static void mode_rsp(struct pending_cmd *cmd, void *data)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001979{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01001980 struct mgmt_mode *cp = cmd->param;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001981 struct cmd_lookup *match = data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001982
Johan Hedberg72a734e2010-12-30 00:38:22 +02001983 if (cp->val != match->val)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001984 return;
1985
Johan Hedberg053f0212011-01-26 13:07:10 +02001986 send_mode_rsp(cmd->sk, cmd->opcode, cmd->index, cp->val);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001987
1988 list_del(&cmd->list);
1989
1990 if (match->sk == NULL) {
1991 match->sk = cmd->sk;
1992 sock_hold(match->sk);
1993 }
1994
1995 mgmt_pending_free(cmd);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001996}
Johan Hedberg5add6af2010-12-16 10:00:37 +02001997
1998int mgmt_powered(u16 index, u8 powered)
1999{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002000 struct mgmt_mode ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002001 struct cmd_lookup match = { powered, NULL };
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002002 int ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002003
Johan Hedberg72a734e2010-12-30 00:38:22 +02002004 mgmt_pending_foreach(MGMT_OP_SET_POWERED, index, mode_rsp, &match);
Johan Hedberg5add6af2010-12-16 10:00:37 +02002005
Johan Hedberg72a734e2010-12-30 00:38:22 +02002006 ev.val = powered;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002007
Szymon Janc4e51eae2011-02-25 19:05:48 +01002008 ret = mgmt_event(MGMT_EV_POWERED, index, &ev, sizeof(ev), match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002009
2010 if (match.sk)
2011 sock_put(match.sk);
2012
2013 return ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002014}
Johan Hedberg73f22f62010-12-29 16:00:25 +02002015
Johan Hedberg73f22f62010-12-29 16:00:25 +02002016int mgmt_discoverable(u16 index, u8 discoverable)
2017{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002018 struct mgmt_mode ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002019 struct cmd_lookup match = { discoverable, NULL };
2020 int ret;
2021
Szymon Jancb8534e02011-03-01 16:55:34 +01002022 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, index, mode_rsp, &match);
Johan Hedberg72a734e2010-12-30 00:38:22 +02002023
Johan Hedberg72a734e2010-12-30 00:38:22 +02002024 ev.val = discoverable;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002025
Szymon Janc4e51eae2011-02-25 19:05:48 +01002026 ret = mgmt_event(MGMT_EV_DISCOVERABLE, index, &ev, sizeof(ev),
2027 match.sk);
Johan Hedberg73f22f62010-12-29 16:00:25 +02002028
2029 if (match.sk)
2030 sock_put(match.sk);
2031
2032 return ret;
2033}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002034
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002035int mgmt_connectable(u16 index, u8 connectable)
2036{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002037 struct mgmt_mode ev;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002038 struct cmd_lookup match = { connectable, NULL };
2039 int ret;
2040
Johan Hedberg72a734e2010-12-30 00:38:22 +02002041 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, index, mode_rsp, &match);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002042
Johan Hedberg72a734e2010-12-30 00:38:22 +02002043 ev.val = connectable;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002044
Szymon Janc4e51eae2011-02-25 19:05:48 +01002045 ret = mgmt_event(MGMT_EV_CONNECTABLE, index, &ev, sizeof(ev), match.sk);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002046
2047 if (match.sk)
2048 sock_put(match.sk);
2049
2050 return ret;
2051}
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002052
Johan Hedberg4df378a2011-04-28 11:29:03 -07002053int mgmt_new_key(u16 index, struct link_key *key, u8 persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002054{
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002055 struct mgmt_ev_new_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002056
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002057 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002058
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002059 ev.store_hint = persistent;
2060 bacpy(&ev.key.bdaddr, &key->bdaddr);
2061 ev.key.type = key->type;
2062 memcpy(ev.key.val, key->val, 16);
2063 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002064
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002065 return mgmt_event(MGMT_EV_NEW_KEY, index, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002066}
Johan Hedbergf7520542011-01-20 12:34:39 +02002067
Vinicius Costa Gomescfafccf2011-08-19 21:06:56 -03002068int mgmt_connected(u16 index, bdaddr_t *bdaddr, u8 link_type)
Johan Hedbergf7520542011-01-20 12:34:39 +02002069{
2070 struct mgmt_ev_connected ev;
2071
Johan Hedbergf7520542011-01-20 12:34:39 +02002072 bacpy(&ev.bdaddr, bdaddr);
Vinicius Costa Gomescfafccf2011-08-19 21:06:56 -03002073 ev.link_type = link_type;
Johan Hedbergf7520542011-01-20 12:34:39 +02002074
Szymon Janc4e51eae2011-02-25 19:05:48 +01002075 return mgmt_event(MGMT_EV_CONNECTED, index, &ev, sizeof(ev), NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02002076}
2077
Johan Hedberg8962ee72011-01-20 12:40:27 +02002078static void disconnect_rsp(struct pending_cmd *cmd, void *data)
2079{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01002080 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002081 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02002082 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002083
Johan Hedberga38528f2011-01-22 06:46:43 +02002084 bacpy(&rp.bdaddr, &cp->bdaddr);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002085
Szymon Janc4e51eae2011-02-25 19:05:48 +01002086 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002087
2088 *sk = cmd->sk;
2089 sock_hold(*sk);
2090
Johan Hedberga664b5b2011-02-19 12:06:02 -03002091 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002092}
2093
Johan Hedbergf7520542011-01-20 12:34:39 +02002094int mgmt_disconnected(u16 index, bdaddr_t *bdaddr)
2095{
2096 struct mgmt_ev_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002097 struct sock *sk = NULL;
2098 int err;
2099
2100 mgmt_pending_foreach(MGMT_OP_DISCONNECT, index, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02002101
Johan Hedbergf7520542011-01-20 12:34:39 +02002102 bacpy(&ev.bdaddr, bdaddr);
2103
Szymon Janc4e51eae2011-02-25 19:05:48 +01002104 err = mgmt_event(MGMT_EV_DISCONNECTED, index, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002105
2106 if (sk)
2107 sock_put(sk);
2108
2109 return err;
2110}
2111
2112int mgmt_disconnect_failed(u16 index)
2113{
2114 struct pending_cmd *cmd;
2115 int err;
2116
2117 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, index);
2118 if (!cmd)
2119 return -ENOENT;
2120
Szymon Janc4e51eae2011-02-25 19:05:48 +01002121 err = cmd_status(cmd->sk, index, MGMT_OP_DISCONNECT, EIO);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002122
Johan Hedberga664b5b2011-02-19 12:06:02 -03002123 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002124
2125 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02002126}
Johan Hedberg17d5c042011-01-22 06:09:08 +02002127
2128int mgmt_connect_failed(u16 index, bdaddr_t *bdaddr, u8 status)
2129{
2130 struct mgmt_ev_connect_failed ev;
2131
Johan Hedberg17d5c042011-01-22 06:09:08 +02002132 bacpy(&ev.bdaddr, bdaddr);
2133 ev.status = status;
2134
Szymon Janc4e51eae2011-02-25 19:05:48 +01002135 return mgmt_event(MGMT_EV_CONNECT_FAILED, index, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02002136}
Johan Hedberg980e1a52011-01-22 06:10:07 +02002137
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02002138int mgmt_pin_code_request(u16 index, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002139{
2140 struct mgmt_ev_pin_code_request ev;
2141
Johan Hedberg980e1a52011-01-22 06:10:07 +02002142 bacpy(&ev.bdaddr, bdaddr);
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02002143 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002144
Szymon Janc4e51eae2011-02-25 19:05:48 +01002145 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, index, &ev, sizeof(ev),
2146 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002147}
2148
2149int mgmt_pin_code_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
2150{
2151 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002152 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002153 int err;
2154
2155 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, index);
2156 if (!cmd)
2157 return -ENOENT;
2158
Johan Hedbergac56fb12011-02-19 12:05:59 -03002159 bacpy(&rp.bdaddr, bdaddr);
2160 rp.status = status;
2161
Szymon Janc4e51eae2011-02-25 19:05:48 +01002162 err = cmd_complete(cmd->sk, index, MGMT_OP_PIN_CODE_REPLY, &rp,
2163 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002164
Johan Hedberga664b5b2011-02-19 12:06:02 -03002165 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002166
2167 return err;
2168}
2169
2170int mgmt_pin_code_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
2171{
2172 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002173 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002174 int err;
2175
2176 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, index);
2177 if (!cmd)
2178 return -ENOENT;
2179
Johan Hedbergac56fb12011-02-19 12:05:59 -03002180 bacpy(&rp.bdaddr, bdaddr);
2181 rp.status = status;
2182
Szymon Janc4e51eae2011-02-25 19:05:48 +01002183 err = cmd_complete(cmd->sk, index, MGMT_OP_PIN_CODE_NEG_REPLY, &rp,
2184 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002185
Johan Hedberga664b5b2011-02-19 12:06:02 -03002186 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002187
2188 return err;
2189}
Johan Hedberga5c29682011-02-19 12:05:57 -03002190
Johan Hedberg55bc1a32011-04-28 11:28:56 -07002191int mgmt_user_confirm_request(u16 index, bdaddr_t *bdaddr, __le32 value,
2192 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03002193{
2194 struct mgmt_ev_user_confirm_request ev;
2195
2196 BT_DBG("hci%u", index);
2197
Johan Hedberga5c29682011-02-19 12:05:57 -03002198 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07002199 ev.confirm_hint = confirm_hint;
Johan Hedberga5c29682011-02-19 12:05:57 -03002200 put_unaligned_le32(value, &ev.value);
2201
Szymon Janc4e51eae2011-02-25 19:05:48 +01002202 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, index, &ev, sizeof(ev),
2203 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03002204}
2205
2206static int confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status,
2207 u8 opcode)
2208{
2209 struct pending_cmd *cmd;
2210 struct mgmt_rp_user_confirm_reply rp;
2211 int err;
2212
2213 cmd = mgmt_pending_find(opcode, index);
2214 if (!cmd)
2215 return -ENOENT;
2216
Johan Hedberga5c29682011-02-19 12:05:57 -03002217 bacpy(&rp.bdaddr, bdaddr);
2218 rp.status = status;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002219 err = cmd_complete(cmd->sk, index, opcode, &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03002220
Johan Hedberga664b5b2011-02-19 12:06:02 -03002221 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002222
2223 return err;
2224}
2225
2226int mgmt_user_confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
2227{
2228 return confirm_reply_complete(index, bdaddr, status,
2229 MGMT_OP_USER_CONFIRM_REPLY);
2230}
2231
Szymon Jancb8534e02011-03-01 16:55:34 +01002232int mgmt_user_confirm_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03002233{
2234 return confirm_reply_complete(index, bdaddr, status,
2235 MGMT_OP_USER_CONFIRM_NEG_REPLY);
2236}
Johan Hedberg2a611692011-02-19 12:06:00 -03002237
2238int mgmt_auth_failed(u16 index, bdaddr_t *bdaddr, u8 status)
2239{
2240 struct mgmt_ev_auth_failed ev;
2241
Johan Hedberg2a611692011-02-19 12:06:00 -03002242 bacpy(&ev.bdaddr, bdaddr);
2243 ev.status = status;
2244
Szymon Janc4e51eae2011-02-25 19:05:48 +01002245 return mgmt_event(MGMT_EV_AUTH_FAILED, index, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03002246}
Johan Hedbergb312b1612011-03-16 14:29:37 +02002247
2248int mgmt_set_local_name_complete(u16 index, u8 *name, u8 status)
2249{
2250 struct pending_cmd *cmd;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002251 struct hci_dev *hdev;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002252 struct mgmt_cp_set_local_name ev;
2253 int err;
2254
2255 memset(&ev, 0, sizeof(ev));
2256 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
2257
2258 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, index);
2259 if (!cmd)
2260 goto send_event;
2261
2262 if (status) {
2263 err = cmd_status(cmd->sk, index, MGMT_OP_SET_LOCAL_NAME, EIO);
2264 goto failed;
2265 }
2266
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002267 hdev = hci_dev_get(index);
2268 if (hdev) {
2269 hci_dev_lock_bh(hdev);
2270 update_eir(hdev);
2271 hci_dev_unlock_bh(hdev);
2272 hci_dev_put(hdev);
2273 }
2274
Johan Hedbergb312b1612011-03-16 14:29:37 +02002275 err = cmd_complete(cmd->sk, index, MGMT_OP_SET_LOCAL_NAME, &ev,
2276 sizeof(ev));
2277 if (err < 0)
2278 goto failed;
2279
2280send_event:
2281 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, index, &ev, sizeof(ev),
2282 cmd ? cmd->sk : NULL);
2283
2284failed:
2285 if (cmd)
2286 mgmt_pending_remove(cmd);
2287 return err;
2288}
Szymon Jancc35938b2011-03-22 13:12:21 +01002289
2290int mgmt_read_local_oob_data_reply_complete(u16 index, u8 *hash, u8 *randomizer,
2291 u8 status)
2292{
2293 struct pending_cmd *cmd;
2294 int err;
2295
2296 BT_DBG("hci%u status %u", index, status);
2297
2298 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, index);
2299 if (!cmd)
2300 return -ENOENT;
2301
2302 if (status) {
2303 err = cmd_status(cmd->sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2304 EIO);
2305 } else {
2306 struct mgmt_rp_read_local_oob_data rp;
2307
2308 memcpy(rp.hash, hash, sizeof(rp.hash));
2309 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
2310
2311 err = cmd_complete(cmd->sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2312 &rp, sizeof(rp));
2313 }
2314
2315 mgmt_pending_remove(cmd);
2316
2317 return err;
2318}
Johan Hedberge17acd42011-03-30 23:57:16 +03002319
2320int mgmt_device_found(u16 index, bdaddr_t *bdaddr, u8 *dev_class, s8 rssi,
2321 u8 *eir)
2322{
2323 struct mgmt_ev_device_found ev;
2324
2325 memset(&ev, 0, sizeof(ev));
2326
2327 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberge17acd42011-03-30 23:57:16 +03002328 ev.rssi = rssi;
2329
2330 if (eir)
2331 memcpy(ev.eir, eir, sizeof(ev.eir));
2332
Andre Guedesf8523592011-09-09 18:56:26 -03002333 if (dev_class)
2334 memcpy(ev.dev_class, dev_class, sizeof(ev.dev_class));
2335
Johan Hedberge17acd42011-03-30 23:57:16 +03002336 return mgmt_event(MGMT_EV_DEVICE_FOUND, index, &ev, sizeof(ev), NULL);
2337}
Johan Hedberga88a9652011-03-30 13:18:12 +03002338
2339int mgmt_remote_name(u16 index, bdaddr_t *bdaddr, u8 *name)
2340{
2341 struct mgmt_ev_remote_name ev;
2342
2343 memset(&ev, 0, sizeof(ev));
2344
2345 bacpy(&ev.bdaddr, bdaddr);
2346 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
2347
2348 return mgmt_event(MGMT_EV_REMOTE_NAME, index, &ev, sizeof(ev), NULL);
2349}
Johan Hedberg314b2382011-04-27 10:29:57 -04002350
2351int mgmt_discovering(u16 index, u8 discovering)
2352{
2353 return mgmt_event(MGMT_EV_DISCOVERING, index, &discovering,
2354 sizeof(discovering), NULL);
2355}
Antti Julku5e762442011-08-25 16:48:02 +03002356
2357int mgmt_device_blocked(u16 index, bdaddr_t *bdaddr)
2358{
2359 struct pending_cmd *cmd;
2360 struct mgmt_ev_device_blocked ev;
2361
2362 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, index);
2363
2364 bacpy(&ev.bdaddr, bdaddr);
2365
2366 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, index, &ev, sizeof(ev),
2367 cmd ? cmd->sk : NULL);
2368}
2369
2370int mgmt_device_unblocked(u16 index, bdaddr_t *bdaddr)
2371{
2372 struct pending_cmd *cmd;
2373 struct mgmt_ev_device_unblocked ev;
2374
2375 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, index);
2376
2377 bacpy(&ev.bdaddr, bdaddr);
2378
2379 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, index, &ev, sizeof(ev),
2380 cmd ? cmd->sk : NULL);
2381}