blob: 747366a1f23c88a2cae002f03bf818ec79754998 [file] [log] [blame]
Johan Hedberg03811012010-12-08 00:21:06 +02001/*
2 BlueZ - Bluetooth protocol stack for Linux
3 Copyright (C) 2010 Nokia Corporation
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License version 2 as
7 published by the Free Software Foundation;
8
9 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
10 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
11 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
12 IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
13 CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
14 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17
18 ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
19 COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
20 SOFTWARE IS DISCLAIMED.
21*/
22
23/* Bluetooth HCI Management interface */
24
Szymon Janc72359752011-02-17 14:16:32 +010025#include <linux/uaccess.h>
Johan Hedberg03811012010-12-08 00:21:06 +020026#include <asm/unaligned.h>
27
28#include <net/bluetooth/bluetooth.h>
29#include <net/bluetooth/hci_core.h>
30#include <net/bluetooth/mgmt.h>
31
Johan Hedberg02d98122010-12-13 21:07:04 +020032#define MGMT_VERSION 0
33#define MGMT_REVISION 1
34
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020035struct pending_cmd {
36 struct list_head list;
37 __u16 opcode;
38 int index;
Szymon Jancc68fb7f2011-03-22 13:12:19 +010039 void *param;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020040 struct sock *sk;
Johan Hedberge9a416b2011-02-19 12:05:56 -030041 void *user_data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020042};
43
Johannes Bergb5ad8b72011-06-01 08:54:45 +020044static LIST_HEAD(cmd_list);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020045
Szymon Janc4e51eae2011-02-25 19:05:48 +010046static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
Johan Hedbergf7b64e62010-12-13 21:07:06 +020047{
48 struct sk_buff *skb;
49 struct mgmt_hdr *hdr;
50 struct mgmt_ev_cmd_status *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -030051 int err;
Johan Hedbergf7b64e62010-12-13 21:07:06 +020052
Szymon Janc34eb5252011-02-28 14:10:08 +010053 BT_DBG("sock %p, index %u, cmd %u, status %u", sk, index, cmd, status);
Johan Hedbergf7b64e62010-12-13 21:07:06 +020054
55 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_ATOMIC);
56 if (!skb)
57 return -ENOMEM;
58
59 hdr = (void *) skb_put(skb, sizeof(*hdr));
60
61 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_STATUS);
Szymon Janc4e51eae2011-02-25 19:05:48 +010062 hdr->index = cpu_to_le16(index);
Johan Hedbergf7b64e62010-12-13 21:07:06 +020063 hdr->len = cpu_to_le16(sizeof(*ev));
64
65 ev = (void *) skb_put(skb, sizeof(*ev));
66 ev->status = status;
67 put_unaligned_le16(cmd, &ev->opcode);
68
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -030069 err = sock_queue_rcv_skb(sk, skb);
70 if (err < 0)
Johan Hedbergf7b64e62010-12-13 21:07:06 +020071 kfree_skb(skb);
72
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -030073 return err;
Johan Hedbergf7b64e62010-12-13 21:07:06 +020074}
75
Szymon Janc4e51eae2011-02-25 19:05:48 +010076static int cmd_complete(struct sock *sk, u16 index, u16 cmd, void *rp,
77 size_t rp_len)
Johan Hedberg02d98122010-12-13 21:07:04 +020078{
79 struct sk_buff *skb;
80 struct mgmt_hdr *hdr;
81 struct mgmt_ev_cmd_complete *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -030082 int err;
Johan Hedberg02d98122010-12-13 21:07:04 +020083
84 BT_DBG("sock %p", sk);
85
Johan Hedberga38528f2011-01-22 06:46:43 +020086 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + rp_len, GFP_ATOMIC);
Johan Hedberg02d98122010-12-13 21:07:04 +020087 if (!skb)
88 return -ENOMEM;
89
90 hdr = (void *) skb_put(skb, sizeof(*hdr));
Johan Hedberga38528f2011-01-22 06:46:43 +020091
Johan Hedberg02d98122010-12-13 21:07:04 +020092 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE);
Szymon Janc4e51eae2011-02-25 19:05:48 +010093 hdr->index = cpu_to_le16(index);
Johan Hedberga38528f2011-01-22 06:46:43 +020094 hdr->len = cpu_to_le16(sizeof(*ev) + rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +020095
Johan Hedberga38528f2011-01-22 06:46:43 +020096 ev = (void *) skb_put(skb, sizeof(*ev) + rp_len);
97 put_unaligned_le16(cmd, &ev->opcode);
Szymon Janc8020c162011-02-28 14:09:50 +010098
99 if (rp)
100 memcpy(ev->data, rp, rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200101
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300102 err = sock_queue_rcv_skb(sk, skb);
103 if (err < 0)
Johan Hedberg02d98122010-12-13 21:07:04 +0200104 kfree_skb(skb);
105
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300106 return err;;
Johan Hedberg02d98122010-12-13 21:07:04 +0200107}
108
Johan Hedberga38528f2011-01-22 06:46:43 +0200109static int read_version(struct sock *sk)
110{
111 struct mgmt_rp_read_version rp;
112
113 BT_DBG("sock %p", sk);
114
115 rp.version = MGMT_VERSION;
116 put_unaligned_le16(MGMT_REVISION, &rp.revision);
117
Szymon Janc4e51eae2011-02-25 19:05:48 +0100118 return cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, &rp,
119 sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200120}
121
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200122static int read_index_list(struct sock *sk)
123{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200124 struct mgmt_rp_read_index_list *rp;
125 struct list_head *p;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200126 struct hci_dev *d;
Johan Hedberga38528f2011-01-22 06:46:43 +0200127 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200128 u16 count;
Johan Hedberga38528f2011-01-22 06:46:43 +0200129 int i, err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200130
131 BT_DBG("sock %p", sk);
132
133 read_lock(&hci_dev_list_lock);
134
135 count = 0;
136 list_for_each(p, &hci_dev_list) {
137 count++;
138 }
139
Johan Hedberga38528f2011-01-22 06:46:43 +0200140 rp_len = sizeof(*rp) + (2 * count);
141 rp = kmalloc(rp_len, GFP_ATOMIC);
142 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100143 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200144 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100145 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200146
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200147 put_unaligned_le16(count, &rp->num_controllers);
148
149 i = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200150 list_for_each_entry(d, &hci_dev_list, list) {
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200151 hci_del_off_timer(d);
152
153 if (test_bit(HCI_SETUP, &d->flags))
154 continue;
155
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200156 put_unaligned_le16(d->id, &rp->index[i++]);
157 BT_DBG("Added hci%u", d->id);
158 }
159
160 read_unlock(&hci_dev_list_lock);
161
Szymon Janc4e51eae2011-02-25 19:05:48 +0100162 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST, rp,
163 rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200164
Johan Hedberga38528f2011-01-22 06:46:43 +0200165 kfree(rp);
166
167 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200168}
169
Szymon Janc4e51eae2011-02-25 19:05:48 +0100170static int read_controller_info(struct sock *sk, u16 index)
Johan Hedberg03811012010-12-08 00:21:06 +0200171{
Johan Hedberga38528f2011-01-22 06:46:43 +0200172 struct mgmt_rp_read_info rp;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200173 struct hci_dev *hdev;
Johan Hedberg03811012010-12-08 00:21:06 +0200174
Szymon Janc4e51eae2011-02-25 19:05:48 +0100175 BT_DBG("sock %p hci%u", sk, index);
Johan Hedberg03811012010-12-08 00:21:06 +0200176
Szymon Janc4e51eae2011-02-25 19:05:48 +0100177 hdev = hci_dev_get(index);
Johan Hedberga38528f2011-01-22 06:46:43 +0200178 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100179 return cmd_status(sk, index, MGMT_OP_READ_INFO, ENODEV);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200180
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200181 hci_del_off_timer(hdev);
182
Andre Guedes8c156c32011-07-07 10:30:36 -0300183 hci_dev_lock_bh(hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200184
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200185 set_bit(HCI_MGMT, &hdev->flags);
186
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200187 memset(&rp, 0, sizeof(rp));
188
Johan Hedberga38528f2011-01-22 06:46:43 +0200189 rp.type = hdev->dev_type;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200190
Johan Hedberga38528f2011-01-22 06:46:43 +0200191 rp.powered = test_bit(HCI_UP, &hdev->flags);
192 rp.connectable = test_bit(HCI_PSCAN, &hdev->flags);
193 rp.discoverable = test_bit(HCI_ISCAN, &hdev->flags);
194 rp.pairable = test_bit(HCI_PSCAN, &hdev->flags);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200195
196 if (test_bit(HCI_AUTH, &hdev->flags))
Johan Hedberga38528f2011-01-22 06:46:43 +0200197 rp.sec_mode = 3;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200198 else if (hdev->ssp_mode > 0)
Johan Hedberga38528f2011-01-22 06:46:43 +0200199 rp.sec_mode = 4;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200200 else
Johan Hedberga38528f2011-01-22 06:46:43 +0200201 rp.sec_mode = 2;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200202
Johan Hedberga38528f2011-01-22 06:46:43 +0200203 bacpy(&rp.bdaddr, &hdev->bdaddr);
204 memcpy(rp.features, hdev->features, 8);
205 memcpy(rp.dev_class, hdev->dev_class, 3);
206 put_unaligned_le16(hdev->manufacturer, &rp.manufacturer);
207 rp.hci_ver = hdev->hci_ver;
208 put_unaligned_le16(hdev->hci_rev, &rp.hci_rev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200209
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200210 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
211
Andre Guedes8c156c32011-07-07 10:30:36 -0300212 hci_dev_unlock_bh(hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200213 hci_dev_put(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200214
Szymon Janc4e51eae2011-02-25 19:05:48 +0100215 return cmd_complete(sk, index, MGMT_OP_READ_INFO, &rp, sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +0200216}
217
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200218static void mgmt_pending_free(struct pending_cmd *cmd)
219{
220 sock_put(cmd->sk);
Szymon Jancc68fb7f2011-03-22 13:12:19 +0100221 kfree(cmd->param);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200222 kfree(cmd);
223}
224
Johan Hedberg366a0332011-02-19 12:05:55 -0300225static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
226 u16 index, void *data, u16 len)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200227{
228 struct pending_cmd *cmd;
229
230 cmd = kmalloc(sizeof(*cmd), GFP_ATOMIC);
231 if (!cmd)
Johan Hedberg366a0332011-02-19 12:05:55 -0300232 return NULL;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200233
234 cmd->opcode = opcode;
235 cmd->index = index;
236
Szymon Jancc68fb7f2011-03-22 13:12:19 +0100237 cmd->param = kmalloc(len, GFP_ATOMIC);
238 if (!cmd->param) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200239 kfree(cmd);
Johan Hedberg366a0332011-02-19 12:05:55 -0300240 return NULL;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200241 }
242
Szymon Janc8fce6352011-03-22 13:12:20 +0100243 if (data)
244 memcpy(cmd->param, data, len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200245
246 cmd->sk = sk;
247 sock_hold(sk);
248
249 list_add(&cmd->list, &cmd_list);
250
Johan Hedberg366a0332011-02-19 12:05:55 -0300251 return cmd;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200252}
253
254static void mgmt_pending_foreach(u16 opcode, int index,
255 void (*cb)(struct pending_cmd *cmd, void *data),
256 void *data)
257{
258 struct list_head *p, *n;
259
260 list_for_each_safe(p, n, &cmd_list) {
261 struct pending_cmd *cmd;
262
263 cmd = list_entry(p, struct pending_cmd, list);
264
Johan Hedbergb24752f2011-11-03 14:40:33 +0200265 if (opcode > 0 && cmd->opcode != opcode)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200266 continue;
267
268 if (index >= 0 && cmd->index != index)
269 continue;
270
271 cb(cmd, data);
272 }
273}
274
275static struct pending_cmd *mgmt_pending_find(u16 opcode, int index)
276{
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200277 struct pending_cmd *cmd;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200278
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200279 list_for_each_entry(cmd, &cmd_list, list) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200280 if (cmd->opcode != opcode)
281 continue;
282
283 if (index >= 0 && cmd->index != index)
284 continue;
285
286 return cmd;
287 }
288
289 return NULL;
290}
291
Johan Hedberga664b5b2011-02-19 12:06:02 -0300292static void mgmt_pending_remove(struct pending_cmd *cmd)
Johan Hedberg73f22f62010-12-29 16:00:25 +0200293{
Johan Hedberg73f22f62010-12-29 16:00:25 +0200294 list_del(&cmd->list);
295 mgmt_pending_free(cmd);
296}
297
Szymon Janc4e51eae2011-02-25 19:05:48 +0100298static int set_powered(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200299{
Johan Hedberg72a734e2010-12-30 00:38:22 +0200300 struct mgmt_mode *cp;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200301 struct hci_dev *hdev;
Johan Hedberg366a0332011-02-19 12:05:55 -0300302 struct pending_cmd *cmd;
Johan Hedberg366a0332011-02-19 12:05:55 -0300303 int err, up;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200304
305 cp = (void *) data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200306
Szymon Janc4e51eae2011-02-25 19:05:48 +0100307 BT_DBG("request for hci%u", index);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200308
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100309 if (len != sizeof(*cp))
310 return cmd_status(sk, index, MGMT_OP_SET_POWERED, EINVAL);
311
Szymon Janc4e51eae2011-02-25 19:05:48 +0100312 hdev = hci_dev_get(index);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200313 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100314 return cmd_status(sk, index, MGMT_OP_SET_POWERED, ENODEV);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200315
Andre Guedes8c156c32011-07-07 10:30:36 -0300316 hci_dev_lock_bh(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200317
318 up = test_bit(HCI_UP, &hdev->flags);
Johan Hedberg72a734e2010-12-30 00:38:22 +0200319 if ((cp->val && up) || (!cp->val && !up)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100320 err = cmd_status(sk, index, MGMT_OP_SET_POWERED, EALREADY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200321 goto failed;
322 }
323
Szymon Janc4e51eae2011-02-25 19:05:48 +0100324 if (mgmt_pending_find(MGMT_OP_SET_POWERED, index)) {
325 err = cmd_status(sk, index, MGMT_OP_SET_POWERED, EBUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200326 goto failed;
327 }
328
Szymon Janc4e51eae2011-02-25 19:05:48 +0100329 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -0300330 if (!cmd) {
331 err = -ENOMEM;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200332 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -0300333 }
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200334
Johan Hedberg72a734e2010-12-30 00:38:22 +0200335 if (cp->val)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200336 queue_work(hdev->workqueue, &hdev->power_on);
337 else
338 queue_work(hdev->workqueue, &hdev->power_off);
339
Johan Hedberg366a0332011-02-19 12:05:55 -0300340 err = 0;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200341
342failed:
Andre Guedes8c156c32011-07-07 10:30:36 -0300343 hci_dev_unlock_bh(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200344 hci_dev_put(hdev);
Johan Hedberg366a0332011-02-19 12:05:55 -0300345 return err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200346}
347
Szymon Janc4e51eae2011-02-25 19:05:48 +0100348static int set_discoverable(struct sock *sk, u16 index, unsigned char *data,
349 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +0200350{
Johan Hedberg72a734e2010-12-30 00:38:22 +0200351 struct mgmt_mode *cp;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200352 struct hci_dev *hdev;
Johan Hedberg366a0332011-02-19 12:05:55 -0300353 struct pending_cmd *cmd;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200354 u8 scan;
355 int err;
356
357 cp = (void *) data;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200358
Szymon Janc4e51eae2011-02-25 19:05:48 +0100359 BT_DBG("request for hci%u", index);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200360
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100361 if (len != sizeof(*cp))
362 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, EINVAL);
363
Szymon Janc4e51eae2011-02-25 19:05:48 +0100364 hdev = hci_dev_get(index);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200365 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100366 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, ENODEV);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200367
Andre Guedes8c156c32011-07-07 10:30:36 -0300368 hci_dev_lock_bh(hdev);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200369
370 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100371 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, ENETDOWN);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200372 goto failed;
373 }
374
Szymon Janc4e51eae2011-02-25 19:05:48 +0100375 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, index) ||
376 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, index)) {
377 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, EBUSY);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200378 goto failed;
379 }
380
Johan Hedberg72a734e2010-12-30 00:38:22 +0200381 if (cp->val == test_bit(HCI_ISCAN, &hdev->flags) &&
Johan Hedberg73f22f62010-12-29 16:00:25 +0200382 test_bit(HCI_PSCAN, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100383 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, EALREADY);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200384 goto failed;
385 }
386
Szymon Janc4e51eae2011-02-25 19:05:48 +0100387 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -0300388 if (!cmd) {
389 err = -ENOMEM;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200390 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -0300391 }
Johan Hedberg73f22f62010-12-29 16:00:25 +0200392
393 scan = SCAN_PAGE;
394
Johan Hedberg72a734e2010-12-30 00:38:22 +0200395 if (cp->val)
Johan Hedberg73f22f62010-12-29 16:00:25 +0200396 scan |= SCAN_INQUIRY;
397
398 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
399 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -0300400 mgmt_pending_remove(cmd);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200401
402failed:
Andre Guedes8c156c32011-07-07 10:30:36 -0300403 hci_dev_unlock_bh(hdev);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200404 hci_dev_put(hdev);
405
406 return err;
407}
408
Szymon Janc4e51eae2011-02-25 19:05:48 +0100409static int set_connectable(struct sock *sk, u16 index, unsigned char *data,
410 u16 len)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200411{
Johan Hedberg72a734e2010-12-30 00:38:22 +0200412 struct mgmt_mode *cp;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200413 struct hci_dev *hdev;
Johan Hedberg366a0332011-02-19 12:05:55 -0300414 struct pending_cmd *cmd;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200415 u8 scan;
416 int err;
417
418 cp = (void *) data;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200419
Szymon Janc4e51eae2011-02-25 19:05:48 +0100420 BT_DBG("request for hci%u", index);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200421
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100422 if (len != sizeof(*cp))
423 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, EINVAL);
424
Szymon Janc4e51eae2011-02-25 19:05:48 +0100425 hdev = hci_dev_get(index);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200426 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100427 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, ENODEV);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200428
Andre Guedes8c156c32011-07-07 10:30:36 -0300429 hci_dev_lock_bh(hdev);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200430
431 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100432 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, ENETDOWN);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200433 goto failed;
434 }
435
Szymon Janc4e51eae2011-02-25 19:05:48 +0100436 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, index) ||
437 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, index)) {
438 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, EBUSY);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200439 goto failed;
440 }
441
Johan Hedberg72a734e2010-12-30 00:38:22 +0200442 if (cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100443 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, EALREADY);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200444 goto failed;
445 }
446
Szymon Janc4e51eae2011-02-25 19:05:48 +0100447 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -0300448 if (!cmd) {
449 err = -ENOMEM;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200450 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -0300451 }
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200452
Johan Hedberg72a734e2010-12-30 00:38:22 +0200453 if (cp->val)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200454 scan = SCAN_PAGE;
455 else
456 scan = 0;
457
458 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
459 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -0300460 mgmt_pending_remove(cmd);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200461
462failed:
Andre Guedes8c156c32011-07-07 10:30:36 -0300463 hci_dev_unlock_bh(hdev);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200464 hci_dev_put(hdev);
465
466 return err;
467}
468
Szymon Janc4e51eae2011-02-25 19:05:48 +0100469static int mgmt_event(u16 event, u16 index, void *data, u16 data_len,
470 struct sock *skip_sk)
Johan Hedbergc542a062011-01-26 13:11:03 +0200471{
472 struct sk_buff *skb;
473 struct mgmt_hdr *hdr;
474
475 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_ATOMIC);
476 if (!skb)
477 return -ENOMEM;
478
479 bt_cb(skb)->channel = HCI_CHANNEL_CONTROL;
480
481 hdr = (void *) skb_put(skb, sizeof(*hdr));
482 hdr->opcode = cpu_to_le16(event);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100483 hdr->index = cpu_to_le16(index);
Johan Hedbergc542a062011-01-26 13:11:03 +0200484 hdr->len = cpu_to_le16(data_len);
485
Szymon Janc4e51eae2011-02-25 19:05:48 +0100486 if (data)
487 memcpy(skb_put(skb, data_len), data, data_len);
Johan Hedbergc542a062011-01-26 13:11:03 +0200488
489 hci_send_to_sock(NULL, skb, skip_sk);
490 kfree_skb(skb);
491
492 return 0;
493}
494
Johan Hedberg053f0212011-01-26 13:07:10 +0200495static int send_mode_rsp(struct sock *sk, u16 opcode, u16 index, u8 val)
496{
Johan Hedberga38528f2011-01-22 06:46:43 +0200497 struct mgmt_mode rp;
Johan Hedberg053f0212011-01-26 13:07:10 +0200498
Johan Hedberga38528f2011-01-22 06:46:43 +0200499 rp.val = val;
Johan Hedberg053f0212011-01-26 13:07:10 +0200500
Szymon Janc4e51eae2011-02-25 19:05:48 +0100501 return cmd_complete(sk, index, opcode, &rp, sizeof(rp));
Johan Hedberg053f0212011-01-26 13:07:10 +0200502}
503
Szymon Janc4e51eae2011-02-25 19:05:48 +0100504static int set_pairable(struct sock *sk, u16 index, unsigned char *data,
505 u16 len)
Johan Hedbergc542a062011-01-26 13:11:03 +0200506{
507 struct mgmt_mode *cp, ev;
508 struct hci_dev *hdev;
Johan Hedbergc542a062011-01-26 13:11:03 +0200509 int err;
510
511 cp = (void *) data;
Johan Hedbergc542a062011-01-26 13:11:03 +0200512
Szymon Janc4e51eae2011-02-25 19:05:48 +0100513 BT_DBG("request for hci%u", index);
Johan Hedbergc542a062011-01-26 13:11:03 +0200514
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100515 if (len != sizeof(*cp))
516 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE, EINVAL);
517
Szymon Janc4e51eae2011-02-25 19:05:48 +0100518 hdev = hci_dev_get(index);
Johan Hedbergc542a062011-01-26 13:11:03 +0200519 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100520 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE, ENODEV);
Johan Hedbergc542a062011-01-26 13:11:03 +0200521
Andre Guedes8c156c32011-07-07 10:30:36 -0300522 hci_dev_lock_bh(hdev);
Johan Hedbergc542a062011-01-26 13:11:03 +0200523
524 if (cp->val)
525 set_bit(HCI_PAIRABLE, &hdev->flags);
526 else
527 clear_bit(HCI_PAIRABLE, &hdev->flags);
528
Szymon Janc4e51eae2011-02-25 19:05:48 +0100529 err = send_mode_rsp(sk, MGMT_OP_SET_PAIRABLE, index, cp->val);
Johan Hedbergc542a062011-01-26 13:11:03 +0200530 if (err < 0)
531 goto failed;
532
Johan Hedbergc542a062011-01-26 13:11:03 +0200533 ev.val = cp->val;
534
Szymon Janc4e51eae2011-02-25 19:05:48 +0100535 err = mgmt_event(MGMT_EV_PAIRABLE, index, &ev, sizeof(ev), sk);
Johan Hedbergc542a062011-01-26 13:11:03 +0200536
537failed:
Andre Guedes8c156c32011-07-07 10:30:36 -0300538 hci_dev_unlock_bh(hdev);
Johan Hedbergc542a062011-01-26 13:11:03 +0200539 hci_dev_put(hdev);
540
541 return err;
542}
543
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300544#define EIR_FLAGS 0x01 /* flags */
545#define EIR_UUID16_SOME 0x02 /* 16-bit UUID, more available */
546#define EIR_UUID16_ALL 0x03 /* 16-bit UUID, all listed */
547#define EIR_UUID32_SOME 0x04 /* 32-bit UUID, more available */
548#define EIR_UUID32_ALL 0x05 /* 32-bit UUID, all listed */
549#define EIR_UUID128_SOME 0x06 /* 128-bit UUID, more available */
550#define EIR_UUID128_ALL 0x07 /* 128-bit UUID, all listed */
551#define EIR_NAME_SHORT 0x08 /* shortened local name */
552#define EIR_NAME_COMPLETE 0x09 /* complete local name */
553#define EIR_TX_POWER 0x0A /* transmit power level */
554#define EIR_DEVICE_ID 0x10 /* device ID */
555
556#define PNP_INFO_SVCLASS_ID 0x1200
557
558static u8 bluetooth_base_uuid[] = {
559 0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80,
560 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
561};
562
563static u16 get_uuid16(u8 *uuid128)
564{
565 u32 val;
566 int i;
567
568 for (i = 0; i < 12; i++) {
569 if (bluetooth_base_uuid[i] != uuid128[i])
570 return 0;
571 }
572
573 memcpy(&val, &uuid128[12], 4);
574
575 val = le32_to_cpu(val);
576 if (val > 0xffff)
577 return 0;
578
579 return (u16) val;
580}
581
582static void create_eir(struct hci_dev *hdev, u8 *data)
583{
584 u8 *ptr = data;
585 u16 eir_len = 0;
586 u16 uuid16_list[HCI_MAX_EIR_LENGTH / sizeof(u16)];
587 int i, truncated = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200588 struct bt_uuid *uuid;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300589 size_t name_len;
590
591 name_len = strlen(hdev->dev_name);
592
593 if (name_len > 0) {
594 /* EIR Data type */
595 if (name_len > 48) {
596 name_len = 48;
597 ptr[1] = EIR_NAME_SHORT;
598 } else
599 ptr[1] = EIR_NAME_COMPLETE;
600
601 /* EIR Data length */
602 ptr[0] = name_len + 1;
603
604 memcpy(ptr + 2, hdev->dev_name, name_len);
605
606 eir_len += (name_len + 2);
607 ptr += (name_len + 2);
608 }
609
610 memset(uuid16_list, 0, sizeof(uuid16_list));
611
612 /* Group all UUID16 types */
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200613 list_for_each_entry(uuid, &hdev->uuids, list) {
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300614 u16 uuid16;
615
616 uuid16 = get_uuid16(uuid->uuid);
617 if (uuid16 == 0)
618 return;
619
620 if (uuid16 < 0x1100)
621 continue;
622
623 if (uuid16 == PNP_INFO_SVCLASS_ID)
624 continue;
625
626 /* Stop if not enough space to put next UUID */
627 if (eir_len + 2 + sizeof(u16) > HCI_MAX_EIR_LENGTH) {
628 truncated = 1;
629 break;
630 }
631
632 /* Check for duplicates */
633 for (i = 0; uuid16_list[i] != 0; i++)
634 if (uuid16_list[i] == uuid16)
635 break;
636
637 if (uuid16_list[i] == 0) {
638 uuid16_list[i] = uuid16;
639 eir_len += sizeof(u16);
640 }
641 }
642
643 if (uuid16_list[0] != 0) {
644 u8 *length = ptr;
645
646 /* EIR Data type */
647 ptr[1] = truncated ? EIR_UUID16_SOME : EIR_UUID16_ALL;
648
649 ptr += 2;
650 eir_len += 2;
651
652 for (i = 0; uuid16_list[i] != 0; i++) {
653 *ptr++ = (uuid16_list[i] & 0x00ff);
654 *ptr++ = (uuid16_list[i] & 0xff00) >> 8;
655 }
656
657 /* EIR Data length */
658 *length = (i * sizeof(u16)) + 1;
659 }
660}
661
662static int update_eir(struct hci_dev *hdev)
663{
664 struct hci_cp_write_eir cp;
665
666 if (!(hdev->features[6] & LMP_EXT_INQ))
667 return 0;
668
669 if (hdev->ssp_mode == 0)
670 return 0;
671
672 if (test_bit(HCI_SERVICE_CACHE, &hdev->flags))
673 return 0;
674
675 memset(&cp, 0, sizeof(cp));
676
677 create_eir(hdev, cp.data);
678
679 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
680 return 0;
681
682 memcpy(hdev->eir, cp.data, sizeof(cp.data));
683
684 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
685}
686
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200687static u8 get_service_classes(struct hci_dev *hdev)
688{
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300689 struct bt_uuid *uuid;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200690 u8 val = 0;
691
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300692 list_for_each_entry(uuid, &hdev->uuids, list)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200693 val |= uuid->svc_hint;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200694
695 return val;
696}
697
698static int update_class(struct hci_dev *hdev)
699{
700 u8 cod[3];
701
702 BT_DBG("%s", hdev->name);
703
704 if (test_bit(HCI_SERVICE_CACHE, &hdev->flags))
705 return 0;
706
707 cod[0] = hdev->minor_class;
708 cod[1] = hdev->major_class;
709 cod[2] = get_service_classes(hdev);
710
711 if (memcmp(cod, hdev->dev_class, 3) == 0)
712 return 0;
713
714 return hci_send_cmd(hdev, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
715}
716
Szymon Janc4e51eae2011-02-25 19:05:48 +0100717static int add_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200718{
719 struct mgmt_cp_add_uuid *cp;
720 struct hci_dev *hdev;
721 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200722 int err;
723
724 cp = (void *) data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200725
Szymon Janc4e51eae2011-02-25 19:05:48 +0100726 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200727
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100728 if (len != sizeof(*cp))
729 return cmd_status(sk, index, MGMT_OP_ADD_UUID, EINVAL);
730
Szymon Janc4e51eae2011-02-25 19:05:48 +0100731 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200732 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100733 return cmd_status(sk, index, MGMT_OP_ADD_UUID, ENODEV);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200734
Andre Guedes8c156c32011-07-07 10:30:36 -0300735 hci_dev_lock_bh(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200736
737 uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC);
738 if (!uuid) {
739 err = -ENOMEM;
740 goto failed;
741 }
742
743 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200744 uuid->svc_hint = cp->svc_hint;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200745
746 list_add(&uuid->list, &hdev->uuids);
747
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200748 err = update_class(hdev);
749 if (err < 0)
750 goto failed;
751
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300752 err = update_eir(hdev);
753 if (err < 0)
754 goto failed;
755
Szymon Janc4e51eae2011-02-25 19:05:48 +0100756 err = cmd_complete(sk, index, MGMT_OP_ADD_UUID, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200757
758failed:
Andre Guedes8c156c32011-07-07 10:30:36 -0300759 hci_dev_unlock_bh(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200760 hci_dev_put(hdev);
761
762 return err;
763}
764
Szymon Janc4e51eae2011-02-25 19:05:48 +0100765static int remove_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200766{
767 struct list_head *p, *n;
Szymon Janc779cb852011-02-25 19:05:47 +0100768 struct mgmt_cp_remove_uuid *cp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200769 struct hci_dev *hdev;
770 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 +0200771 int err, found;
772
773 cp = (void *) data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200774
Szymon Janc4e51eae2011-02-25 19:05:48 +0100775 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200776
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100777 if (len != sizeof(*cp))
778 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID, EINVAL);
779
Szymon Janc4e51eae2011-02-25 19:05:48 +0100780 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200781 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100782 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID, ENODEV);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200783
Andre Guedes8c156c32011-07-07 10:30:36 -0300784 hci_dev_lock_bh(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200785
786 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
787 err = hci_uuids_clear(hdev);
788 goto unlock;
789 }
790
791 found = 0;
792
793 list_for_each_safe(p, n, &hdev->uuids) {
794 struct bt_uuid *match = list_entry(p, struct bt_uuid, list);
795
796 if (memcmp(match->uuid, cp->uuid, 16) != 0)
797 continue;
798
799 list_del(&match->list);
800 found++;
801 }
802
803 if (found == 0) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100804 err = cmd_status(sk, index, MGMT_OP_REMOVE_UUID, ENOENT);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200805 goto unlock;
806 }
807
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200808 err = update_class(hdev);
809 if (err < 0)
810 goto unlock;
811
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300812 err = update_eir(hdev);
813 if (err < 0)
814 goto unlock;
815
Szymon Janc4e51eae2011-02-25 19:05:48 +0100816 err = cmd_complete(sk, index, MGMT_OP_REMOVE_UUID, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200817
818unlock:
Andre Guedes8c156c32011-07-07 10:30:36 -0300819 hci_dev_unlock_bh(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200820 hci_dev_put(hdev);
821
822 return err;
823}
824
Szymon Janc4e51eae2011-02-25 19:05:48 +0100825static int set_dev_class(struct sock *sk, u16 index, unsigned char *data,
826 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200827{
828 struct hci_dev *hdev;
829 struct mgmt_cp_set_dev_class *cp;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200830 int err;
831
832 cp = (void *) data;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200833
Szymon Janc4e51eae2011-02-25 19:05:48 +0100834 BT_DBG("request for hci%u", index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200835
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100836 if (len != sizeof(*cp))
837 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS, EINVAL);
838
Szymon Janc4e51eae2011-02-25 19:05:48 +0100839 hdev = hci_dev_get(index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200840 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100841 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS, ENODEV);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200842
Andre Guedes8c156c32011-07-07 10:30:36 -0300843 hci_dev_lock_bh(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200844
845 hdev->major_class = cp->major;
846 hdev->minor_class = cp->minor;
847
848 err = update_class(hdev);
849
850 if (err == 0)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100851 err = cmd_complete(sk, index, MGMT_OP_SET_DEV_CLASS, NULL, 0);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200852
Andre Guedes8c156c32011-07-07 10:30:36 -0300853 hci_dev_unlock_bh(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200854 hci_dev_put(hdev);
855
856 return err;
857}
858
Szymon Janc4e51eae2011-02-25 19:05:48 +0100859static int set_service_cache(struct sock *sk, u16 index, unsigned char *data,
860 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200861{
862 struct hci_dev *hdev;
863 struct mgmt_cp_set_service_cache *cp;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200864 int err;
865
866 cp = (void *) data;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200867
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100868 if (len != sizeof(*cp))
Szymon Jancb8534e02011-03-01 16:55:34 +0100869 return cmd_status(sk, index, MGMT_OP_SET_SERVICE_CACHE, EINVAL);
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100870
Szymon Janc4e51eae2011-02-25 19:05:48 +0100871 hdev = hci_dev_get(index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200872 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100873 return cmd_status(sk, index, MGMT_OP_SET_SERVICE_CACHE, ENODEV);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200874
Andre Guedes8c156c32011-07-07 10:30:36 -0300875 hci_dev_lock_bh(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200876
Szymon Janc4e51eae2011-02-25 19:05:48 +0100877 BT_DBG("hci%u enable %d", index, cp->enable);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200878
879 if (cp->enable) {
880 set_bit(HCI_SERVICE_CACHE, &hdev->flags);
881 err = 0;
882 } else {
883 clear_bit(HCI_SERVICE_CACHE, &hdev->flags);
884 err = update_class(hdev);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300885 if (err == 0)
886 err = update_eir(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200887 }
888
889 if (err == 0)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100890 err = cmd_complete(sk, index, MGMT_OP_SET_SERVICE_CACHE, NULL,
891 0);
Gustavo F. Padovane5b82e52011-10-15 18:03:15 -0300892 else
893 cmd_status(sk, index, MGMT_OP_SET_SERVICE_CACHE, -err);
894
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200895
Andre Guedes8c156c32011-07-07 10:30:36 -0300896 hci_dev_unlock_bh(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200897 hci_dev_put(hdev);
898
899 return err;
900}
901
Szymon Janc4e51eae2011-02-25 19:05:48 +0100902static int load_keys(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200903{
904 struct hci_dev *hdev;
905 struct mgmt_cp_load_keys *cp;
Szymon Janc4e51eae2011-02-25 19:05:48 +0100906 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -0300907 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200908
909 cp = (void *) data;
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100910
911 if (len < sizeof(*cp))
Gustavo F. Padovanb7059132011-10-14 19:23:27 -0300912 return cmd_status(sk, index, MGMT_OP_LOAD_KEYS, EINVAL);
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100913
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200914 key_count = get_unaligned_le16(&cp->key_count);
915
916 expected_len = sizeof(*cp) + key_count * sizeof(struct mgmt_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -0300917 if (expected_len != len) {
918 BT_ERR("load_keys: expected %u bytes, got %u bytes",
919 len, expected_len);
Gustavo F. Padovanb7059132011-10-14 19:23:27 -0300920 return cmd_status(sk, index, MGMT_OP_LOAD_KEYS, EINVAL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200921 }
922
Szymon Janc4e51eae2011-02-25 19:05:48 +0100923 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200924 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100925 return cmd_status(sk, index, MGMT_OP_LOAD_KEYS, ENODEV);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200926
Szymon Janc4e51eae2011-02-25 19:05:48 +0100927 BT_DBG("hci%u debug_keys %u key_count %u", index, cp->debug_keys,
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200928 key_count);
929
Andre Guedes8c156c32011-07-07 10:30:36 -0300930 hci_dev_lock_bh(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200931
932 hci_link_keys_clear(hdev);
933
934 set_bit(HCI_LINK_KEYS, &hdev->flags);
935
936 if (cp->debug_keys)
937 set_bit(HCI_DEBUG_KEYS, &hdev->flags);
938 else
939 clear_bit(HCI_DEBUG_KEYS, &hdev->flags);
940
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -0300941 for (i = 0; i < key_count; i++) {
942 struct mgmt_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200943
Johan Hedbergd25e28a2011-04-28 11:28:59 -0700944 hci_add_link_key(hdev, NULL, 0, &key->bdaddr, key->val, key->type,
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200945 key->pin_len);
946 }
947
Andre Guedes8c156c32011-07-07 10:30:36 -0300948 hci_dev_unlock_bh(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200949 hci_dev_put(hdev);
950
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -0300951 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200952}
953
Szymon Janc4e51eae2011-02-25 19:05:48 +0100954static int remove_key(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200955{
956 struct hci_dev *hdev;
957 struct mgmt_cp_remove_key *cp;
958 struct hci_conn *conn;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200959 int err;
960
961 cp = (void *) data;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200962
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100963 if (len != sizeof(*cp))
964 return cmd_status(sk, index, MGMT_OP_REMOVE_KEY, EINVAL);
965
Szymon Janc4e51eae2011-02-25 19:05:48 +0100966 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200967 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100968 return cmd_status(sk, index, MGMT_OP_REMOVE_KEY, ENODEV);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200969
Andre Guedes8c156c32011-07-07 10:30:36 -0300970 hci_dev_lock_bh(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200971
972 err = hci_remove_link_key(hdev, &cp->bdaddr);
973 if (err < 0) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100974 err = cmd_status(sk, index, MGMT_OP_REMOVE_KEY, -err);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200975 goto unlock;
976 }
977
978 err = 0;
979
980 if (!test_bit(HCI_UP, &hdev->flags) || !cp->disconnect)
981 goto unlock;
982
983 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
984 if (conn) {
985 struct hci_cp_disconnect dc;
986
987 put_unaligned_le16(conn->handle, &dc.handle);
988 dc.reason = 0x13; /* Remote User Terminated Connection */
Anderson Lizardo94ac0272011-06-13 15:42:03 -0400989 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200990 }
991
992unlock:
Andre Guedes8c156c32011-07-07 10:30:36 -0300993 hci_dev_unlock_bh(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200994 hci_dev_put(hdev);
995
996 return err;
997}
998
Szymon Janc4e51eae2011-02-25 19:05:48 +0100999static int disconnect(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02001000{
1001 struct hci_dev *hdev;
1002 struct mgmt_cp_disconnect *cp;
1003 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03001004 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001005 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001006 int err;
1007
1008 BT_DBG("");
1009
1010 cp = (void *) data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001011
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001012 if (len != sizeof(*cp))
1013 return cmd_status(sk, index, MGMT_OP_DISCONNECT, EINVAL);
1014
Szymon Janc4e51eae2011-02-25 19:05:48 +01001015 hdev = hci_dev_get(index);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001016 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001017 return cmd_status(sk, index, MGMT_OP_DISCONNECT, ENODEV);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001018
Andre Guedes8c156c32011-07-07 10:30:36 -03001019 hci_dev_lock_bh(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001020
1021 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001022 err = cmd_status(sk, index, MGMT_OP_DISCONNECT, ENETDOWN);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001023 goto failed;
1024 }
1025
Szymon Janc4e51eae2011-02-25 19:05:48 +01001026 if (mgmt_pending_find(MGMT_OP_DISCONNECT, index)) {
1027 err = cmd_status(sk, index, MGMT_OP_DISCONNECT, EBUSY);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001028 goto failed;
1029 }
1030
1031 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03001032 if (!conn)
1033 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->bdaddr);
1034
Johan Hedberg8962ee72011-01-20 12:40:27 +02001035 if (!conn) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001036 err = cmd_status(sk, index, MGMT_OP_DISCONNECT, ENOTCONN);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001037 goto failed;
1038 }
1039
Szymon Janc4e51eae2011-02-25 19:05:48 +01001040 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001041 if (!cmd) {
1042 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001043 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001044 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001045
1046 put_unaligned_le16(conn->handle, &dc.handle);
1047 dc.reason = 0x13; /* Remote User Terminated Connection */
1048
1049 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1050 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001051 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001052
1053failed:
Andre Guedes8c156c32011-07-07 10:30:36 -03001054 hci_dev_unlock_bh(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001055 hci_dev_put(hdev);
1056
1057 return err;
1058}
1059
Szymon Janc8ce62842011-03-01 16:55:32 +01001060static int get_connections(struct sock *sk, u16 index)
Johan Hedberg2784eb42011-01-21 13:56:35 +02001061{
Johan Hedberg2784eb42011-01-21 13:56:35 +02001062 struct mgmt_rp_get_connections *rp;
1063 struct hci_dev *hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001064 struct hci_conn *c;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001065 struct list_head *p;
Johan Hedberga38528f2011-01-22 06:46:43 +02001066 size_t rp_len;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001067 u16 count;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001068 int i, err;
1069
1070 BT_DBG("");
1071
Szymon Janc4e51eae2011-02-25 19:05:48 +01001072 hdev = hci_dev_get(index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001073 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001074 return cmd_status(sk, index, MGMT_OP_GET_CONNECTIONS, ENODEV);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001075
Andre Guedes8c156c32011-07-07 10:30:36 -03001076 hci_dev_lock_bh(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001077
1078 count = 0;
1079 list_for_each(p, &hdev->conn_hash.list) {
1080 count++;
1081 }
1082
Johan Hedberga38528f2011-01-22 06:46:43 +02001083 rp_len = sizeof(*rp) + (count * sizeof(bdaddr_t));
1084 rp = kmalloc(rp_len, GFP_ATOMIC);
1085 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02001086 err = -ENOMEM;
1087 goto unlock;
1088 }
1089
Johan Hedberg2784eb42011-01-21 13:56:35 +02001090 put_unaligned_le16(count, &rp->conn_count);
1091
Johan Hedberg2784eb42011-01-21 13:56:35 +02001092 i = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001093 list_for_each_entry(c, &hdev->conn_hash.list, list)
Johan Hedberg2784eb42011-01-21 13:56:35 +02001094 bacpy(&rp->conn[i++], &c->dst);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001095
Szymon Janc4e51eae2011-02-25 19:05:48 +01001096 err = cmd_complete(sk, index, MGMT_OP_GET_CONNECTIONS, rp, rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001097
1098unlock:
Johan Hedberga38528f2011-01-22 06:46:43 +02001099 kfree(rp);
Andre Guedes8c156c32011-07-07 10:30:36 -03001100 hci_dev_unlock_bh(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001101 hci_dev_put(hdev);
1102 return err;
1103}
1104
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001105static int send_pin_code_neg_reply(struct sock *sk, u16 index,
1106 struct hci_dev *hdev, struct mgmt_cp_pin_code_neg_reply *cp)
1107{
1108 struct pending_cmd *cmd;
1109 int err;
1110
1111 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, index, cp,
1112 sizeof(*cp));
1113 if (!cmd)
1114 return -ENOMEM;
1115
1116 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY, sizeof(cp->bdaddr),
1117 &cp->bdaddr);
1118 if (err < 0)
1119 mgmt_pending_remove(cmd);
1120
1121 return err;
1122}
1123
Szymon Janc4e51eae2011-02-25 19:05:48 +01001124static int pin_code_reply(struct sock *sk, u16 index, unsigned char *data,
1125 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001126{
1127 struct hci_dev *hdev;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001128 struct hci_conn *conn;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001129 struct mgmt_cp_pin_code_reply *cp;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001130 struct mgmt_cp_pin_code_neg_reply ncp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001131 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03001132 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001133 int err;
1134
1135 BT_DBG("");
1136
1137 cp = (void *) data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001138
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001139 if (len != sizeof(*cp))
1140 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, EINVAL);
1141
Szymon Janc4e51eae2011-02-25 19:05:48 +01001142 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001143 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001144 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENODEV);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001145
Andre Guedes8c156c32011-07-07 10:30:36 -03001146 hci_dev_lock_bh(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001147
1148 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001149 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENETDOWN);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001150 goto failed;
1151 }
1152
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001153 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
1154 if (!conn) {
1155 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENOTCONN);
1156 goto failed;
1157 }
1158
1159 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
1160 bacpy(&ncp.bdaddr, &cp->bdaddr);
1161
1162 BT_ERR("PIN code is not 16 bytes long");
1163
1164 err = send_pin_code_neg_reply(sk, index, hdev, &ncp);
1165 if (err >= 0)
1166 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1167 EINVAL);
1168
1169 goto failed;
1170 }
1171
Szymon Janc4e51eae2011-02-25 19:05:48 +01001172 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, index, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001173 if (!cmd) {
1174 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001175 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001176 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02001177
1178 bacpy(&reply.bdaddr, &cp->bdaddr);
1179 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02001180 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02001181
1182 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
1183 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001184 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001185
1186failed:
Andre Guedes8c156c32011-07-07 10:30:36 -03001187 hci_dev_unlock_bh(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001188 hci_dev_put(hdev);
1189
1190 return err;
1191}
1192
Szymon Janc4e51eae2011-02-25 19:05:48 +01001193static int pin_code_neg_reply(struct sock *sk, u16 index, unsigned char *data,
1194 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001195{
1196 struct hci_dev *hdev;
1197 struct mgmt_cp_pin_code_neg_reply *cp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001198 int err;
1199
1200 BT_DBG("");
1201
1202 cp = (void *) data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001203
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001204 if (len != sizeof(*cp))
1205 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1206 EINVAL);
1207
Szymon Janc4e51eae2011-02-25 19:05:48 +01001208 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001209 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001210 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1211 ENODEV);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001212
Andre Guedes8c156c32011-07-07 10:30:36 -03001213 hci_dev_lock_bh(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001214
1215 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001216 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1217 ENETDOWN);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001218 goto failed;
1219 }
1220
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001221 err = send_pin_code_neg_reply(sk, index, hdev, cp);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001222
1223failed:
Andre Guedes8c156c32011-07-07 10:30:36 -03001224 hci_dev_unlock_bh(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001225 hci_dev_put(hdev);
1226
1227 return err;
1228}
1229
Szymon Janc4e51eae2011-02-25 19:05:48 +01001230static int set_io_capability(struct sock *sk, u16 index, unsigned char *data,
1231 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001232{
1233 struct hci_dev *hdev;
1234 struct mgmt_cp_set_io_capability *cp;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001235
1236 BT_DBG("");
1237
1238 cp = (void *) data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001239
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001240 if (len != sizeof(*cp))
Szymon Jancb8534e02011-03-01 16:55:34 +01001241 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY, EINVAL);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001242
Szymon Janc4e51eae2011-02-25 19:05:48 +01001243 hdev = hci_dev_get(index);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001244 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001245 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY, ENODEV);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001246
Andre Guedes8c156c32011-07-07 10:30:36 -03001247 hci_dev_lock_bh(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001248
1249 hdev->io_capability = cp->io_capability;
1250
1251 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Szymon Jancb8534e02011-03-01 16:55:34 +01001252 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001253
Andre Guedes8c156c32011-07-07 10:30:36 -03001254 hci_dev_unlock_bh(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001255 hci_dev_put(hdev);
1256
Szymon Janc4e51eae2011-02-25 19:05:48 +01001257 return cmd_complete(sk, index, MGMT_OP_SET_IO_CAPABILITY, NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001258}
1259
Johan Hedberge9a416b2011-02-19 12:05:56 -03001260static inline struct pending_cmd *find_pairing(struct hci_conn *conn)
1261{
1262 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001263 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001264
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001265 list_for_each_entry(cmd, &cmd_list, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03001266 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
1267 continue;
1268
1269 if (cmd->index != hdev->id)
1270 continue;
1271
1272 if (cmd->user_data != conn)
1273 continue;
1274
1275 return cmd;
1276 }
1277
1278 return NULL;
1279}
1280
1281static void pairing_complete(struct pending_cmd *cmd, u8 status)
1282{
1283 struct mgmt_rp_pair_device rp;
1284 struct hci_conn *conn = cmd->user_data;
1285
Johan Hedberge9a416b2011-02-19 12:05:56 -03001286 bacpy(&rp.bdaddr, &conn->dst);
1287 rp.status = status;
1288
Szymon Janc4e51eae2011-02-25 19:05:48 +01001289 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001290
1291 /* So we don't get further callbacks for this connection */
1292 conn->connect_cfm_cb = NULL;
1293 conn->security_cfm_cb = NULL;
1294 conn->disconn_cfm_cb = NULL;
1295
1296 hci_conn_put(conn);
1297
Johan Hedberga664b5b2011-02-19 12:06:02 -03001298 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001299}
1300
1301static void pairing_complete_cb(struct hci_conn *conn, u8 status)
1302{
1303 struct pending_cmd *cmd;
1304
1305 BT_DBG("status %u", status);
1306
1307 cmd = find_pairing(conn);
1308 if (!cmd) {
1309 BT_DBG("Unable to find a pending command");
1310 return;
1311 }
1312
1313 pairing_complete(cmd, status);
1314}
1315
Szymon Janc4e51eae2011-02-25 19:05:48 +01001316static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001317{
1318 struct hci_dev *hdev;
1319 struct mgmt_cp_pair_device *cp;
1320 struct pending_cmd *cmd;
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001321 struct adv_entry *entry;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001322 u8 sec_level, auth_type;
1323 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001324 int err;
1325
1326 BT_DBG("");
1327
1328 cp = (void *) data;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001329
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001330 if (len != sizeof(*cp))
1331 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, EINVAL);
1332
Szymon Janc4e51eae2011-02-25 19:05:48 +01001333 hdev = hci_dev_get(index);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001334 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001335 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, ENODEV);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001336
Andre Guedes8c156c32011-07-07 10:30:36 -03001337 hci_dev_lock_bh(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001338
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001339 sec_level = BT_SECURITY_MEDIUM;
1340 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001341 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001342 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03001343 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001344
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001345 entry = hci_find_adv_entry(hdev, &cp->bdaddr);
1346 if (entry)
1347 conn = hci_connect(hdev, LE_LINK, &cp->bdaddr, sec_level,
1348 auth_type);
1349 else
1350 conn = hci_connect(hdev, ACL_LINK, &cp->bdaddr, sec_level,
1351 auth_type);
1352
Ville Tervo30e76272011-02-22 16:10:53 -03001353 if (IS_ERR(conn)) {
1354 err = PTR_ERR(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001355 goto unlock;
1356 }
1357
1358 if (conn->connect_cfm_cb) {
1359 hci_conn_put(conn);
Szymon Janc4e51eae2011-02-25 19:05:48 +01001360 err = cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, EBUSY);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001361 goto unlock;
1362 }
1363
Szymon Janc4e51eae2011-02-25 19:05:48 +01001364 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, index, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001365 if (!cmd) {
1366 err = -ENOMEM;
1367 hci_conn_put(conn);
1368 goto unlock;
1369 }
1370
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001371 /* For LE, just connecting isn't a proof that the pairing finished */
1372 if (!entry)
1373 conn->connect_cfm_cb = pairing_complete_cb;
1374
Johan Hedberge9a416b2011-02-19 12:05:56 -03001375 conn->security_cfm_cb = pairing_complete_cb;
1376 conn->disconn_cfm_cb = pairing_complete_cb;
1377 conn->io_capability = cp->io_cap;
1378 cmd->user_data = conn;
1379
1380 if (conn->state == BT_CONNECTED &&
1381 hci_conn_security(conn, sec_level, auth_type))
1382 pairing_complete(cmd, 0);
1383
1384 err = 0;
1385
1386unlock:
Andre Guedes8c156c32011-07-07 10:30:36 -03001387 hci_dev_unlock_bh(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001388 hci_dev_put(hdev);
1389
1390 return err;
1391}
1392
Szymon Janc4e51eae2011-02-25 19:05:48 +01001393static int user_confirm_reply(struct sock *sk, u16 index, unsigned char *data,
1394 u16 len, int success)
Johan Hedberga5c29682011-02-19 12:05:57 -03001395{
1396 struct mgmt_cp_user_confirm_reply *cp = (void *) data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001397 u16 mgmt_op, hci_op;
Johan Hedberga5c29682011-02-19 12:05:57 -03001398 struct pending_cmd *cmd;
1399 struct hci_dev *hdev;
1400 int err;
1401
1402 BT_DBG("");
1403
Johan Hedberga5c29682011-02-19 12:05:57 -03001404 if (success) {
1405 mgmt_op = MGMT_OP_USER_CONFIRM_REPLY;
1406 hci_op = HCI_OP_USER_CONFIRM_REPLY;
1407 } else {
1408 mgmt_op = MGMT_OP_USER_CONFIRM_NEG_REPLY;
1409 hci_op = HCI_OP_USER_CONFIRM_NEG_REPLY;
1410 }
1411
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001412 if (len != sizeof(*cp))
1413 return cmd_status(sk, index, mgmt_op, EINVAL);
1414
Szymon Janc4e51eae2011-02-25 19:05:48 +01001415 hdev = hci_dev_get(index);
Johan Hedberga5c29682011-02-19 12:05:57 -03001416 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001417 return cmd_status(sk, index, mgmt_op, ENODEV);
Johan Hedberga5c29682011-02-19 12:05:57 -03001418
Andre Guedes8c156c32011-07-07 10:30:36 -03001419 hci_dev_lock_bh(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02001420
Johan Hedberga5c29682011-02-19 12:05:57 -03001421 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001422 err = cmd_status(sk, index, mgmt_op, ENETDOWN);
Johan Hedberga5c29682011-02-19 12:05:57 -03001423 goto failed;
1424 }
1425
Szymon Janc4e51eae2011-02-25 19:05:48 +01001426 cmd = mgmt_pending_add(sk, mgmt_op, index, data, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03001427 if (!cmd) {
1428 err = -ENOMEM;
1429 goto failed;
1430 }
1431
1432 err = hci_send_cmd(hdev, hci_op, sizeof(cp->bdaddr), &cp->bdaddr);
Johan Hedberga664b5b2011-02-19 12:06:02 -03001433 if (err < 0)
1434 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03001435
1436failed:
Andre Guedes8c156c32011-07-07 10:30:36 -03001437 hci_dev_unlock_bh(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03001438 hci_dev_put(hdev);
1439
1440 return err;
1441}
1442
Johan Hedbergb312b1612011-03-16 14:29:37 +02001443static int set_local_name(struct sock *sk, u16 index, unsigned char *data,
1444 u16 len)
1445{
1446 struct mgmt_cp_set_local_name *mgmt_cp = (void *) data;
1447 struct hci_cp_write_local_name hci_cp;
1448 struct hci_dev *hdev;
1449 struct pending_cmd *cmd;
1450 int err;
1451
1452 BT_DBG("");
1453
1454 if (len != sizeof(*mgmt_cp))
1455 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, EINVAL);
1456
1457 hdev = hci_dev_get(index);
1458 if (!hdev)
1459 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, ENODEV);
1460
Andre Guedes8c156c32011-07-07 10:30:36 -03001461 hci_dev_lock_bh(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001462
1463 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, index, data, len);
1464 if (!cmd) {
1465 err = -ENOMEM;
1466 goto failed;
1467 }
1468
1469 memcpy(hci_cp.name, mgmt_cp->name, sizeof(hci_cp.name));
1470 err = hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(hci_cp),
1471 &hci_cp);
1472 if (err < 0)
1473 mgmt_pending_remove(cmd);
1474
1475failed:
Andre Guedes8c156c32011-07-07 10:30:36 -03001476 hci_dev_unlock_bh(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001477 hci_dev_put(hdev);
1478
1479 return err;
1480}
1481
Szymon Jancc35938b2011-03-22 13:12:21 +01001482static int read_local_oob_data(struct sock *sk, u16 index)
1483{
1484 struct hci_dev *hdev;
1485 struct pending_cmd *cmd;
1486 int err;
1487
1488 BT_DBG("hci%u", index);
1489
1490 hdev = hci_dev_get(index);
1491 if (!hdev)
1492 return cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
1493 ENODEV);
1494
Andre Guedes8c156c32011-07-07 10:30:36 -03001495 hci_dev_lock_bh(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01001496
1497 if (!test_bit(HCI_UP, &hdev->flags)) {
1498 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
1499 ENETDOWN);
1500 goto unlock;
1501 }
1502
1503 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
1504 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
1505 EOPNOTSUPP);
1506 goto unlock;
1507 }
1508
1509 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, index)) {
1510 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA, EBUSY);
1511 goto unlock;
1512 }
1513
1514 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, index, NULL, 0);
1515 if (!cmd) {
1516 err = -ENOMEM;
1517 goto unlock;
1518 }
1519
1520 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
1521 if (err < 0)
1522 mgmt_pending_remove(cmd);
1523
1524unlock:
Andre Guedes8c156c32011-07-07 10:30:36 -03001525 hci_dev_unlock_bh(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01001526 hci_dev_put(hdev);
1527
1528 return err;
1529}
1530
Szymon Janc2763eda2011-03-22 13:12:22 +01001531static int add_remote_oob_data(struct sock *sk, u16 index, unsigned char *data,
1532 u16 len)
1533{
1534 struct hci_dev *hdev;
1535 struct mgmt_cp_add_remote_oob_data *cp = (void *) data;
1536 int err;
1537
1538 BT_DBG("hci%u ", index);
1539
1540 if (len != sizeof(*cp))
1541 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
1542 EINVAL);
1543
1544 hdev = hci_dev_get(index);
1545 if (!hdev)
1546 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
1547 ENODEV);
1548
Andre Guedes8c156c32011-07-07 10:30:36 -03001549 hci_dev_lock_bh(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001550
1551 err = hci_add_remote_oob_data(hdev, &cp->bdaddr, cp->hash,
1552 cp->randomizer);
1553 if (err < 0)
1554 err = cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, -err);
1555 else
1556 err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, NULL,
1557 0);
1558
Andre Guedes8c156c32011-07-07 10:30:36 -03001559 hci_dev_unlock_bh(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001560 hci_dev_put(hdev);
1561
1562 return err;
1563}
1564
1565static int remove_remote_oob_data(struct sock *sk, u16 index,
1566 unsigned char *data, u16 len)
1567{
1568 struct hci_dev *hdev;
1569 struct mgmt_cp_remove_remote_oob_data *cp = (void *) data;
1570 int err;
1571
1572 BT_DBG("hci%u ", index);
1573
1574 if (len != sizeof(*cp))
1575 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
1576 EINVAL);
1577
1578 hdev = hci_dev_get(index);
1579 if (!hdev)
1580 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
1581 ENODEV);
1582
Andre Guedes8c156c32011-07-07 10:30:36 -03001583 hci_dev_lock_bh(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001584
1585 err = hci_remove_remote_oob_data(hdev, &cp->bdaddr);
1586 if (err < 0)
1587 err = cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
1588 -err);
1589 else
1590 err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
1591 NULL, 0);
1592
Andre Guedes8c156c32011-07-07 10:30:36 -03001593 hci_dev_unlock_bh(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001594 hci_dev_put(hdev);
1595
1596 return err;
1597}
1598
Johan Hedberg14a53662011-04-27 10:29:56 -04001599static int start_discovery(struct sock *sk, u16 index)
1600{
1601 u8 lap[3] = { 0x33, 0x8b, 0x9e };
1602 struct hci_cp_inquiry cp;
1603 struct pending_cmd *cmd;
1604 struct hci_dev *hdev;
1605 int err;
1606
1607 BT_DBG("hci%u", index);
1608
1609 hdev = hci_dev_get(index);
1610 if (!hdev)
1611 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY, ENODEV);
1612
1613 hci_dev_lock_bh(hdev);
1614
1615 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, index, NULL, 0);
1616 if (!cmd) {
1617 err = -ENOMEM;
1618 goto failed;
1619 }
1620
1621 memset(&cp, 0, sizeof(cp));
1622 memcpy(&cp.lap, lap, 3);
1623 cp.length = 0x08;
1624 cp.num_rsp = 0x00;
1625
1626 err = hci_send_cmd(hdev, HCI_OP_INQUIRY, sizeof(cp), &cp);
1627 if (err < 0)
1628 mgmt_pending_remove(cmd);
1629
1630failed:
1631 hci_dev_unlock_bh(hdev);
1632 hci_dev_put(hdev);
1633
1634 return err;
1635}
1636
1637static int stop_discovery(struct sock *sk, u16 index)
1638{
1639 struct hci_dev *hdev;
1640 struct pending_cmd *cmd;
1641 int err;
1642
1643 BT_DBG("hci%u", index);
1644
1645 hdev = hci_dev_get(index);
1646 if (!hdev)
1647 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY, ENODEV);
1648
1649 hci_dev_lock_bh(hdev);
1650
1651 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, index, NULL, 0);
1652 if (!cmd) {
1653 err = -ENOMEM;
1654 goto failed;
1655 }
1656
1657 err = hci_send_cmd(hdev, HCI_OP_INQUIRY_CANCEL, 0, NULL);
1658 if (err < 0)
1659 mgmt_pending_remove(cmd);
1660
1661failed:
1662 hci_dev_unlock_bh(hdev);
1663 hci_dev_put(hdev);
1664
1665 return err;
1666}
1667
Antti Julku7fbec222011-06-15 12:01:15 +03001668static int block_device(struct sock *sk, u16 index, unsigned char *data,
1669 u16 len)
1670{
1671 struct hci_dev *hdev;
Antti Julku5e762442011-08-25 16:48:02 +03001672 struct pending_cmd *cmd;
1673 struct mgmt_cp_block_device *cp = (void *) data;
Antti Julku7fbec222011-06-15 12:01:15 +03001674 int err;
1675
1676 BT_DBG("hci%u", index);
1677
Antti Julku7fbec222011-06-15 12:01:15 +03001678 if (len != sizeof(*cp))
1679 return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
1680 EINVAL);
1681
1682 hdev = hci_dev_get(index);
1683 if (!hdev)
1684 return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
1685 ENODEV);
1686
Antti Julku5e762442011-08-25 16:48:02 +03001687 hci_dev_lock_bh(hdev);
1688
1689 cmd = mgmt_pending_add(sk, MGMT_OP_BLOCK_DEVICE, index, NULL, 0);
1690 if (!cmd) {
1691 err = -ENOMEM;
1692 goto failed;
1693 }
1694
Antti Julku7fbec222011-06-15 12:01:15 +03001695 err = hci_blacklist_add(hdev, &cp->bdaddr);
1696
1697 if (err < 0)
1698 err = cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE, -err);
1699 else
1700 err = cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE,
1701 NULL, 0);
Antti Julku5e762442011-08-25 16:48:02 +03001702
1703 mgmt_pending_remove(cmd);
1704
1705failed:
1706 hci_dev_unlock_bh(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03001707 hci_dev_put(hdev);
1708
1709 return err;
1710}
1711
1712static int unblock_device(struct sock *sk, u16 index, unsigned char *data,
1713 u16 len)
1714{
1715 struct hci_dev *hdev;
Antti Julku5e762442011-08-25 16:48:02 +03001716 struct pending_cmd *cmd;
1717 struct mgmt_cp_unblock_device *cp = (void *) data;
Antti Julku7fbec222011-06-15 12:01:15 +03001718 int err;
1719
1720 BT_DBG("hci%u", index);
1721
Antti Julku7fbec222011-06-15 12:01:15 +03001722 if (len != sizeof(*cp))
1723 return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
1724 EINVAL);
1725
1726 hdev = hci_dev_get(index);
1727 if (!hdev)
1728 return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
1729 ENODEV);
1730
Antti Julku5e762442011-08-25 16:48:02 +03001731 hci_dev_lock_bh(hdev);
1732
1733 cmd = mgmt_pending_add(sk, MGMT_OP_UNBLOCK_DEVICE, index, NULL, 0);
1734 if (!cmd) {
1735 err = -ENOMEM;
1736 goto failed;
1737 }
1738
Antti Julku7fbec222011-06-15 12:01:15 +03001739 err = hci_blacklist_del(hdev, &cp->bdaddr);
1740
1741 if (err < 0)
1742 err = cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE, -err);
1743 else
1744 err = cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE,
1745 NULL, 0);
Antti Julku5e762442011-08-25 16:48:02 +03001746
1747 mgmt_pending_remove(cmd);
1748
1749failed:
1750 hci_dev_unlock_bh(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03001751 hci_dev_put(hdev);
1752
1753 return err;
1754}
1755
Antti Julkuf6422ec2011-06-22 13:11:56 +03001756static int set_fast_connectable(struct sock *sk, u16 index,
1757 unsigned char *data, u16 len)
1758{
1759 struct hci_dev *hdev;
1760 struct mgmt_cp_set_fast_connectable *cp = (void *) data;
1761 struct hci_cp_write_page_scan_activity acp;
1762 u8 type;
1763 int err;
1764
1765 BT_DBG("hci%u", index);
1766
1767 if (len != sizeof(*cp))
1768 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
1769 EINVAL);
1770
1771 hdev = hci_dev_get(index);
1772 if (!hdev)
1773 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
1774 ENODEV);
1775
1776 hci_dev_lock(hdev);
1777
1778 if (cp->enable) {
1779 type = PAGE_SCAN_TYPE_INTERLACED;
1780 acp.interval = 0x0024; /* 22.5 msec page scan interval */
1781 } else {
1782 type = PAGE_SCAN_TYPE_STANDARD; /* default */
1783 acp.interval = 0x0800; /* default 1.28 sec page scan */
1784 }
1785
1786 acp.window = 0x0012; /* default 11.25 msec page scan window */
1787
1788 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
1789 sizeof(acp), &acp);
1790 if (err < 0) {
1791 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
1792 -err);
1793 goto done;
1794 }
1795
1796 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
1797 if (err < 0) {
1798 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
1799 -err);
1800 goto done;
1801 }
1802
1803 err = cmd_complete(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
1804 NULL, 0);
1805done:
1806 hci_dev_unlock(hdev);
1807 hci_dev_put(hdev);
1808
1809 return err;
1810}
1811
Johan Hedberg03811012010-12-08 00:21:06 +02001812int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
1813{
1814 unsigned char *buf;
1815 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001816 u16 opcode, index, len;
Johan Hedberg03811012010-12-08 00:21:06 +02001817 int err;
1818
1819 BT_DBG("got %zu bytes", msglen);
1820
1821 if (msglen < sizeof(*hdr))
1822 return -EINVAL;
1823
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03001824 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02001825 if (!buf)
1826 return -ENOMEM;
1827
1828 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
1829 err = -EFAULT;
1830 goto done;
1831 }
1832
1833 hdr = (struct mgmt_hdr *) buf;
1834 opcode = get_unaligned_le16(&hdr->opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01001835 index = get_unaligned_le16(&hdr->index);
Johan Hedberg03811012010-12-08 00:21:06 +02001836 len = get_unaligned_le16(&hdr->len);
1837
1838 if (len != msglen - sizeof(*hdr)) {
1839 err = -EINVAL;
1840 goto done;
1841 }
1842
1843 switch (opcode) {
Johan Hedberg02d98122010-12-13 21:07:04 +02001844 case MGMT_OP_READ_VERSION:
1845 err = read_version(sk);
1846 break;
Johan Hedbergfaba42e2010-12-13 21:07:05 +02001847 case MGMT_OP_READ_INDEX_LIST:
1848 err = read_index_list(sk);
1849 break;
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001850 case MGMT_OP_READ_INFO:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001851 err = read_controller_info(sk, index);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001852 break;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001853 case MGMT_OP_SET_POWERED:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001854 err = set_powered(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001855 break;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001856 case MGMT_OP_SET_DISCOVERABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001857 err = set_discoverable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001858 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001859 case MGMT_OP_SET_CONNECTABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001860 err = set_connectable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001861 break;
Johan Hedbergc542a062011-01-26 13:11:03 +02001862 case MGMT_OP_SET_PAIRABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001863 err = set_pairable(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergc542a062011-01-26 13:11:03 +02001864 break;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001865 case MGMT_OP_ADD_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001866 err = add_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001867 break;
1868 case MGMT_OP_REMOVE_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001869 err = remove_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001870 break;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001871 case MGMT_OP_SET_DEV_CLASS:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001872 err = set_dev_class(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001873 break;
1874 case MGMT_OP_SET_SERVICE_CACHE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001875 err = set_service_cache(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001876 break;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001877 case MGMT_OP_LOAD_KEYS:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001878 err = load_keys(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001879 break;
1880 case MGMT_OP_REMOVE_KEY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001881 err = remove_key(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001882 break;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001883 case MGMT_OP_DISCONNECT:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001884 err = disconnect(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001885 break;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001886 case MGMT_OP_GET_CONNECTIONS:
Szymon Janc8ce62842011-03-01 16:55:32 +01001887 err = get_connections(sk, index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001888 break;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001889 case MGMT_OP_PIN_CODE_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001890 err = pin_code_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001891 break;
1892 case MGMT_OP_PIN_CODE_NEG_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001893 err = pin_code_neg_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001894 break;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001895 case MGMT_OP_SET_IO_CAPABILITY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001896 err = set_io_capability(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001897 break;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001898 case MGMT_OP_PAIR_DEVICE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001899 err = pair_device(sk, index, buf + sizeof(*hdr), len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001900 break;
Johan Hedberga5c29682011-02-19 12:05:57 -03001901 case MGMT_OP_USER_CONFIRM_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001902 err = user_confirm_reply(sk, index, buf + sizeof(*hdr), len, 1);
Johan Hedberga5c29682011-02-19 12:05:57 -03001903 break;
1904 case MGMT_OP_USER_CONFIRM_NEG_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001905 err = user_confirm_reply(sk, index, buf + sizeof(*hdr), len, 0);
Johan Hedberga5c29682011-02-19 12:05:57 -03001906 break;
Johan Hedbergb312b1612011-03-16 14:29:37 +02001907 case MGMT_OP_SET_LOCAL_NAME:
1908 err = set_local_name(sk, index, buf + sizeof(*hdr), len);
1909 break;
Szymon Jancc35938b2011-03-22 13:12:21 +01001910 case MGMT_OP_READ_LOCAL_OOB_DATA:
1911 err = read_local_oob_data(sk, index);
1912 break;
Szymon Janc2763eda2011-03-22 13:12:22 +01001913 case MGMT_OP_ADD_REMOTE_OOB_DATA:
1914 err = add_remote_oob_data(sk, index, buf + sizeof(*hdr), len);
1915 break;
1916 case MGMT_OP_REMOVE_REMOTE_OOB_DATA:
1917 err = remove_remote_oob_data(sk, index, buf + sizeof(*hdr),
1918 len);
1919 break;
Johan Hedberg14a53662011-04-27 10:29:56 -04001920 case MGMT_OP_START_DISCOVERY:
1921 err = start_discovery(sk, index);
1922 break;
1923 case MGMT_OP_STOP_DISCOVERY:
1924 err = stop_discovery(sk, index);
1925 break;
Antti Julku7fbec222011-06-15 12:01:15 +03001926 case MGMT_OP_BLOCK_DEVICE:
1927 err = block_device(sk, index, buf + sizeof(*hdr), len);
1928 break;
1929 case MGMT_OP_UNBLOCK_DEVICE:
1930 err = unblock_device(sk, index, buf + sizeof(*hdr), len);
1931 break;
Antti Julkuf6422ec2011-06-22 13:11:56 +03001932 case MGMT_OP_SET_FAST_CONNECTABLE:
1933 err = set_fast_connectable(sk, index, buf + sizeof(*hdr),
1934 len);
1935 break;
Johan Hedberg03811012010-12-08 00:21:06 +02001936 default:
1937 BT_DBG("Unknown op %u", opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01001938 err = cmd_status(sk, index, opcode, 0x01);
Johan Hedberg03811012010-12-08 00:21:06 +02001939 break;
1940 }
1941
Johan Hedberge41d8b42010-12-13 21:07:03 +02001942 if (err < 0)
1943 goto done;
1944
Johan Hedberg03811012010-12-08 00:21:06 +02001945 err = msglen;
1946
1947done:
1948 kfree(buf);
1949 return err;
1950}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001951
Johan Hedbergb24752f2011-11-03 14:40:33 +02001952static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
1953{
1954 u8 *status = data;
1955
1956 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
1957 mgmt_pending_remove(cmd);
1958}
1959
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001960int mgmt_index_added(u16 index)
1961{
Szymon Janc4e51eae2011-02-25 19:05:48 +01001962 return mgmt_event(MGMT_EV_INDEX_ADDED, index, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001963}
1964
1965int mgmt_index_removed(u16 index)
1966{
Johan Hedbergb24752f2011-11-03 14:40:33 +02001967 u8 status = ENODEV;
1968
1969 mgmt_pending_foreach(0, index, cmd_status_rsp, &status);
1970
Szymon Janc4e51eae2011-02-25 19:05:48 +01001971 return mgmt_event(MGMT_EV_INDEX_REMOVED, index, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001972}
1973
Johan Hedberg73f22f62010-12-29 16:00:25 +02001974struct cmd_lookup {
Johan Hedberg72a734e2010-12-30 00:38:22 +02001975 u8 val;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001976 struct sock *sk;
1977};
1978
Johan Hedberg72a734e2010-12-30 00:38:22 +02001979static void mode_rsp(struct pending_cmd *cmd, void *data)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001980{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01001981 struct mgmt_mode *cp = cmd->param;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001982 struct cmd_lookup *match = data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001983
Johan Hedberg72a734e2010-12-30 00:38:22 +02001984 if (cp->val != match->val)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001985 return;
1986
Johan Hedberg053f0212011-01-26 13:07:10 +02001987 send_mode_rsp(cmd->sk, cmd->opcode, cmd->index, cp->val);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001988
1989 list_del(&cmd->list);
1990
1991 if (match->sk == NULL) {
1992 match->sk = cmd->sk;
1993 sock_hold(match->sk);
1994 }
1995
1996 mgmt_pending_free(cmd);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001997}
Johan Hedberg5add6af2010-12-16 10:00:37 +02001998
1999int mgmt_powered(u16 index, u8 powered)
2000{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002001 struct mgmt_mode ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002002 struct cmd_lookup match = { powered, NULL };
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002003 int ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002004
Johan Hedberg72a734e2010-12-30 00:38:22 +02002005 mgmt_pending_foreach(MGMT_OP_SET_POWERED, index, mode_rsp, &match);
Johan Hedberg5add6af2010-12-16 10:00:37 +02002006
Johan Hedbergb24752f2011-11-03 14:40:33 +02002007 if (!powered) {
2008 u8 status = ENETDOWN;
2009 mgmt_pending_foreach(0, index, cmd_status_rsp, &status);
2010 }
2011
Johan Hedberg72a734e2010-12-30 00:38:22 +02002012 ev.val = powered;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002013
Szymon Janc4e51eae2011-02-25 19:05:48 +01002014 ret = mgmt_event(MGMT_EV_POWERED, index, &ev, sizeof(ev), match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002015
2016 if (match.sk)
2017 sock_put(match.sk);
2018
2019 return ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002020}
Johan Hedberg73f22f62010-12-29 16:00:25 +02002021
Johan Hedberg73f22f62010-12-29 16:00:25 +02002022int mgmt_discoverable(u16 index, u8 discoverable)
2023{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002024 struct mgmt_mode ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002025 struct cmd_lookup match = { discoverable, NULL };
2026 int ret;
2027
Szymon Jancb8534e02011-03-01 16:55:34 +01002028 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, index, mode_rsp, &match);
Johan Hedberg72a734e2010-12-30 00:38:22 +02002029
Johan Hedberg72a734e2010-12-30 00:38:22 +02002030 ev.val = discoverable;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002031
Szymon Janc4e51eae2011-02-25 19:05:48 +01002032 ret = mgmt_event(MGMT_EV_DISCOVERABLE, index, &ev, sizeof(ev),
2033 match.sk);
Johan Hedberg73f22f62010-12-29 16:00:25 +02002034
2035 if (match.sk)
2036 sock_put(match.sk);
2037
2038 return ret;
2039}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002040
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002041int mgmt_connectable(u16 index, u8 connectable)
2042{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002043 struct mgmt_mode ev;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002044 struct cmd_lookup match = { connectable, NULL };
2045 int ret;
2046
Johan Hedberg72a734e2010-12-30 00:38:22 +02002047 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, index, mode_rsp, &match);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002048
Johan Hedberg72a734e2010-12-30 00:38:22 +02002049 ev.val = connectable;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002050
Szymon Janc4e51eae2011-02-25 19:05:48 +01002051 ret = mgmt_event(MGMT_EV_CONNECTABLE, index, &ev, sizeof(ev), match.sk);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002052
2053 if (match.sk)
2054 sock_put(match.sk);
2055
2056 return ret;
2057}
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002058
Johan Hedberg4df378a2011-04-28 11:29:03 -07002059int mgmt_new_key(u16 index, struct link_key *key, u8 persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002060{
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002061 struct mgmt_ev_new_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002062
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002063 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002064
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002065 ev.store_hint = persistent;
2066 bacpy(&ev.key.bdaddr, &key->bdaddr);
2067 ev.key.type = key->type;
2068 memcpy(ev.key.val, key->val, 16);
2069 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002070
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002071 return mgmt_event(MGMT_EV_NEW_KEY, index, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002072}
Johan Hedbergf7520542011-01-20 12:34:39 +02002073
Vinicius Costa Gomescfafccf2011-08-19 21:06:56 -03002074int mgmt_connected(u16 index, bdaddr_t *bdaddr, u8 link_type)
Johan Hedbergf7520542011-01-20 12:34:39 +02002075{
2076 struct mgmt_ev_connected ev;
2077
Johan Hedbergf7520542011-01-20 12:34:39 +02002078 bacpy(&ev.bdaddr, bdaddr);
Vinicius Costa Gomescfafccf2011-08-19 21:06:56 -03002079 ev.link_type = link_type;
Johan Hedbergf7520542011-01-20 12:34:39 +02002080
Szymon Janc4e51eae2011-02-25 19:05:48 +01002081 return mgmt_event(MGMT_EV_CONNECTED, index, &ev, sizeof(ev), NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02002082}
2083
Johan Hedberg8962ee72011-01-20 12:40:27 +02002084static void disconnect_rsp(struct pending_cmd *cmd, void *data)
2085{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01002086 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002087 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02002088 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002089
Johan Hedberga38528f2011-01-22 06:46:43 +02002090 bacpy(&rp.bdaddr, &cp->bdaddr);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002091
Szymon Janc4e51eae2011-02-25 19:05:48 +01002092 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002093
2094 *sk = cmd->sk;
2095 sock_hold(*sk);
2096
Johan Hedberga664b5b2011-02-19 12:06:02 -03002097 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002098}
2099
Johan Hedbergf7520542011-01-20 12:34:39 +02002100int mgmt_disconnected(u16 index, bdaddr_t *bdaddr)
2101{
2102 struct mgmt_ev_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002103 struct sock *sk = NULL;
2104 int err;
2105
2106 mgmt_pending_foreach(MGMT_OP_DISCONNECT, index, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02002107
Johan Hedbergf7520542011-01-20 12:34:39 +02002108 bacpy(&ev.bdaddr, bdaddr);
2109
Szymon Janc4e51eae2011-02-25 19:05:48 +01002110 err = mgmt_event(MGMT_EV_DISCONNECTED, index, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002111
2112 if (sk)
2113 sock_put(sk);
2114
2115 return err;
2116}
2117
2118int mgmt_disconnect_failed(u16 index)
2119{
2120 struct pending_cmd *cmd;
2121 int err;
2122
2123 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, index);
2124 if (!cmd)
2125 return -ENOENT;
2126
Szymon Janc4e51eae2011-02-25 19:05:48 +01002127 err = cmd_status(cmd->sk, index, MGMT_OP_DISCONNECT, EIO);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002128
Johan Hedberga664b5b2011-02-19 12:06:02 -03002129 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002130
2131 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02002132}
Johan Hedberg17d5c042011-01-22 06:09:08 +02002133
2134int mgmt_connect_failed(u16 index, bdaddr_t *bdaddr, u8 status)
2135{
2136 struct mgmt_ev_connect_failed ev;
2137
Johan Hedberg17d5c042011-01-22 06:09:08 +02002138 bacpy(&ev.bdaddr, bdaddr);
2139 ev.status = status;
2140
Szymon Janc4e51eae2011-02-25 19:05:48 +01002141 return mgmt_event(MGMT_EV_CONNECT_FAILED, index, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02002142}
Johan Hedberg980e1a52011-01-22 06:10:07 +02002143
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02002144int mgmt_pin_code_request(u16 index, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002145{
2146 struct mgmt_ev_pin_code_request ev;
2147
Johan Hedberg980e1a52011-01-22 06:10:07 +02002148 bacpy(&ev.bdaddr, bdaddr);
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02002149 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002150
Szymon Janc4e51eae2011-02-25 19:05:48 +01002151 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, index, &ev, sizeof(ev),
2152 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002153}
2154
2155int mgmt_pin_code_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
2156{
2157 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002158 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002159 int err;
2160
2161 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, index);
2162 if (!cmd)
2163 return -ENOENT;
2164
Johan Hedbergac56fb12011-02-19 12:05:59 -03002165 bacpy(&rp.bdaddr, bdaddr);
2166 rp.status = status;
2167
Szymon Janc4e51eae2011-02-25 19:05:48 +01002168 err = cmd_complete(cmd->sk, index, MGMT_OP_PIN_CODE_REPLY, &rp,
2169 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002170
Johan Hedberga664b5b2011-02-19 12:06:02 -03002171 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002172
2173 return err;
2174}
2175
2176int mgmt_pin_code_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
2177{
2178 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002179 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002180 int err;
2181
2182 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, index);
2183 if (!cmd)
2184 return -ENOENT;
2185
Johan Hedbergac56fb12011-02-19 12:05:59 -03002186 bacpy(&rp.bdaddr, bdaddr);
2187 rp.status = status;
2188
Szymon Janc4e51eae2011-02-25 19:05:48 +01002189 err = cmd_complete(cmd->sk, index, MGMT_OP_PIN_CODE_NEG_REPLY, &rp,
2190 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002191
Johan Hedberga664b5b2011-02-19 12:06:02 -03002192 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002193
2194 return err;
2195}
Johan Hedberga5c29682011-02-19 12:05:57 -03002196
Johan Hedberg55bc1a32011-04-28 11:28:56 -07002197int mgmt_user_confirm_request(u16 index, bdaddr_t *bdaddr, __le32 value,
2198 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03002199{
2200 struct mgmt_ev_user_confirm_request ev;
2201
2202 BT_DBG("hci%u", index);
2203
Johan Hedberga5c29682011-02-19 12:05:57 -03002204 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07002205 ev.confirm_hint = confirm_hint;
Johan Hedberga5c29682011-02-19 12:05:57 -03002206 put_unaligned_le32(value, &ev.value);
2207
Szymon Janc4e51eae2011-02-25 19:05:48 +01002208 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, index, &ev, sizeof(ev),
2209 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03002210}
2211
2212static int confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status,
2213 u8 opcode)
2214{
2215 struct pending_cmd *cmd;
2216 struct mgmt_rp_user_confirm_reply rp;
2217 int err;
2218
2219 cmd = mgmt_pending_find(opcode, index);
2220 if (!cmd)
2221 return -ENOENT;
2222
Johan Hedberga5c29682011-02-19 12:05:57 -03002223 bacpy(&rp.bdaddr, bdaddr);
2224 rp.status = status;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002225 err = cmd_complete(cmd->sk, index, opcode, &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03002226
Johan Hedberga664b5b2011-02-19 12:06:02 -03002227 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002228
2229 return err;
2230}
2231
2232int mgmt_user_confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
2233{
2234 return confirm_reply_complete(index, bdaddr, status,
2235 MGMT_OP_USER_CONFIRM_REPLY);
2236}
2237
Szymon Jancb8534e02011-03-01 16:55:34 +01002238int mgmt_user_confirm_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03002239{
2240 return confirm_reply_complete(index, bdaddr, status,
2241 MGMT_OP_USER_CONFIRM_NEG_REPLY);
2242}
Johan Hedberg2a611692011-02-19 12:06:00 -03002243
2244int mgmt_auth_failed(u16 index, bdaddr_t *bdaddr, u8 status)
2245{
2246 struct mgmt_ev_auth_failed ev;
2247
Johan Hedberg2a611692011-02-19 12:06:00 -03002248 bacpy(&ev.bdaddr, bdaddr);
2249 ev.status = status;
2250
Szymon Janc4e51eae2011-02-25 19:05:48 +01002251 return mgmt_event(MGMT_EV_AUTH_FAILED, index, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03002252}
Johan Hedbergb312b1612011-03-16 14:29:37 +02002253
2254int mgmt_set_local_name_complete(u16 index, u8 *name, u8 status)
2255{
2256 struct pending_cmd *cmd;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002257 struct hci_dev *hdev;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002258 struct mgmt_cp_set_local_name ev;
2259 int err;
2260
2261 memset(&ev, 0, sizeof(ev));
2262 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
2263
2264 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, index);
2265 if (!cmd)
2266 goto send_event;
2267
2268 if (status) {
2269 err = cmd_status(cmd->sk, index, MGMT_OP_SET_LOCAL_NAME, EIO);
2270 goto failed;
2271 }
2272
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002273 hdev = hci_dev_get(index);
2274 if (hdev) {
2275 hci_dev_lock_bh(hdev);
2276 update_eir(hdev);
2277 hci_dev_unlock_bh(hdev);
2278 hci_dev_put(hdev);
2279 }
2280
Johan Hedbergb312b1612011-03-16 14:29:37 +02002281 err = cmd_complete(cmd->sk, index, MGMT_OP_SET_LOCAL_NAME, &ev,
2282 sizeof(ev));
2283 if (err < 0)
2284 goto failed;
2285
2286send_event:
2287 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, index, &ev, sizeof(ev),
2288 cmd ? cmd->sk : NULL);
2289
2290failed:
2291 if (cmd)
2292 mgmt_pending_remove(cmd);
2293 return err;
2294}
Szymon Jancc35938b2011-03-22 13:12:21 +01002295
2296int mgmt_read_local_oob_data_reply_complete(u16 index, u8 *hash, u8 *randomizer,
2297 u8 status)
2298{
2299 struct pending_cmd *cmd;
2300 int err;
2301
2302 BT_DBG("hci%u status %u", index, status);
2303
2304 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, index);
2305 if (!cmd)
2306 return -ENOENT;
2307
2308 if (status) {
2309 err = cmd_status(cmd->sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2310 EIO);
2311 } else {
2312 struct mgmt_rp_read_local_oob_data rp;
2313
2314 memcpy(rp.hash, hash, sizeof(rp.hash));
2315 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
2316
2317 err = cmd_complete(cmd->sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2318 &rp, sizeof(rp));
2319 }
2320
2321 mgmt_pending_remove(cmd);
2322
2323 return err;
2324}
Johan Hedberge17acd42011-03-30 23:57:16 +03002325
2326int mgmt_device_found(u16 index, bdaddr_t *bdaddr, u8 *dev_class, s8 rssi,
2327 u8 *eir)
2328{
2329 struct mgmt_ev_device_found ev;
2330
2331 memset(&ev, 0, sizeof(ev));
2332
2333 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberge17acd42011-03-30 23:57:16 +03002334 ev.rssi = rssi;
2335
2336 if (eir)
2337 memcpy(ev.eir, eir, sizeof(ev.eir));
2338
Andre Guedesf8523592011-09-09 18:56:26 -03002339 if (dev_class)
2340 memcpy(ev.dev_class, dev_class, sizeof(ev.dev_class));
2341
Johan Hedberge17acd42011-03-30 23:57:16 +03002342 return mgmt_event(MGMT_EV_DEVICE_FOUND, index, &ev, sizeof(ev), NULL);
2343}
Johan Hedberga88a9652011-03-30 13:18:12 +03002344
2345int mgmt_remote_name(u16 index, bdaddr_t *bdaddr, u8 *name)
2346{
2347 struct mgmt_ev_remote_name ev;
2348
2349 memset(&ev, 0, sizeof(ev));
2350
2351 bacpy(&ev.bdaddr, bdaddr);
2352 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
2353
2354 return mgmt_event(MGMT_EV_REMOTE_NAME, index, &ev, sizeof(ev), NULL);
2355}
Johan Hedberg314b2382011-04-27 10:29:57 -04002356
Johan Hedberg164a6e72011-11-01 17:06:44 +02002357int mgmt_inquiry_failed(u16 index, u8 status)
2358{
2359 struct pending_cmd *cmd;
2360 int err;
2361
2362 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, index);
2363 if (!cmd)
2364 return -ENOENT;
2365
2366 err = cmd_status(cmd->sk, index, cmd->opcode, status);
2367 mgmt_pending_remove(cmd);
2368
2369 return err;
2370}
2371
Johan Hedberg314b2382011-04-27 10:29:57 -04002372int mgmt_discovering(u16 index, u8 discovering)
2373{
Johan Hedberg164a6e72011-11-01 17:06:44 +02002374 struct pending_cmd *cmd;
2375
2376 if (discovering)
2377 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, index);
2378 else
2379 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, index);
2380
2381 if (cmd != NULL) {
2382 cmd_complete(cmd->sk, index, cmd->opcode, NULL, 0);
2383 mgmt_pending_remove(cmd);
2384 }
2385
Johan Hedberg314b2382011-04-27 10:29:57 -04002386 return mgmt_event(MGMT_EV_DISCOVERING, index, &discovering,
2387 sizeof(discovering), NULL);
2388}
Antti Julku5e762442011-08-25 16:48:02 +03002389
2390int mgmt_device_blocked(u16 index, bdaddr_t *bdaddr)
2391{
2392 struct pending_cmd *cmd;
2393 struct mgmt_ev_device_blocked ev;
2394
2395 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, index);
2396
2397 bacpy(&ev.bdaddr, bdaddr);
2398
2399 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, index, &ev, sizeof(ev),
2400 cmd ? cmd->sk : NULL);
2401}
2402
2403int mgmt_device_unblocked(u16 index, bdaddr_t *bdaddr)
2404{
2405 struct pending_cmd *cmd;
2406 struct mgmt_ev_device_unblocked ev;
2407
2408 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, index);
2409
2410 bacpy(&ev.bdaddr, bdaddr);
2411
2412 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, index, &ev, sizeof(ev),
2413 cmd ? cmd->sk : NULL);
2414}