blob: be198f382ed8f02f52a9ff2178d14132358a6b4b [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
Andre Guedes2519a1f2011-11-07 11:45:24 -030035#define INQUIRY_LEN_BREDR 0x08 /* TGAP(100) */
36
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020037struct pending_cmd {
38 struct list_head list;
39 __u16 opcode;
40 int index;
Szymon Jancc68fb7f2011-03-22 13:12:19 +010041 void *param;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020042 struct sock *sk;
Johan Hedberge9a416b2011-02-19 12:05:56 -030043 void *user_data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020044};
45
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 Hedberg32435532011-11-07 22:16:04 +0200151 if (test_and_clear_bit(HCI_AUTO_OFF, &d->flags))
152 cancel_delayed_work_sync(&d->power_off);
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200153
154 if (test_bit(HCI_SETUP, &d->flags))
155 continue;
156
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200157 put_unaligned_le16(d->id, &rp->index[i++]);
158 BT_DBG("Added hci%u", d->id);
159 }
160
161 read_unlock(&hci_dev_list_lock);
162
Szymon Janc4e51eae2011-02-25 19:05:48 +0100163 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST, rp,
164 rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200165
Johan Hedberga38528f2011-01-22 06:46:43 +0200166 kfree(rp);
167
168 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200169}
170
Szymon Janc4e51eae2011-02-25 19:05:48 +0100171static int read_controller_info(struct sock *sk, u16 index)
Johan Hedberg03811012010-12-08 00:21:06 +0200172{
Johan Hedberga38528f2011-01-22 06:46:43 +0200173 struct mgmt_rp_read_info rp;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200174 struct hci_dev *hdev;
Johan Hedberg03811012010-12-08 00:21:06 +0200175
Szymon Janc4e51eae2011-02-25 19:05:48 +0100176 BT_DBG("sock %p hci%u", sk, index);
Johan Hedberg03811012010-12-08 00:21:06 +0200177
Szymon Janc4e51eae2011-02-25 19:05:48 +0100178 hdev = hci_dev_get(index);
Johan Hedberga38528f2011-01-22 06:46:43 +0200179 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100180 return cmd_status(sk, index, MGMT_OP_READ_INFO, ENODEV);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200181
Johan Hedberg32435532011-11-07 22:16:04 +0200182 if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->flags))
183 cancel_delayed_work_sync(&hdev->power_off);
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200184
Andre Guedes8c156c32011-07-07 10:30:36 -0300185 hci_dev_lock_bh(hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200186
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200187 set_bit(HCI_MGMT, &hdev->flags);
188
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200189 memset(&rp, 0, sizeof(rp));
190
Johan Hedberga38528f2011-01-22 06:46:43 +0200191 rp.type = hdev->dev_type;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200192
Johan Hedberga38528f2011-01-22 06:46:43 +0200193 rp.powered = test_bit(HCI_UP, &hdev->flags);
194 rp.connectable = test_bit(HCI_PSCAN, &hdev->flags);
195 rp.discoverable = test_bit(HCI_ISCAN, &hdev->flags);
196 rp.pairable = test_bit(HCI_PSCAN, &hdev->flags);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200197
198 if (test_bit(HCI_AUTH, &hdev->flags))
Johan Hedberga38528f2011-01-22 06:46:43 +0200199 rp.sec_mode = 3;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200200 else if (hdev->ssp_mode > 0)
Johan Hedberga38528f2011-01-22 06:46:43 +0200201 rp.sec_mode = 4;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200202 else
Johan Hedberga38528f2011-01-22 06:46:43 +0200203 rp.sec_mode = 2;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200204
Johan Hedberga38528f2011-01-22 06:46:43 +0200205 bacpy(&rp.bdaddr, &hdev->bdaddr);
206 memcpy(rp.features, hdev->features, 8);
207 memcpy(rp.dev_class, hdev->dev_class, 3);
208 put_unaligned_le16(hdev->manufacturer, &rp.manufacturer);
209 rp.hci_ver = hdev->hci_ver;
210 put_unaligned_le16(hdev->hci_rev, &rp.hci_rev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200211
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200212 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
213
Andre Guedes8c156c32011-07-07 10:30:36 -0300214 hci_dev_unlock_bh(hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200215 hci_dev_put(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200216
Szymon Janc4e51eae2011-02-25 19:05:48 +0100217 return cmd_complete(sk, index, MGMT_OP_READ_INFO, &rp, sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +0200218}
219
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200220static void mgmt_pending_free(struct pending_cmd *cmd)
221{
222 sock_put(cmd->sk);
Szymon Jancc68fb7f2011-03-22 13:12:19 +0100223 kfree(cmd->param);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200224 kfree(cmd);
225}
226
Johan Hedberg366a0332011-02-19 12:05:55 -0300227static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
Johan Hedberg2e58ef32011-11-08 20:40:15 +0200228 struct hci_dev *hdev,
229 void *data, u16 len)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200230{
231 struct pending_cmd *cmd;
232
233 cmd = kmalloc(sizeof(*cmd), GFP_ATOMIC);
234 if (!cmd)
Johan Hedberg366a0332011-02-19 12:05:55 -0300235 return NULL;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200236
237 cmd->opcode = opcode;
Johan Hedberg2e58ef32011-11-08 20:40:15 +0200238 cmd->index = hdev->id;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200239
Szymon Jancc68fb7f2011-03-22 13:12:19 +0100240 cmd->param = kmalloc(len, GFP_ATOMIC);
241 if (!cmd->param) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200242 kfree(cmd);
Johan Hedberg366a0332011-02-19 12:05:55 -0300243 return NULL;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200244 }
245
Szymon Janc8fce6352011-03-22 13:12:20 +0100246 if (data)
247 memcpy(cmd->param, data, len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200248
249 cmd->sk = sk;
250 sock_hold(sk);
251
Johan Hedberg2e58ef32011-11-08 20:40:15 +0200252 list_add(&cmd->list, &hdev->mgmt_pending);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200253
Johan Hedberg366a0332011-02-19 12:05:55 -0300254 return cmd;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200255}
256
Johan Hedberg744cf192011-11-08 20:40:14 +0200257static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200258 void (*cb)(struct pending_cmd *cmd, void *data),
259 void *data)
260{
261 struct list_head *p, *n;
262
Johan Hedberg2e58ef32011-11-08 20:40:15 +0200263 list_for_each_safe(p, n, &hdev->mgmt_pending) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200264 struct pending_cmd *cmd;
265
266 cmd = list_entry(p, struct pending_cmd, list);
267
Johan Hedbergb24752f2011-11-03 14:40:33 +0200268 if (opcode > 0 && cmd->opcode != opcode)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200269 continue;
270
Johan Hedberg744cf192011-11-08 20:40:14 +0200271 if (hdev && cmd->index != hdev->id)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200272 continue;
273
274 cb(cmd, data);
275 }
276}
277
Johan Hedberg2e58ef32011-11-08 20:40:15 +0200278static struct pending_cmd *mgmt_pending_find(u16 opcode, struct hci_dev *hdev)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200279{
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200280 struct pending_cmd *cmd;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200281
Johan Hedberg2e58ef32011-11-08 20:40:15 +0200282 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200283 if (cmd->opcode != opcode)
284 continue;
285
Johan Hedberg2e58ef32011-11-08 20:40:15 +0200286 if (hdev && cmd->index != hdev->id)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200287 continue;
288
289 return cmd;
290 }
291
292 return NULL;
293}
294
Johan Hedberga664b5b2011-02-19 12:06:02 -0300295static void mgmt_pending_remove(struct pending_cmd *cmd)
Johan Hedberg73f22f62010-12-29 16:00:25 +0200296{
Johan Hedberg73f22f62010-12-29 16:00:25 +0200297 list_del(&cmd->list);
298 mgmt_pending_free(cmd);
299}
300
Szymon Janc4e51eae2011-02-25 19:05:48 +0100301static int set_powered(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200302{
Johan Hedberg72a734e2010-12-30 00:38:22 +0200303 struct mgmt_mode *cp;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200304 struct hci_dev *hdev;
Johan Hedberg366a0332011-02-19 12:05:55 -0300305 struct pending_cmd *cmd;
Johan Hedberg366a0332011-02-19 12:05:55 -0300306 int err, up;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200307
308 cp = (void *) data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200309
Szymon Janc4e51eae2011-02-25 19:05:48 +0100310 BT_DBG("request for hci%u", index);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200311
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100312 if (len != sizeof(*cp))
313 return cmd_status(sk, index, MGMT_OP_SET_POWERED, EINVAL);
314
Szymon Janc4e51eae2011-02-25 19:05:48 +0100315 hdev = hci_dev_get(index);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200316 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100317 return cmd_status(sk, index, MGMT_OP_SET_POWERED, ENODEV);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200318
Andre Guedes8c156c32011-07-07 10:30:36 -0300319 hci_dev_lock_bh(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200320
321 up = test_bit(HCI_UP, &hdev->flags);
Johan Hedberg72a734e2010-12-30 00:38:22 +0200322 if ((cp->val && up) || (!cp->val && !up)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100323 err = cmd_status(sk, index, MGMT_OP_SET_POWERED, EALREADY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200324 goto failed;
325 }
326
Johan Hedberg2e58ef32011-11-08 20:40:15 +0200327 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100328 err = cmd_status(sk, index, MGMT_OP_SET_POWERED, EBUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200329 goto failed;
330 }
331
Johan Hedberg2e58ef32011-11-08 20:40:15 +0200332 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -0300333 if (!cmd) {
334 err = -ENOMEM;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200335 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -0300336 }
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200337
Johan Hedberg72a734e2010-12-30 00:38:22 +0200338 if (cp->val)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200339 queue_work(hdev->workqueue, &hdev->power_on);
340 else
Johan Hedberg32435532011-11-07 22:16:04 +0200341 queue_work(hdev->workqueue, &hdev->power_off.work);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200342
Johan Hedberg366a0332011-02-19 12:05:55 -0300343 err = 0;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200344
345failed:
Andre Guedes8c156c32011-07-07 10:30:36 -0300346 hci_dev_unlock_bh(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200347 hci_dev_put(hdev);
Johan Hedberg366a0332011-02-19 12:05:55 -0300348 return err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200349}
350
Szymon Janc4e51eae2011-02-25 19:05:48 +0100351static int set_discoverable(struct sock *sk, u16 index, unsigned char *data,
352 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +0200353{
Johan Hedberg16ab91a2011-11-07 22:16:02 +0200354 struct mgmt_cp_set_discoverable *cp;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200355 struct hci_dev *hdev;
Johan Hedberg366a0332011-02-19 12:05:55 -0300356 struct pending_cmd *cmd;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200357 u8 scan;
358 int err;
359
360 cp = (void *) data;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200361
Szymon Janc4e51eae2011-02-25 19:05:48 +0100362 BT_DBG("request for hci%u", index);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200363
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100364 if (len != sizeof(*cp))
365 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, EINVAL);
366
Szymon Janc4e51eae2011-02-25 19:05:48 +0100367 hdev = hci_dev_get(index);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200368 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100369 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, ENODEV);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200370
Andre Guedes8c156c32011-07-07 10:30:36 -0300371 hci_dev_lock_bh(hdev);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200372
373 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100374 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, ENETDOWN);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200375 goto failed;
376 }
377
Johan Hedberg2e58ef32011-11-08 20:40:15 +0200378 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
379 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100380 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, EBUSY);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200381 goto failed;
382 }
383
Johan Hedberg72a734e2010-12-30 00:38:22 +0200384 if (cp->val == test_bit(HCI_ISCAN, &hdev->flags) &&
Johan Hedberg73f22f62010-12-29 16:00:25 +0200385 test_bit(HCI_PSCAN, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100386 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, EALREADY);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200387 goto failed;
388 }
389
Johan Hedberg2e58ef32011-11-08 20:40:15 +0200390 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -0300391 if (!cmd) {
392 err = -ENOMEM;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200393 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -0300394 }
Johan Hedberg73f22f62010-12-29 16:00:25 +0200395
396 scan = SCAN_PAGE;
397
Johan Hedberg72a734e2010-12-30 00:38:22 +0200398 if (cp->val)
Johan Hedberg73f22f62010-12-29 16:00:25 +0200399 scan |= SCAN_INQUIRY;
Johan Hedberg16ab91a2011-11-07 22:16:02 +0200400 else
401 cancel_delayed_work_sync(&hdev->discov_off);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200402
403 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
404 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -0300405 mgmt_pending_remove(cmd);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200406
Johan Hedberg16ab91a2011-11-07 22:16:02 +0200407 if (cp->val)
408 hdev->discov_timeout = get_unaligned_le16(&cp->timeout);
409
Johan Hedberg73f22f62010-12-29 16:00:25 +0200410failed:
Andre Guedes8c156c32011-07-07 10:30:36 -0300411 hci_dev_unlock_bh(hdev);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200412 hci_dev_put(hdev);
413
414 return err;
415}
416
Szymon Janc4e51eae2011-02-25 19:05:48 +0100417static int set_connectable(struct sock *sk, u16 index, unsigned char *data,
418 u16 len)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200419{
Johan Hedberg72a734e2010-12-30 00:38:22 +0200420 struct mgmt_mode *cp;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200421 struct hci_dev *hdev;
Johan Hedberg366a0332011-02-19 12:05:55 -0300422 struct pending_cmd *cmd;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200423 u8 scan;
424 int err;
425
426 cp = (void *) data;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200427
Szymon Janc4e51eae2011-02-25 19:05:48 +0100428 BT_DBG("request for hci%u", index);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200429
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100430 if (len != sizeof(*cp))
431 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, EINVAL);
432
Szymon Janc4e51eae2011-02-25 19:05:48 +0100433 hdev = hci_dev_get(index);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200434 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100435 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, ENODEV);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200436
Andre Guedes8c156c32011-07-07 10:30:36 -0300437 hci_dev_lock_bh(hdev);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200438
439 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100440 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, ENETDOWN);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200441 goto failed;
442 }
443
Johan Hedberg2e58ef32011-11-08 20:40:15 +0200444 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
445 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100446 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, EBUSY);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200447 goto failed;
448 }
449
Johan Hedberg72a734e2010-12-30 00:38:22 +0200450 if (cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100451 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, EALREADY);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200452 goto failed;
453 }
454
Johan Hedberg2e58ef32011-11-08 20:40:15 +0200455 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -0300456 if (!cmd) {
457 err = -ENOMEM;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200458 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -0300459 }
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200460
Johan Hedberg72a734e2010-12-30 00:38:22 +0200461 if (cp->val)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200462 scan = SCAN_PAGE;
463 else
464 scan = 0;
465
466 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
467 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -0300468 mgmt_pending_remove(cmd);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200469
470failed:
Andre Guedes8c156c32011-07-07 10:30:36 -0300471 hci_dev_unlock_bh(hdev);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200472 hci_dev_put(hdev);
473
474 return err;
475}
476
Johan Hedberg744cf192011-11-08 20:40:14 +0200477static int mgmt_event(u16 event, struct hci_dev *hdev, void *data,
478 u16 data_len, struct sock *skip_sk)
Johan Hedbergc542a062011-01-26 13:11:03 +0200479{
480 struct sk_buff *skb;
481 struct mgmt_hdr *hdr;
482
483 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_ATOMIC);
484 if (!skb)
485 return -ENOMEM;
486
487 bt_cb(skb)->channel = HCI_CHANNEL_CONTROL;
488
489 hdr = (void *) skb_put(skb, sizeof(*hdr));
490 hdr->opcode = cpu_to_le16(event);
Johan Hedberg744cf192011-11-08 20:40:14 +0200491 if (hdev)
492 hdr->index = cpu_to_le16(hdev->id);
493 else
494 hdr->index = cpu_to_le16(MGMT_INDEX_NONE);
Johan Hedbergc542a062011-01-26 13:11:03 +0200495 hdr->len = cpu_to_le16(data_len);
496
Szymon Janc4e51eae2011-02-25 19:05:48 +0100497 if (data)
498 memcpy(skb_put(skb, data_len), data, data_len);
Johan Hedbergc542a062011-01-26 13:11:03 +0200499
500 hci_send_to_sock(NULL, skb, skip_sk);
501 kfree_skb(skb);
502
503 return 0;
504}
505
Johan Hedberg053f0212011-01-26 13:07:10 +0200506static int send_mode_rsp(struct sock *sk, u16 opcode, u16 index, u8 val)
507{
Johan Hedberga38528f2011-01-22 06:46:43 +0200508 struct mgmt_mode rp;
Johan Hedberg053f0212011-01-26 13:07:10 +0200509
Johan Hedberga38528f2011-01-22 06:46:43 +0200510 rp.val = val;
Johan Hedberg053f0212011-01-26 13:07:10 +0200511
Szymon Janc4e51eae2011-02-25 19:05:48 +0100512 return cmd_complete(sk, index, opcode, &rp, sizeof(rp));
Johan Hedberg053f0212011-01-26 13:07:10 +0200513}
514
Szymon Janc4e51eae2011-02-25 19:05:48 +0100515static int set_pairable(struct sock *sk, u16 index, unsigned char *data,
516 u16 len)
Johan Hedbergc542a062011-01-26 13:11:03 +0200517{
518 struct mgmt_mode *cp, ev;
519 struct hci_dev *hdev;
Johan Hedbergc542a062011-01-26 13:11:03 +0200520 int err;
521
522 cp = (void *) data;
Johan Hedbergc542a062011-01-26 13:11:03 +0200523
Szymon Janc4e51eae2011-02-25 19:05:48 +0100524 BT_DBG("request for hci%u", index);
Johan Hedbergc542a062011-01-26 13:11:03 +0200525
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100526 if (len != sizeof(*cp))
527 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE, EINVAL);
528
Szymon Janc4e51eae2011-02-25 19:05:48 +0100529 hdev = hci_dev_get(index);
Johan Hedbergc542a062011-01-26 13:11:03 +0200530 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100531 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE, ENODEV);
Johan Hedbergc542a062011-01-26 13:11:03 +0200532
Andre Guedes8c156c32011-07-07 10:30:36 -0300533 hci_dev_lock_bh(hdev);
Johan Hedbergc542a062011-01-26 13:11:03 +0200534
535 if (cp->val)
536 set_bit(HCI_PAIRABLE, &hdev->flags);
537 else
538 clear_bit(HCI_PAIRABLE, &hdev->flags);
539
Szymon Janc4e51eae2011-02-25 19:05:48 +0100540 err = send_mode_rsp(sk, MGMT_OP_SET_PAIRABLE, index, cp->val);
Johan Hedbergc542a062011-01-26 13:11:03 +0200541 if (err < 0)
542 goto failed;
543
Johan Hedbergc542a062011-01-26 13:11:03 +0200544 ev.val = cp->val;
545
Johan Hedberg744cf192011-11-08 20:40:14 +0200546 err = mgmt_event(MGMT_EV_PAIRABLE, hdev, &ev, sizeof(ev), sk);
Johan Hedbergc542a062011-01-26 13:11:03 +0200547
548failed:
Andre Guedes8c156c32011-07-07 10:30:36 -0300549 hci_dev_unlock_bh(hdev);
Johan Hedbergc542a062011-01-26 13:11:03 +0200550 hci_dev_put(hdev);
551
552 return err;
553}
554
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300555#define EIR_FLAGS 0x01 /* flags */
556#define EIR_UUID16_SOME 0x02 /* 16-bit UUID, more available */
557#define EIR_UUID16_ALL 0x03 /* 16-bit UUID, all listed */
558#define EIR_UUID32_SOME 0x04 /* 32-bit UUID, more available */
559#define EIR_UUID32_ALL 0x05 /* 32-bit UUID, all listed */
560#define EIR_UUID128_SOME 0x06 /* 128-bit UUID, more available */
561#define EIR_UUID128_ALL 0x07 /* 128-bit UUID, all listed */
562#define EIR_NAME_SHORT 0x08 /* shortened local name */
563#define EIR_NAME_COMPLETE 0x09 /* complete local name */
564#define EIR_TX_POWER 0x0A /* transmit power level */
565#define EIR_DEVICE_ID 0x10 /* device ID */
566
567#define PNP_INFO_SVCLASS_ID 0x1200
568
569static u8 bluetooth_base_uuid[] = {
570 0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80,
571 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
572};
573
574static u16 get_uuid16(u8 *uuid128)
575{
576 u32 val;
577 int i;
578
579 for (i = 0; i < 12; i++) {
580 if (bluetooth_base_uuid[i] != uuid128[i])
581 return 0;
582 }
583
584 memcpy(&val, &uuid128[12], 4);
585
586 val = le32_to_cpu(val);
587 if (val > 0xffff)
588 return 0;
589
590 return (u16) val;
591}
592
593static void create_eir(struct hci_dev *hdev, u8 *data)
594{
595 u8 *ptr = data;
596 u16 eir_len = 0;
597 u16 uuid16_list[HCI_MAX_EIR_LENGTH / sizeof(u16)];
598 int i, truncated = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200599 struct bt_uuid *uuid;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300600 size_t name_len;
601
602 name_len = strlen(hdev->dev_name);
603
604 if (name_len > 0) {
605 /* EIR Data type */
606 if (name_len > 48) {
607 name_len = 48;
608 ptr[1] = EIR_NAME_SHORT;
609 } else
610 ptr[1] = EIR_NAME_COMPLETE;
611
612 /* EIR Data length */
613 ptr[0] = name_len + 1;
614
615 memcpy(ptr + 2, hdev->dev_name, name_len);
616
617 eir_len += (name_len + 2);
618 ptr += (name_len + 2);
619 }
620
621 memset(uuid16_list, 0, sizeof(uuid16_list));
622
623 /* Group all UUID16 types */
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200624 list_for_each_entry(uuid, &hdev->uuids, list) {
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300625 u16 uuid16;
626
627 uuid16 = get_uuid16(uuid->uuid);
628 if (uuid16 == 0)
629 return;
630
631 if (uuid16 < 0x1100)
632 continue;
633
634 if (uuid16 == PNP_INFO_SVCLASS_ID)
635 continue;
636
637 /* Stop if not enough space to put next UUID */
638 if (eir_len + 2 + sizeof(u16) > HCI_MAX_EIR_LENGTH) {
639 truncated = 1;
640 break;
641 }
642
643 /* Check for duplicates */
644 for (i = 0; uuid16_list[i] != 0; i++)
645 if (uuid16_list[i] == uuid16)
646 break;
647
648 if (uuid16_list[i] == 0) {
649 uuid16_list[i] = uuid16;
650 eir_len += sizeof(u16);
651 }
652 }
653
654 if (uuid16_list[0] != 0) {
655 u8 *length = ptr;
656
657 /* EIR Data type */
658 ptr[1] = truncated ? EIR_UUID16_SOME : EIR_UUID16_ALL;
659
660 ptr += 2;
661 eir_len += 2;
662
663 for (i = 0; uuid16_list[i] != 0; i++) {
664 *ptr++ = (uuid16_list[i] & 0x00ff);
665 *ptr++ = (uuid16_list[i] & 0xff00) >> 8;
666 }
667
668 /* EIR Data length */
669 *length = (i * sizeof(u16)) + 1;
670 }
671}
672
673static int update_eir(struct hci_dev *hdev)
674{
675 struct hci_cp_write_eir cp;
676
677 if (!(hdev->features[6] & LMP_EXT_INQ))
678 return 0;
679
680 if (hdev->ssp_mode == 0)
681 return 0;
682
683 if (test_bit(HCI_SERVICE_CACHE, &hdev->flags))
684 return 0;
685
686 memset(&cp, 0, sizeof(cp));
687
688 create_eir(hdev, cp.data);
689
690 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
691 return 0;
692
693 memcpy(hdev->eir, cp.data, sizeof(cp.data));
694
695 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
696}
697
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200698static u8 get_service_classes(struct hci_dev *hdev)
699{
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300700 struct bt_uuid *uuid;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200701 u8 val = 0;
702
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300703 list_for_each_entry(uuid, &hdev->uuids, list)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200704 val |= uuid->svc_hint;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200705
706 return val;
707}
708
709static int update_class(struct hci_dev *hdev)
710{
711 u8 cod[3];
712
713 BT_DBG("%s", hdev->name);
714
715 if (test_bit(HCI_SERVICE_CACHE, &hdev->flags))
716 return 0;
717
718 cod[0] = hdev->minor_class;
719 cod[1] = hdev->major_class;
720 cod[2] = get_service_classes(hdev);
721
722 if (memcmp(cod, hdev->dev_class, 3) == 0)
723 return 0;
724
725 return hci_send_cmd(hdev, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
726}
727
Szymon Janc4e51eae2011-02-25 19:05:48 +0100728static int add_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200729{
730 struct mgmt_cp_add_uuid *cp;
731 struct hci_dev *hdev;
732 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200733 int err;
734
735 cp = (void *) data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200736
Szymon Janc4e51eae2011-02-25 19:05:48 +0100737 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200738
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100739 if (len != sizeof(*cp))
740 return cmd_status(sk, index, MGMT_OP_ADD_UUID, EINVAL);
741
Szymon Janc4e51eae2011-02-25 19:05:48 +0100742 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200743 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100744 return cmd_status(sk, index, MGMT_OP_ADD_UUID, ENODEV);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200745
Andre Guedes8c156c32011-07-07 10:30:36 -0300746 hci_dev_lock_bh(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200747
748 uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC);
749 if (!uuid) {
750 err = -ENOMEM;
751 goto failed;
752 }
753
754 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200755 uuid->svc_hint = cp->svc_hint;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200756
757 list_add(&uuid->list, &hdev->uuids);
758
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200759 err = update_class(hdev);
760 if (err < 0)
761 goto failed;
762
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300763 err = update_eir(hdev);
764 if (err < 0)
765 goto failed;
766
Szymon Janc4e51eae2011-02-25 19:05:48 +0100767 err = cmd_complete(sk, index, MGMT_OP_ADD_UUID, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200768
769failed:
Andre Guedes8c156c32011-07-07 10:30:36 -0300770 hci_dev_unlock_bh(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200771 hci_dev_put(hdev);
772
773 return err;
774}
775
Szymon Janc4e51eae2011-02-25 19:05:48 +0100776static int remove_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200777{
778 struct list_head *p, *n;
Szymon Janc779cb852011-02-25 19:05:47 +0100779 struct mgmt_cp_remove_uuid *cp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200780 struct hci_dev *hdev;
781 u8 bt_uuid_any[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200782 int err, found;
783
784 cp = (void *) data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200785
Szymon Janc4e51eae2011-02-25 19:05:48 +0100786 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200787
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100788 if (len != sizeof(*cp))
789 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID, EINVAL);
790
Szymon Janc4e51eae2011-02-25 19:05:48 +0100791 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200792 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100793 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID, ENODEV);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200794
Andre Guedes8c156c32011-07-07 10:30:36 -0300795 hci_dev_lock_bh(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200796
797 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
798 err = hci_uuids_clear(hdev);
799 goto unlock;
800 }
801
802 found = 0;
803
804 list_for_each_safe(p, n, &hdev->uuids) {
805 struct bt_uuid *match = list_entry(p, struct bt_uuid, list);
806
807 if (memcmp(match->uuid, cp->uuid, 16) != 0)
808 continue;
809
810 list_del(&match->list);
811 found++;
812 }
813
814 if (found == 0) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100815 err = cmd_status(sk, index, MGMT_OP_REMOVE_UUID, ENOENT);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200816 goto unlock;
817 }
818
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200819 err = update_class(hdev);
820 if (err < 0)
821 goto unlock;
822
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300823 err = update_eir(hdev);
824 if (err < 0)
825 goto unlock;
826
Szymon Janc4e51eae2011-02-25 19:05:48 +0100827 err = cmd_complete(sk, index, MGMT_OP_REMOVE_UUID, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200828
829unlock:
Andre Guedes8c156c32011-07-07 10:30:36 -0300830 hci_dev_unlock_bh(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200831 hci_dev_put(hdev);
832
833 return err;
834}
835
Szymon Janc4e51eae2011-02-25 19:05:48 +0100836static int set_dev_class(struct sock *sk, u16 index, unsigned char *data,
837 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200838{
839 struct hci_dev *hdev;
840 struct mgmt_cp_set_dev_class *cp;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200841 int err;
842
843 cp = (void *) data;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200844
Szymon Janc4e51eae2011-02-25 19:05:48 +0100845 BT_DBG("request for hci%u", index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200846
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100847 if (len != sizeof(*cp))
848 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS, EINVAL);
849
Szymon Janc4e51eae2011-02-25 19:05:48 +0100850 hdev = hci_dev_get(index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200851 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100852 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS, ENODEV);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200853
Andre Guedes8c156c32011-07-07 10:30:36 -0300854 hci_dev_lock_bh(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200855
856 hdev->major_class = cp->major;
857 hdev->minor_class = cp->minor;
858
859 err = update_class(hdev);
860
861 if (err == 0)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100862 err = cmd_complete(sk, index, MGMT_OP_SET_DEV_CLASS, NULL, 0);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200863
Andre Guedes8c156c32011-07-07 10:30:36 -0300864 hci_dev_unlock_bh(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200865 hci_dev_put(hdev);
866
867 return err;
868}
869
Szymon Janc4e51eae2011-02-25 19:05:48 +0100870static int set_service_cache(struct sock *sk, u16 index, unsigned char *data,
871 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200872{
873 struct hci_dev *hdev;
874 struct mgmt_cp_set_service_cache *cp;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200875 int err;
876
877 cp = (void *) data;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200878
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100879 if (len != sizeof(*cp))
Szymon Jancb8534e0f2011-03-01 16:55:34 +0100880 return cmd_status(sk, index, MGMT_OP_SET_SERVICE_CACHE, EINVAL);
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100881
Szymon Janc4e51eae2011-02-25 19:05:48 +0100882 hdev = hci_dev_get(index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200883 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100884 return cmd_status(sk, index, MGMT_OP_SET_SERVICE_CACHE, ENODEV);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200885
Andre Guedes8c156c32011-07-07 10:30:36 -0300886 hci_dev_lock_bh(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200887
Szymon Janc4e51eae2011-02-25 19:05:48 +0100888 BT_DBG("hci%u enable %d", index, cp->enable);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200889
890 if (cp->enable) {
891 set_bit(HCI_SERVICE_CACHE, &hdev->flags);
892 err = 0;
893 } else {
894 clear_bit(HCI_SERVICE_CACHE, &hdev->flags);
895 err = update_class(hdev);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300896 if (err == 0)
897 err = update_eir(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200898 }
899
900 if (err == 0)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100901 err = cmd_complete(sk, index, MGMT_OP_SET_SERVICE_CACHE, NULL,
902 0);
Gustavo F. Padovane5b82e52011-10-15 18:03:15 -0300903 else
904 cmd_status(sk, index, MGMT_OP_SET_SERVICE_CACHE, -err);
905
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200906
Andre Guedes8c156c32011-07-07 10:30:36 -0300907 hci_dev_unlock_bh(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200908 hci_dev_put(hdev);
909
910 return err;
911}
912
Johan Hedberg86742e12011-11-07 23:13:38 +0200913static int load_link_keys(struct sock *sk, u16 index, unsigned char *data,
914 u16 len)
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200915{
916 struct hci_dev *hdev;
Johan Hedberg86742e12011-11-07 23:13:38 +0200917 struct mgmt_cp_load_link_keys *cp;
Szymon Janc4e51eae2011-02-25 19:05:48 +0100918 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -0300919 int i;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200920
921 cp = (void *) data;
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100922
923 if (len < sizeof(*cp))
Johan Hedberg86742e12011-11-07 23:13:38 +0200924 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS, EINVAL);
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100925
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200926 key_count = get_unaligned_le16(&cp->key_count);
927
Johan Hedberg86742e12011-11-07 23:13:38 +0200928 expected_len = sizeof(*cp) + key_count *
929 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -0300930 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +0200931 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -0300932 len, expected_len);
Johan Hedberg86742e12011-11-07 23:13:38 +0200933 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS, EINVAL);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200934 }
935
Szymon Janc4e51eae2011-02-25 19:05:48 +0100936 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200937 if (!hdev)
Johan Hedberg86742e12011-11-07 23:13:38 +0200938 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS, ENODEV);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200939
Szymon Janc4e51eae2011-02-25 19:05:48 +0100940 BT_DBG("hci%u debug_keys %u key_count %u", index, cp->debug_keys,
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200941 key_count);
942
Andre Guedes8c156c32011-07-07 10:30:36 -0300943 hci_dev_lock_bh(hdev);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200944
945 hci_link_keys_clear(hdev);
946
947 set_bit(HCI_LINK_KEYS, &hdev->flags);
948
949 if (cp->debug_keys)
950 set_bit(HCI_DEBUG_KEYS, &hdev->flags);
951 else
952 clear_bit(HCI_DEBUG_KEYS, &hdev->flags);
953
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -0300954 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +0200955 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200956
Johan Hedbergd25e28a2011-04-28 11:28:59 -0700957 hci_add_link_key(hdev, NULL, 0, &key->bdaddr, key->val, key->type,
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200958 key->pin_len);
959 }
960
Andre Guedes8c156c32011-07-07 10:30:36 -0300961 hci_dev_unlock_bh(hdev);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200962 hci_dev_put(hdev);
963
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -0300964 return 0;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200965}
966
Johan Hedberg86742e12011-11-07 23:13:38 +0200967static int remove_keys(struct sock *sk, u16 index, unsigned char *data,
968 u16 len)
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200969{
970 struct hci_dev *hdev;
Johan Hedberg86742e12011-11-07 23:13:38 +0200971 struct mgmt_cp_remove_keys *cp;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200972 struct hci_conn *conn;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200973 int err;
974
975 cp = (void *) data;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200976
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100977 if (len != sizeof(*cp))
Johan Hedberg86742e12011-11-07 23:13:38 +0200978 return cmd_status(sk, index, MGMT_OP_REMOVE_KEYS, EINVAL);
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100979
Szymon Janc4e51eae2011-02-25 19:05:48 +0100980 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200981 if (!hdev)
Johan Hedberg86742e12011-11-07 23:13:38 +0200982 return cmd_status(sk, index, MGMT_OP_REMOVE_KEYS, ENODEV);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200983
Andre Guedes8c156c32011-07-07 10:30:36 -0300984 hci_dev_lock_bh(hdev);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200985
986 err = hci_remove_link_key(hdev, &cp->bdaddr);
987 if (err < 0) {
Johan Hedberg86742e12011-11-07 23:13:38 +0200988 err = cmd_status(sk, index, MGMT_OP_REMOVE_KEYS, -err);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200989 goto unlock;
990 }
991
992 err = 0;
993
994 if (!test_bit(HCI_UP, &hdev->flags) || !cp->disconnect)
995 goto unlock;
996
997 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
998 if (conn) {
999 struct hci_cp_disconnect dc;
1000
1001 put_unaligned_le16(conn->handle, &dc.handle);
1002 dc.reason = 0x13; /* Remote User Terminated Connection */
Anderson Lizardo94ac0272011-06-13 15:42:03 -04001003 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001004 }
1005
1006unlock:
Andre Guedes8c156c32011-07-07 10:30:36 -03001007 hci_dev_unlock_bh(hdev);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001008 hci_dev_put(hdev);
1009
1010 return err;
1011}
1012
Szymon Janc4e51eae2011-02-25 19:05:48 +01001013static int disconnect(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02001014{
1015 struct hci_dev *hdev;
1016 struct mgmt_cp_disconnect *cp;
1017 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03001018 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001019 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001020 int err;
1021
1022 BT_DBG("");
1023
1024 cp = (void *) data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001025
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001026 if (len != sizeof(*cp))
1027 return cmd_status(sk, index, MGMT_OP_DISCONNECT, EINVAL);
1028
Szymon Janc4e51eae2011-02-25 19:05:48 +01001029 hdev = hci_dev_get(index);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001030 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001031 return cmd_status(sk, index, MGMT_OP_DISCONNECT, ENODEV);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001032
Andre Guedes8c156c32011-07-07 10:30:36 -03001033 hci_dev_lock_bh(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001034
1035 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001036 err = cmd_status(sk, index, MGMT_OP_DISCONNECT, ENETDOWN);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001037 goto failed;
1038 }
1039
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001040 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001041 err = cmd_status(sk, index, MGMT_OP_DISCONNECT, EBUSY);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001042 goto failed;
1043 }
1044
1045 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03001046 if (!conn)
1047 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->bdaddr);
1048
Johan Hedberg8962ee72011-01-20 12:40:27 +02001049 if (!conn) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001050 err = cmd_status(sk, index, MGMT_OP_DISCONNECT, ENOTCONN);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001051 goto failed;
1052 }
1053
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001054 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001055 if (!cmd) {
1056 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001057 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001058 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001059
1060 put_unaligned_le16(conn->handle, &dc.handle);
1061 dc.reason = 0x13; /* Remote User Terminated Connection */
1062
1063 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1064 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001065 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001066
1067failed:
Andre Guedes8c156c32011-07-07 10:30:36 -03001068 hci_dev_unlock_bh(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001069 hci_dev_put(hdev);
1070
1071 return err;
1072}
1073
Johan Hedberg4c659c32011-11-07 23:13:39 +02001074static u8 link_to_mgmt(u8 link_type)
1075{
1076 switch (link_type) {
1077 case LE_LINK:
1078 return MGMT_ADDR_LE;
1079 case ACL_LINK:
1080 return MGMT_ADDR_BREDR;
1081 default:
1082 return MGMT_ADDR_INVALID;
1083 }
1084}
1085
Szymon Janc8ce62842011-03-01 16:55:32 +01001086static int get_connections(struct sock *sk, u16 index)
Johan Hedberg2784eb42011-01-21 13:56:35 +02001087{
Johan Hedberg2784eb42011-01-21 13:56:35 +02001088 struct mgmt_rp_get_connections *rp;
1089 struct hci_dev *hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001090 struct hci_conn *c;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001091 struct list_head *p;
Johan Hedberga38528f2011-01-22 06:46:43 +02001092 size_t rp_len;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001093 u16 count;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001094 int i, err;
1095
1096 BT_DBG("");
1097
Szymon Janc4e51eae2011-02-25 19:05:48 +01001098 hdev = hci_dev_get(index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001099 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001100 return cmd_status(sk, index, MGMT_OP_GET_CONNECTIONS, ENODEV);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001101
Andre Guedes8c156c32011-07-07 10:30:36 -03001102 hci_dev_lock_bh(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001103
1104 count = 0;
1105 list_for_each(p, &hdev->conn_hash.list) {
1106 count++;
1107 }
1108
Johan Hedberg4c659c32011-11-07 23:13:39 +02001109 rp_len = sizeof(*rp) + (count * sizeof(struct mgmt_addr_info));
Johan Hedberga38528f2011-01-22 06:46:43 +02001110 rp = kmalloc(rp_len, GFP_ATOMIC);
1111 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02001112 err = -ENOMEM;
1113 goto unlock;
1114 }
1115
Johan Hedberg2784eb42011-01-21 13:56:35 +02001116 put_unaligned_le16(count, &rp->conn_count);
1117
Johan Hedberg2784eb42011-01-21 13:56:35 +02001118 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001119 list_for_each_entry(c, &hdev->conn_hash.list, list) {
1120 bacpy(&rp->addr[i].bdaddr, &c->dst);
1121 rp->addr[i].type = link_to_mgmt(c->type);
1122 if (rp->addr[i].type == MGMT_ADDR_INVALID)
1123 continue;
1124 i++;
1125 }
1126
1127 /* Recalculate length in case of filtered SCO connections, etc */
1128 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02001129
Szymon Janc4e51eae2011-02-25 19:05:48 +01001130 err = cmd_complete(sk, index, MGMT_OP_GET_CONNECTIONS, rp, rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001131
1132unlock:
Johan Hedberga38528f2011-01-22 06:46:43 +02001133 kfree(rp);
Andre Guedes8c156c32011-07-07 10:30:36 -03001134 hci_dev_unlock_bh(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001135 hci_dev_put(hdev);
1136 return err;
1137}
1138
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001139static int send_pin_code_neg_reply(struct sock *sk, u16 index,
1140 struct hci_dev *hdev, struct mgmt_cp_pin_code_neg_reply *cp)
1141{
1142 struct pending_cmd *cmd;
1143 int err;
1144
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001145 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001146 sizeof(*cp));
1147 if (!cmd)
1148 return -ENOMEM;
1149
1150 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY, sizeof(cp->bdaddr),
1151 &cp->bdaddr);
1152 if (err < 0)
1153 mgmt_pending_remove(cmd);
1154
1155 return err;
1156}
1157
Szymon Janc4e51eae2011-02-25 19:05:48 +01001158static int pin_code_reply(struct sock *sk, u16 index, unsigned char *data,
1159 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001160{
1161 struct hci_dev *hdev;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001162 struct hci_conn *conn;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001163 struct mgmt_cp_pin_code_reply *cp;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001164 struct mgmt_cp_pin_code_neg_reply ncp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001165 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03001166 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001167 int err;
1168
1169 BT_DBG("");
1170
1171 cp = (void *) data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001172
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001173 if (len != sizeof(*cp))
1174 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, EINVAL);
1175
Szymon Janc4e51eae2011-02-25 19:05:48 +01001176 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001177 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001178 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENODEV);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001179
Andre Guedes8c156c32011-07-07 10:30:36 -03001180 hci_dev_lock_bh(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001181
1182 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001183 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENETDOWN);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001184 goto failed;
1185 }
1186
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001187 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
1188 if (!conn) {
1189 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENOTCONN);
1190 goto failed;
1191 }
1192
1193 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
1194 bacpy(&ncp.bdaddr, &cp->bdaddr);
1195
1196 BT_ERR("PIN code is not 16 bytes long");
1197
1198 err = send_pin_code_neg_reply(sk, index, hdev, &ncp);
1199 if (err >= 0)
1200 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1201 EINVAL);
1202
1203 goto failed;
1204 }
1205
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001206 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001207 if (!cmd) {
1208 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001209 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001210 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02001211
1212 bacpy(&reply.bdaddr, &cp->bdaddr);
1213 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02001214 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02001215
1216 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
1217 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001218 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001219
1220failed:
Andre Guedes8c156c32011-07-07 10:30:36 -03001221 hci_dev_unlock_bh(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001222 hci_dev_put(hdev);
1223
1224 return err;
1225}
1226
Szymon Janc4e51eae2011-02-25 19:05:48 +01001227static int pin_code_neg_reply(struct sock *sk, u16 index, unsigned char *data,
1228 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001229{
1230 struct hci_dev *hdev;
1231 struct mgmt_cp_pin_code_neg_reply *cp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001232 int err;
1233
1234 BT_DBG("");
1235
1236 cp = (void *) data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001237
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001238 if (len != sizeof(*cp))
1239 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1240 EINVAL);
1241
Szymon Janc4e51eae2011-02-25 19:05:48 +01001242 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001243 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001244 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1245 ENODEV);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001246
Andre Guedes8c156c32011-07-07 10:30:36 -03001247 hci_dev_lock_bh(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001248
1249 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001250 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1251 ENETDOWN);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001252 goto failed;
1253 }
1254
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001255 err = send_pin_code_neg_reply(sk, index, hdev, cp);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001256
1257failed:
Andre Guedes8c156c32011-07-07 10:30:36 -03001258 hci_dev_unlock_bh(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001259 hci_dev_put(hdev);
1260
1261 return err;
1262}
1263
Szymon Janc4e51eae2011-02-25 19:05:48 +01001264static int set_io_capability(struct sock *sk, u16 index, unsigned char *data,
1265 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001266{
1267 struct hci_dev *hdev;
1268 struct mgmt_cp_set_io_capability *cp;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001269
1270 BT_DBG("");
1271
1272 cp = (void *) data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001273
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001274 if (len != sizeof(*cp))
Szymon Jancb8534e0f2011-03-01 16:55:34 +01001275 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY, EINVAL);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001276
Szymon Janc4e51eae2011-02-25 19:05:48 +01001277 hdev = hci_dev_get(index);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001278 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001279 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY, ENODEV);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001280
Andre Guedes8c156c32011-07-07 10:30:36 -03001281 hci_dev_lock_bh(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001282
1283 hdev->io_capability = cp->io_capability;
1284
1285 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Szymon Jancb8534e0f2011-03-01 16:55:34 +01001286 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001287
Andre Guedes8c156c32011-07-07 10:30:36 -03001288 hci_dev_unlock_bh(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001289 hci_dev_put(hdev);
1290
Szymon Janc4e51eae2011-02-25 19:05:48 +01001291 return cmd_complete(sk, index, MGMT_OP_SET_IO_CAPABILITY, NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001292}
1293
Johan Hedberge9a416b2011-02-19 12:05:56 -03001294static inline struct pending_cmd *find_pairing(struct hci_conn *conn)
1295{
1296 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001297 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001298
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001299 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03001300 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
1301 continue;
1302
1303 if (cmd->index != hdev->id)
1304 continue;
1305
1306 if (cmd->user_data != conn)
1307 continue;
1308
1309 return cmd;
1310 }
1311
1312 return NULL;
1313}
1314
1315static void pairing_complete(struct pending_cmd *cmd, u8 status)
1316{
1317 struct mgmt_rp_pair_device rp;
1318 struct hci_conn *conn = cmd->user_data;
1319
Johan Hedberge9a416b2011-02-19 12:05:56 -03001320 bacpy(&rp.bdaddr, &conn->dst);
1321 rp.status = status;
1322
Szymon Janc4e51eae2011-02-25 19:05:48 +01001323 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001324
1325 /* So we don't get further callbacks for this connection */
1326 conn->connect_cfm_cb = NULL;
1327 conn->security_cfm_cb = NULL;
1328 conn->disconn_cfm_cb = NULL;
1329
1330 hci_conn_put(conn);
1331
Johan Hedberga664b5b2011-02-19 12:06:02 -03001332 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001333}
1334
1335static void pairing_complete_cb(struct hci_conn *conn, u8 status)
1336{
1337 struct pending_cmd *cmd;
1338
1339 BT_DBG("status %u", status);
1340
1341 cmd = find_pairing(conn);
1342 if (!cmd) {
1343 BT_DBG("Unable to find a pending command");
1344 return;
1345 }
1346
1347 pairing_complete(cmd, status);
1348}
1349
Szymon Janc4e51eae2011-02-25 19:05:48 +01001350static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001351{
1352 struct hci_dev *hdev;
1353 struct mgmt_cp_pair_device *cp;
1354 struct pending_cmd *cmd;
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001355 struct adv_entry *entry;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001356 u8 sec_level, auth_type;
1357 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001358 int err;
1359
1360 BT_DBG("");
1361
1362 cp = (void *) data;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001363
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001364 if (len != sizeof(*cp))
1365 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, EINVAL);
1366
Szymon Janc4e51eae2011-02-25 19:05:48 +01001367 hdev = hci_dev_get(index);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001368 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001369 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, ENODEV);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001370
Andre Guedes8c156c32011-07-07 10:30:36 -03001371 hci_dev_lock_bh(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001372
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001373 sec_level = BT_SECURITY_MEDIUM;
1374 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001375 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001376 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03001377 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001378
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001379 entry = hci_find_adv_entry(hdev, &cp->bdaddr);
1380 if (entry)
1381 conn = hci_connect(hdev, LE_LINK, &cp->bdaddr, sec_level,
1382 auth_type);
1383 else
1384 conn = hci_connect(hdev, ACL_LINK, &cp->bdaddr, sec_level,
1385 auth_type);
1386
Ville Tervo30e76272011-02-22 16:10:53 -03001387 if (IS_ERR(conn)) {
1388 err = PTR_ERR(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001389 goto unlock;
1390 }
1391
1392 if (conn->connect_cfm_cb) {
1393 hci_conn_put(conn);
Szymon Janc4e51eae2011-02-25 19:05:48 +01001394 err = cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, EBUSY);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001395 goto unlock;
1396 }
1397
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001398 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001399 if (!cmd) {
1400 err = -ENOMEM;
1401 hci_conn_put(conn);
1402 goto unlock;
1403 }
1404
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001405 /* For LE, just connecting isn't a proof that the pairing finished */
1406 if (!entry)
1407 conn->connect_cfm_cb = pairing_complete_cb;
1408
Johan Hedberge9a416b2011-02-19 12:05:56 -03001409 conn->security_cfm_cb = pairing_complete_cb;
1410 conn->disconn_cfm_cb = pairing_complete_cb;
1411 conn->io_capability = cp->io_cap;
1412 cmd->user_data = conn;
1413
1414 if (conn->state == BT_CONNECTED &&
1415 hci_conn_security(conn, sec_level, auth_type))
1416 pairing_complete(cmd, 0);
1417
1418 err = 0;
1419
1420unlock:
Andre Guedes8c156c32011-07-07 10:30:36 -03001421 hci_dev_unlock_bh(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001422 hci_dev_put(hdev);
1423
1424 return err;
1425}
1426
Szymon Janc4e51eae2011-02-25 19:05:48 +01001427static int user_confirm_reply(struct sock *sk, u16 index, unsigned char *data,
1428 u16 len, int success)
Johan Hedberga5c29682011-02-19 12:05:57 -03001429{
1430 struct mgmt_cp_user_confirm_reply *cp = (void *) data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001431 u16 mgmt_op, hci_op;
Johan Hedberga5c29682011-02-19 12:05:57 -03001432 struct pending_cmd *cmd;
1433 struct hci_dev *hdev;
1434 int err;
1435
1436 BT_DBG("");
1437
Johan Hedberga5c29682011-02-19 12:05:57 -03001438 if (success) {
1439 mgmt_op = MGMT_OP_USER_CONFIRM_REPLY;
1440 hci_op = HCI_OP_USER_CONFIRM_REPLY;
1441 } else {
1442 mgmt_op = MGMT_OP_USER_CONFIRM_NEG_REPLY;
1443 hci_op = HCI_OP_USER_CONFIRM_NEG_REPLY;
1444 }
1445
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001446 if (len != sizeof(*cp))
1447 return cmd_status(sk, index, mgmt_op, EINVAL);
1448
Szymon Janc4e51eae2011-02-25 19:05:48 +01001449 hdev = hci_dev_get(index);
Johan Hedberga5c29682011-02-19 12:05:57 -03001450 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001451 return cmd_status(sk, index, mgmt_op, ENODEV);
Johan Hedberga5c29682011-02-19 12:05:57 -03001452
Andre Guedes8c156c32011-07-07 10:30:36 -03001453 hci_dev_lock_bh(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02001454
Johan Hedberga5c29682011-02-19 12:05:57 -03001455 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001456 err = cmd_status(sk, index, mgmt_op, ENETDOWN);
Johan Hedberga5c29682011-02-19 12:05:57 -03001457 goto failed;
1458 }
1459
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001460 cmd = mgmt_pending_add(sk, mgmt_op, hdev, data, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03001461 if (!cmd) {
1462 err = -ENOMEM;
1463 goto failed;
1464 }
1465
1466 err = hci_send_cmd(hdev, hci_op, sizeof(cp->bdaddr), &cp->bdaddr);
Johan Hedberga664b5b2011-02-19 12:06:02 -03001467 if (err < 0)
1468 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03001469
1470failed:
Andre Guedes8c156c32011-07-07 10:30:36 -03001471 hci_dev_unlock_bh(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03001472 hci_dev_put(hdev);
1473
1474 return err;
1475}
1476
Johan Hedbergb312b1612011-03-16 14:29:37 +02001477static int set_local_name(struct sock *sk, u16 index, unsigned char *data,
1478 u16 len)
1479{
1480 struct mgmt_cp_set_local_name *mgmt_cp = (void *) data;
1481 struct hci_cp_write_local_name hci_cp;
1482 struct hci_dev *hdev;
1483 struct pending_cmd *cmd;
1484 int err;
1485
1486 BT_DBG("");
1487
1488 if (len != sizeof(*mgmt_cp))
1489 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, EINVAL);
1490
1491 hdev = hci_dev_get(index);
1492 if (!hdev)
1493 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, ENODEV);
1494
Andre Guedes8c156c32011-07-07 10:30:36 -03001495 hci_dev_lock_bh(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001496
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001497 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001498 if (!cmd) {
1499 err = -ENOMEM;
1500 goto failed;
1501 }
1502
1503 memcpy(hci_cp.name, mgmt_cp->name, sizeof(hci_cp.name));
1504 err = hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(hci_cp),
1505 &hci_cp);
1506 if (err < 0)
1507 mgmt_pending_remove(cmd);
1508
1509failed:
Andre Guedes8c156c32011-07-07 10:30:36 -03001510 hci_dev_unlock_bh(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001511 hci_dev_put(hdev);
1512
1513 return err;
1514}
1515
Szymon Jancc35938b2011-03-22 13:12:21 +01001516static int read_local_oob_data(struct sock *sk, u16 index)
1517{
1518 struct hci_dev *hdev;
1519 struct pending_cmd *cmd;
1520 int err;
1521
1522 BT_DBG("hci%u", index);
1523
1524 hdev = hci_dev_get(index);
1525 if (!hdev)
1526 return cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
1527 ENODEV);
1528
Andre Guedes8c156c32011-07-07 10:30:36 -03001529 hci_dev_lock_bh(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01001530
1531 if (!test_bit(HCI_UP, &hdev->flags)) {
1532 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
1533 ENETDOWN);
1534 goto unlock;
1535 }
1536
1537 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
1538 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
1539 EOPNOTSUPP);
1540 goto unlock;
1541 }
1542
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001543 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Szymon Jancc35938b2011-03-22 13:12:21 +01001544 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA, EBUSY);
1545 goto unlock;
1546 }
1547
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001548 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01001549 if (!cmd) {
1550 err = -ENOMEM;
1551 goto unlock;
1552 }
1553
1554 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
1555 if (err < 0)
1556 mgmt_pending_remove(cmd);
1557
1558unlock:
Andre Guedes8c156c32011-07-07 10:30:36 -03001559 hci_dev_unlock_bh(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01001560 hci_dev_put(hdev);
1561
1562 return err;
1563}
1564
Szymon Janc2763eda2011-03-22 13:12:22 +01001565static int add_remote_oob_data(struct sock *sk, u16 index, unsigned char *data,
1566 u16 len)
1567{
1568 struct hci_dev *hdev;
1569 struct mgmt_cp_add_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_ADD_REMOTE_OOB_DATA,
1576 EINVAL);
1577
1578 hdev = hci_dev_get(index);
1579 if (!hdev)
1580 return cmd_status(sk, index, MGMT_OP_ADD_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_add_remote_oob_data(hdev, &cp->bdaddr, cp->hash,
1586 cp->randomizer);
1587 if (err < 0)
1588 err = cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, -err);
1589 else
1590 err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, NULL,
1591 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
1599static int remove_remote_oob_data(struct sock *sk, u16 index,
1600 unsigned char *data, u16 len)
1601{
1602 struct hci_dev *hdev;
1603 struct mgmt_cp_remove_remote_oob_data *cp = (void *) data;
1604 int err;
1605
1606 BT_DBG("hci%u ", index);
1607
1608 if (len != sizeof(*cp))
1609 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
1610 EINVAL);
1611
1612 hdev = hci_dev_get(index);
1613 if (!hdev)
1614 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
1615 ENODEV);
1616
Andre Guedes8c156c32011-07-07 10:30:36 -03001617 hci_dev_lock_bh(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001618
1619 err = hci_remove_remote_oob_data(hdev, &cp->bdaddr);
1620 if (err < 0)
1621 err = cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
1622 -err);
1623 else
1624 err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
1625 NULL, 0);
1626
Andre Guedes8c156c32011-07-07 10:30:36 -03001627 hci_dev_unlock_bh(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001628 hci_dev_put(hdev);
1629
1630 return err;
1631}
1632
Johan Hedberg14a53662011-04-27 10:29:56 -04001633static int start_discovery(struct sock *sk, u16 index)
1634{
Johan Hedberg14a53662011-04-27 10:29:56 -04001635 struct pending_cmd *cmd;
1636 struct hci_dev *hdev;
1637 int err;
1638
1639 BT_DBG("hci%u", index);
1640
1641 hdev = hci_dev_get(index);
1642 if (!hdev)
1643 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY, ENODEV);
1644
1645 hci_dev_lock_bh(hdev);
1646
Johan Hedbergbd2d1332011-11-07 23:13:37 +02001647 if (!test_bit(HCI_UP, &hdev->flags)) {
1648 err = cmd_status(sk, index, MGMT_OP_START_DISCOVERY, ENETDOWN);
1649 goto failed;
1650 }
1651
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001652 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04001653 if (!cmd) {
1654 err = -ENOMEM;
1655 goto failed;
1656 }
1657
Andre Guedes2519a1f2011-11-07 11:45:24 -03001658 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
Johan Hedberg14a53662011-04-27 10:29:56 -04001659 if (err < 0)
1660 mgmt_pending_remove(cmd);
1661
1662failed:
1663 hci_dev_unlock_bh(hdev);
1664 hci_dev_put(hdev);
1665
1666 return err;
1667}
1668
1669static int stop_discovery(struct sock *sk, u16 index)
1670{
1671 struct hci_dev *hdev;
1672 struct pending_cmd *cmd;
1673 int err;
1674
1675 BT_DBG("hci%u", index);
1676
1677 hdev = hci_dev_get(index);
1678 if (!hdev)
1679 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY, ENODEV);
1680
1681 hci_dev_lock_bh(hdev);
1682
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001683 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04001684 if (!cmd) {
1685 err = -ENOMEM;
1686 goto failed;
1687 }
1688
Andre Guedes023d5042011-11-04 14:16:52 -03001689 err = hci_cancel_inquiry(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04001690 if (err < 0)
1691 mgmt_pending_remove(cmd);
1692
1693failed:
1694 hci_dev_unlock_bh(hdev);
1695 hci_dev_put(hdev);
1696
1697 return err;
1698}
1699
Antti Julku7fbec222011-06-15 12:01:15 +03001700static int block_device(struct sock *sk, u16 index, unsigned char *data,
1701 u16 len)
1702{
1703 struct hci_dev *hdev;
Antti Julku5e762442011-08-25 16:48:02 +03001704 struct mgmt_cp_block_device *cp = (void *) data;
Antti Julku7fbec222011-06-15 12:01:15 +03001705 int err;
1706
1707 BT_DBG("hci%u", index);
1708
Antti Julku7fbec222011-06-15 12:01:15 +03001709 if (len != sizeof(*cp))
1710 return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
1711 EINVAL);
1712
1713 hdev = hci_dev_get(index);
1714 if (!hdev)
1715 return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
1716 ENODEV);
1717
Antti Julku5e762442011-08-25 16:48:02 +03001718 hci_dev_lock_bh(hdev);
1719
Antti Julku7fbec222011-06-15 12:01:15 +03001720 err = hci_blacklist_add(hdev, &cp->bdaddr);
Antti Julku7fbec222011-06-15 12:01:15 +03001721 if (err < 0)
1722 err = cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE, -err);
1723 else
1724 err = cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE,
1725 NULL, 0);
Antti Julku5e762442011-08-25 16:48:02 +03001726
Antti Julku5e762442011-08-25 16:48:02 +03001727 hci_dev_unlock_bh(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03001728 hci_dev_put(hdev);
1729
1730 return err;
1731}
1732
1733static int unblock_device(struct sock *sk, u16 index, unsigned char *data,
1734 u16 len)
1735{
1736 struct hci_dev *hdev;
Antti Julku5e762442011-08-25 16:48:02 +03001737 struct mgmt_cp_unblock_device *cp = (void *) data;
Antti Julku7fbec222011-06-15 12:01:15 +03001738 int err;
1739
1740 BT_DBG("hci%u", index);
1741
Antti Julku7fbec222011-06-15 12:01:15 +03001742 if (len != sizeof(*cp))
1743 return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
1744 EINVAL);
1745
1746 hdev = hci_dev_get(index);
1747 if (!hdev)
1748 return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
1749 ENODEV);
1750
Antti Julku5e762442011-08-25 16:48:02 +03001751 hci_dev_lock_bh(hdev);
1752
Antti Julku7fbec222011-06-15 12:01:15 +03001753 err = hci_blacklist_del(hdev, &cp->bdaddr);
1754
1755 if (err < 0)
1756 err = cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE, -err);
1757 else
1758 err = cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE,
1759 NULL, 0);
Antti Julku5e762442011-08-25 16:48:02 +03001760
Antti Julku5e762442011-08-25 16:48:02 +03001761 hci_dev_unlock_bh(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03001762 hci_dev_put(hdev);
1763
1764 return err;
1765}
1766
Antti Julkuf6422ec2011-06-22 13:11:56 +03001767static int set_fast_connectable(struct sock *sk, u16 index,
1768 unsigned char *data, u16 len)
1769{
1770 struct hci_dev *hdev;
1771 struct mgmt_cp_set_fast_connectable *cp = (void *) data;
1772 struct hci_cp_write_page_scan_activity acp;
1773 u8 type;
1774 int err;
1775
1776 BT_DBG("hci%u", index);
1777
1778 if (len != sizeof(*cp))
1779 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
1780 EINVAL);
1781
1782 hdev = hci_dev_get(index);
1783 if (!hdev)
1784 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
1785 ENODEV);
1786
1787 hci_dev_lock(hdev);
1788
1789 if (cp->enable) {
1790 type = PAGE_SCAN_TYPE_INTERLACED;
1791 acp.interval = 0x0024; /* 22.5 msec page scan interval */
1792 } else {
1793 type = PAGE_SCAN_TYPE_STANDARD; /* default */
1794 acp.interval = 0x0800; /* default 1.28 sec page scan */
1795 }
1796
1797 acp.window = 0x0012; /* default 11.25 msec page scan window */
1798
1799 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
1800 sizeof(acp), &acp);
1801 if (err < 0) {
1802 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
1803 -err);
1804 goto done;
1805 }
1806
1807 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
1808 if (err < 0) {
1809 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
1810 -err);
1811 goto done;
1812 }
1813
1814 err = cmd_complete(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
1815 NULL, 0);
1816done:
1817 hci_dev_unlock(hdev);
1818 hci_dev_put(hdev);
1819
1820 return err;
1821}
1822
Johan Hedberg03811012010-12-08 00:21:06 +02001823int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
1824{
1825 unsigned char *buf;
1826 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001827 u16 opcode, index, len;
Johan Hedberg03811012010-12-08 00:21:06 +02001828 int err;
1829
1830 BT_DBG("got %zu bytes", msglen);
1831
1832 if (msglen < sizeof(*hdr))
1833 return -EINVAL;
1834
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03001835 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02001836 if (!buf)
1837 return -ENOMEM;
1838
1839 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
1840 err = -EFAULT;
1841 goto done;
1842 }
1843
1844 hdr = (struct mgmt_hdr *) buf;
1845 opcode = get_unaligned_le16(&hdr->opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01001846 index = get_unaligned_le16(&hdr->index);
Johan Hedberg03811012010-12-08 00:21:06 +02001847 len = get_unaligned_le16(&hdr->len);
1848
1849 if (len != msglen - sizeof(*hdr)) {
1850 err = -EINVAL;
1851 goto done;
1852 }
1853
1854 switch (opcode) {
Johan Hedberg02d98122010-12-13 21:07:04 +02001855 case MGMT_OP_READ_VERSION:
1856 err = read_version(sk);
1857 break;
Johan Hedbergfaba42e2010-12-13 21:07:05 +02001858 case MGMT_OP_READ_INDEX_LIST:
1859 err = read_index_list(sk);
1860 break;
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001861 case MGMT_OP_READ_INFO:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001862 err = read_controller_info(sk, index);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001863 break;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001864 case MGMT_OP_SET_POWERED:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001865 err = set_powered(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001866 break;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001867 case MGMT_OP_SET_DISCOVERABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001868 err = set_discoverable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001869 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001870 case MGMT_OP_SET_CONNECTABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001871 err = set_connectable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001872 break;
Johan Hedbergc542a062011-01-26 13:11:03 +02001873 case MGMT_OP_SET_PAIRABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001874 err = set_pairable(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergc542a062011-01-26 13:11:03 +02001875 break;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001876 case MGMT_OP_ADD_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001877 err = add_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001878 break;
1879 case MGMT_OP_REMOVE_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001880 err = remove_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001881 break;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001882 case MGMT_OP_SET_DEV_CLASS:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001883 err = set_dev_class(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001884 break;
1885 case MGMT_OP_SET_SERVICE_CACHE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001886 err = set_service_cache(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001887 break;
Johan Hedberg86742e12011-11-07 23:13:38 +02001888 case MGMT_OP_LOAD_LINK_KEYS:
1889 err = load_link_keys(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001890 break;
Johan Hedberg86742e12011-11-07 23:13:38 +02001891 case MGMT_OP_REMOVE_KEYS:
1892 err = remove_keys(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001893 break;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001894 case MGMT_OP_DISCONNECT:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001895 err = disconnect(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001896 break;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001897 case MGMT_OP_GET_CONNECTIONS:
Szymon Janc8ce62842011-03-01 16:55:32 +01001898 err = get_connections(sk, index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001899 break;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001900 case MGMT_OP_PIN_CODE_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001901 err = pin_code_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001902 break;
1903 case MGMT_OP_PIN_CODE_NEG_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001904 err = pin_code_neg_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001905 break;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001906 case MGMT_OP_SET_IO_CAPABILITY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001907 err = set_io_capability(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001908 break;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001909 case MGMT_OP_PAIR_DEVICE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001910 err = pair_device(sk, index, buf + sizeof(*hdr), len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001911 break;
Johan Hedberga5c29682011-02-19 12:05:57 -03001912 case MGMT_OP_USER_CONFIRM_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001913 err = user_confirm_reply(sk, index, buf + sizeof(*hdr), len, 1);
Johan Hedberga5c29682011-02-19 12:05:57 -03001914 break;
1915 case MGMT_OP_USER_CONFIRM_NEG_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001916 err = user_confirm_reply(sk, index, buf + sizeof(*hdr), len, 0);
Johan Hedberga5c29682011-02-19 12:05:57 -03001917 break;
Johan Hedbergb312b1612011-03-16 14:29:37 +02001918 case MGMT_OP_SET_LOCAL_NAME:
1919 err = set_local_name(sk, index, buf + sizeof(*hdr), len);
1920 break;
Szymon Jancc35938b2011-03-22 13:12:21 +01001921 case MGMT_OP_READ_LOCAL_OOB_DATA:
1922 err = read_local_oob_data(sk, index);
1923 break;
Szymon Janc2763eda2011-03-22 13:12:22 +01001924 case MGMT_OP_ADD_REMOTE_OOB_DATA:
1925 err = add_remote_oob_data(sk, index, buf + sizeof(*hdr), len);
1926 break;
1927 case MGMT_OP_REMOVE_REMOTE_OOB_DATA:
1928 err = remove_remote_oob_data(sk, index, buf + sizeof(*hdr),
1929 len);
1930 break;
Johan Hedberg14a53662011-04-27 10:29:56 -04001931 case MGMT_OP_START_DISCOVERY:
1932 err = start_discovery(sk, index);
1933 break;
1934 case MGMT_OP_STOP_DISCOVERY:
1935 err = stop_discovery(sk, index);
1936 break;
Antti Julku7fbec222011-06-15 12:01:15 +03001937 case MGMT_OP_BLOCK_DEVICE:
1938 err = block_device(sk, index, buf + sizeof(*hdr), len);
1939 break;
1940 case MGMT_OP_UNBLOCK_DEVICE:
1941 err = unblock_device(sk, index, buf + sizeof(*hdr), len);
1942 break;
Antti Julkuf6422ec2011-06-22 13:11:56 +03001943 case MGMT_OP_SET_FAST_CONNECTABLE:
1944 err = set_fast_connectable(sk, index, buf + sizeof(*hdr),
1945 len);
1946 break;
Johan Hedberg03811012010-12-08 00:21:06 +02001947 default:
1948 BT_DBG("Unknown op %u", opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01001949 err = cmd_status(sk, index, opcode, 0x01);
Johan Hedberg03811012010-12-08 00:21:06 +02001950 break;
1951 }
1952
Johan Hedberge41d8b42010-12-13 21:07:03 +02001953 if (err < 0)
1954 goto done;
1955
Johan Hedberg03811012010-12-08 00:21:06 +02001956 err = msglen;
1957
1958done:
1959 kfree(buf);
1960 return err;
1961}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001962
Johan Hedbergb24752f2011-11-03 14:40:33 +02001963static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
1964{
1965 u8 *status = data;
1966
1967 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
1968 mgmt_pending_remove(cmd);
1969}
1970
Johan Hedberg744cf192011-11-08 20:40:14 +02001971int mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001972{
Johan Hedberg744cf192011-11-08 20:40:14 +02001973 return mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001974}
1975
Johan Hedberg744cf192011-11-08 20:40:14 +02001976int mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001977{
Johan Hedbergb24752f2011-11-03 14:40:33 +02001978 u8 status = ENODEV;
1979
Johan Hedberg744cf192011-11-08 20:40:14 +02001980 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02001981
Johan Hedberg744cf192011-11-08 20:40:14 +02001982 return mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001983}
1984
Johan Hedberg73f22f62010-12-29 16:00:25 +02001985struct cmd_lookup {
Johan Hedberg72a734e2010-12-30 00:38:22 +02001986 u8 val;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001987 struct sock *sk;
1988};
1989
Johan Hedberg72a734e2010-12-30 00:38:22 +02001990static void mode_rsp(struct pending_cmd *cmd, void *data)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001991{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01001992 struct mgmt_mode *cp = cmd->param;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001993 struct cmd_lookup *match = data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001994
Johan Hedberg72a734e2010-12-30 00:38:22 +02001995 if (cp->val != match->val)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001996 return;
1997
Johan Hedberg053f0212011-01-26 13:07:10 +02001998 send_mode_rsp(cmd->sk, cmd->opcode, cmd->index, cp->val);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001999
2000 list_del(&cmd->list);
2001
2002 if (match->sk == NULL) {
2003 match->sk = cmd->sk;
2004 sock_hold(match->sk);
2005 }
2006
2007 mgmt_pending_free(cmd);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002008}
Johan Hedberg5add6af2010-12-16 10:00:37 +02002009
Johan Hedberg744cf192011-11-08 20:40:14 +02002010int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg5add6af2010-12-16 10:00:37 +02002011{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002012 struct mgmt_mode ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002013 struct cmd_lookup match = { powered, NULL };
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002014 int ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002015
Johan Hedberg744cf192011-11-08 20:40:14 +02002016 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, mode_rsp, &match);
Johan Hedberg5add6af2010-12-16 10:00:37 +02002017
Johan Hedbergb24752f2011-11-03 14:40:33 +02002018 if (!powered) {
2019 u8 status = ENETDOWN;
Johan Hedberg744cf192011-11-08 20:40:14 +02002020 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002021 }
2022
Johan Hedberg72a734e2010-12-30 00:38:22 +02002023 ev.val = powered;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002024
Johan Hedberg744cf192011-11-08 20:40:14 +02002025 ret = mgmt_event(MGMT_EV_POWERED, hdev, &ev, sizeof(ev), match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002026
2027 if (match.sk)
2028 sock_put(match.sk);
2029
2030 return ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002031}
Johan Hedberg73f22f62010-12-29 16:00:25 +02002032
Johan Hedberg744cf192011-11-08 20:40:14 +02002033int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg73f22f62010-12-29 16:00:25 +02002034{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002035 struct mgmt_mode ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002036 struct cmd_lookup match = { discoverable, NULL };
2037 int ret;
2038
Johan Hedberg744cf192011-11-08 20:40:14 +02002039 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, mode_rsp, &match);
Johan Hedberg72a734e2010-12-30 00:38:22 +02002040
Johan Hedberg72a734e2010-12-30 00:38:22 +02002041 ev.val = discoverable;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002042
Johan Hedberg744cf192011-11-08 20:40:14 +02002043 ret = mgmt_event(MGMT_EV_DISCOVERABLE, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01002044 match.sk);
Johan Hedberg73f22f62010-12-29 16:00:25 +02002045
2046 if (match.sk)
2047 sock_put(match.sk);
2048
2049 return ret;
2050}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002051
Johan Hedberg744cf192011-11-08 20:40:14 +02002052int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002053{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002054 struct mgmt_mode ev;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002055 struct cmd_lookup match = { connectable, NULL };
2056 int ret;
2057
Johan Hedberg744cf192011-11-08 20:40:14 +02002058 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev, mode_rsp, &match);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002059
Johan Hedberg72a734e2010-12-30 00:38:22 +02002060 ev.val = connectable;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002061
Johan Hedberg744cf192011-11-08 20:40:14 +02002062 ret = mgmt_event(MGMT_EV_CONNECTABLE, hdev, &ev, sizeof(ev), match.sk);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002063
2064 if (match.sk)
2065 sock_put(match.sk);
2066
2067 return ret;
2068}
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002069
Johan Hedberg744cf192011-11-08 20:40:14 +02002070int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002071{
2072 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02002073 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002074 cmd_status_rsp, &status);
2075
2076 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02002077 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002078 cmd_status_rsp, &status);
2079
2080 return 0;
2081}
2082
Johan Hedberg744cf192011-11-08 20:40:14 +02002083int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
2084 u8 persistent)
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002085{
Johan Hedberg86742e12011-11-07 23:13:38 +02002086 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002087
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002088 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002089
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002090 ev.store_hint = persistent;
2091 bacpy(&ev.key.bdaddr, &key->bdaddr);
2092 ev.key.type = key->type;
2093 memcpy(ev.key.val, key->val, 16);
2094 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002095
Johan Hedberg744cf192011-11-08 20:40:14 +02002096 return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002097}
Johan Hedbergf7520542011-01-20 12:34:39 +02002098
Johan Hedberg744cf192011-11-08 20:40:14 +02002099int mgmt_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type)
Johan Hedbergf7520542011-01-20 12:34:39 +02002100{
Johan Hedberg4c659c32011-11-07 23:13:39 +02002101 struct mgmt_addr_info ev;
Johan Hedbergf7520542011-01-20 12:34:39 +02002102
Johan Hedbergf7520542011-01-20 12:34:39 +02002103 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg4c659c32011-11-07 23:13:39 +02002104 ev.type = link_to_mgmt(link_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02002105
Johan Hedberg744cf192011-11-08 20:40:14 +02002106 return mgmt_event(MGMT_EV_CONNECTED, hdev, &ev, sizeof(ev), NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02002107}
2108
Johan Hedberg8962ee72011-01-20 12:40:27 +02002109static void disconnect_rsp(struct pending_cmd *cmd, void *data)
2110{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01002111 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002112 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02002113 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002114
Johan Hedberga38528f2011-01-22 06:46:43 +02002115 bacpy(&rp.bdaddr, &cp->bdaddr);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002116
Szymon Janc4e51eae2011-02-25 19:05:48 +01002117 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002118
2119 *sk = cmd->sk;
2120 sock_hold(*sk);
2121
Johan Hedberga664b5b2011-02-19 12:06:02 -03002122 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002123}
2124
Johan Hedberg744cf192011-11-08 20:40:14 +02002125int mgmt_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Johan Hedbergf7520542011-01-20 12:34:39 +02002126{
Johan Hedberg4c659c32011-11-07 23:13:39 +02002127 struct mgmt_addr_info ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002128 struct sock *sk = NULL;
2129 int err;
2130
Johan Hedberg744cf192011-11-08 20:40:14 +02002131 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02002132
Johan Hedbergf7520542011-01-20 12:34:39 +02002133 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg4c659c32011-11-07 23:13:39 +02002134 ev.type = link_to_mgmt(type);
Johan Hedbergf7520542011-01-20 12:34:39 +02002135
Johan Hedberg744cf192011-11-08 20:40:14 +02002136 err = mgmt_event(MGMT_EV_DISCONNECTED, hdev, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002137
2138 if (sk)
2139 sock_put(sk);
2140
2141 return err;
2142}
2143
Johan Hedberg744cf192011-11-08 20:40:14 +02002144int mgmt_disconnect_failed(struct hci_dev *hdev)
Johan Hedberg8962ee72011-01-20 12:40:27 +02002145{
2146 struct pending_cmd *cmd;
2147 int err;
2148
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002149 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002150 if (!cmd)
2151 return -ENOENT;
2152
Johan Hedberg744cf192011-11-08 20:40:14 +02002153 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_DISCONNECT, EIO);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002154
Johan Hedberga664b5b2011-02-19 12:06:02 -03002155 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002156
2157 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02002158}
Johan Hedberg17d5c042011-01-22 06:09:08 +02002159
Johan Hedberg744cf192011-11-08 20:40:14 +02002160int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type,
2161 u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02002162{
2163 struct mgmt_ev_connect_failed ev;
2164
Johan Hedberg4c659c32011-11-07 23:13:39 +02002165 bacpy(&ev.addr.bdaddr, bdaddr);
2166 ev.addr.type = link_to_mgmt(type);
Johan Hedberg17d5c042011-01-22 06:09:08 +02002167 ev.status = status;
2168
Johan Hedberg744cf192011-11-08 20:40:14 +02002169 return mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02002170}
Johan Hedberg980e1a52011-01-22 06:10:07 +02002171
Johan Hedberg744cf192011-11-08 20:40:14 +02002172int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002173{
2174 struct mgmt_ev_pin_code_request ev;
2175
Johan Hedberg980e1a52011-01-22 06:10:07 +02002176 bacpy(&ev.bdaddr, bdaddr);
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02002177 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002178
Johan Hedberg744cf192011-11-08 20:40:14 +02002179 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01002180 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002181}
2182
Johan Hedberg744cf192011-11-08 20:40:14 +02002183int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
2184 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002185{
2186 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002187 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002188 int err;
2189
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002190 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002191 if (!cmd)
2192 return -ENOENT;
2193
Johan Hedbergac56fb12011-02-19 12:05:59 -03002194 bacpy(&rp.bdaddr, bdaddr);
2195 rp.status = status;
2196
Johan Hedberg744cf192011-11-08 20:40:14 +02002197 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY, &rp,
Szymon Janc4e51eae2011-02-25 19:05:48 +01002198 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002199
Johan Hedberga664b5b2011-02-19 12:06:02 -03002200 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002201
2202 return err;
2203}
2204
Johan Hedberg744cf192011-11-08 20:40:14 +02002205int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
2206 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002207{
2208 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002209 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002210 int err;
2211
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002212 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002213 if (!cmd)
2214 return -ENOENT;
2215
Johan Hedbergac56fb12011-02-19 12:05:59 -03002216 bacpy(&rp.bdaddr, bdaddr);
2217 rp.status = status;
2218
Johan Hedberg744cf192011-11-08 20:40:14 +02002219 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY, &rp,
Szymon Janc4e51eae2011-02-25 19:05:48 +01002220 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002221
Johan Hedberga664b5b2011-02-19 12:06:02 -03002222 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002223
2224 return err;
2225}
Johan Hedberga5c29682011-02-19 12:05:57 -03002226
Johan Hedberg744cf192011-11-08 20:40:14 +02002227int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
2228 __le32 value, u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03002229{
2230 struct mgmt_ev_user_confirm_request ev;
2231
Johan Hedberg744cf192011-11-08 20:40:14 +02002232 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03002233
Johan Hedberga5c29682011-02-19 12:05:57 -03002234 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07002235 ev.confirm_hint = confirm_hint;
Johan Hedberga5c29682011-02-19 12:05:57 -03002236 put_unaligned_le32(value, &ev.value);
2237
Johan Hedberg744cf192011-11-08 20:40:14 +02002238 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01002239 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03002240}
2241
Johan Hedberg744cf192011-11-08 20:40:14 +02002242static int confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
2243 u8 status, u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03002244{
2245 struct pending_cmd *cmd;
2246 struct mgmt_rp_user_confirm_reply rp;
2247 int err;
2248
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002249 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002250 if (!cmd)
2251 return -ENOENT;
2252
Johan Hedberga5c29682011-02-19 12:05:57 -03002253 bacpy(&rp.bdaddr, bdaddr);
2254 rp.status = status;
Johan Hedberg744cf192011-11-08 20:40:14 +02002255 err = cmd_complete(cmd->sk, hdev->id, opcode, &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03002256
Johan Hedberga664b5b2011-02-19 12:06:02 -03002257 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002258
2259 return err;
2260}
2261
Johan Hedberg744cf192011-11-08 20:40:14 +02002262int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
2263 u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03002264{
Johan Hedberg744cf192011-11-08 20:40:14 +02002265 return confirm_reply_complete(hdev, bdaddr, status,
Johan Hedberga5c29682011-02-19 12:05:57 -03002266 MGMT_OP_USER_CONFIRM_REPLY);
2267}
2268
Johan Hedberg744cf192011-11-08 20:40:14 +02002269int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev,
2270 bdaddr_t *bdaddr, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03002271{
Johan Hedberg744cf192011-11-08 20:40:14 +02002272 return confirm_reply_complete(hdev, bdaddr, status,
Johan Hedberga5c29682011-02-19 12:05:57 -03002273 MGMT_OP_USER_CONFIRM_NEG_REPLY);
2274}
Johan Hedberg2a611692011-02-19 12:06:00 -03002275
Johan Hedberg744cf192011-11-08 20:40:14 +02002276int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03002277{
2278 struct mgmt_ev_auth_failed ev;
2279
Johan Hedberg2a611692011-02-19 12:06:00 -03002280 bacpy(&ev.bdaddr, bdaddr);
2281 ev.status = status;
2282
Johan Hedberg744cf192011-11-08 20:40:14 +02002283 return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03002284}
Johan Hedbergb312b1612011-03-16 14:29:37 +02002285
Johan Hedberg744cf192011-11-08 20:40:14 +02002286int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02002287{
2288 struct pending_cmd *cmd;
2289 struct mgmt_cp_set_local_name ev;
2290 int err;
2291
2292 memset(&ev, 0, sizeof(ev));
2293 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
2294
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002295 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002296 if (!cmd)
2297 goto send_event;
2298
2299 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02002300 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
2301 EIO);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002302 goto failed;
2303 }
2304
Johan Hedberg744cf192011-11-08 20:40:14 +02002305 hci_dev_lock_bh(hdev);
2306 update_eir(hdev);
2307 hci_dev_unlock_bh(hdev);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002308
Johan Hedberg744cf192011-11-08 20:40:14 +02002309 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, &ev,
Johan Hedbergb312b1612011-03-16 14:29:37 +02002310 sizeof(ev));
2311 if (err < 0)
2312 goto failed;
2313
2314send_event:
Johan Hedberg744cf192011-11-08 20:40:14 +02002315 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
Johan Hedbergb312b1612011-03-16 14:29:37 +02002316 cmd ? cmd->sk : NULL);
2317
2318failed:
2319 if (cmd)
2320 mgmt_pending_remove(cmd);
2321 return err;
2322}
Szymon Jancc35938b2011-03-22 13:12:21 +01002323
Johan Hedberg744cf192011-11-08 20:40:14 +02002324int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
2325 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01002326{
2327 struct pending_cmd *cmd;
2328 int err;
2329
Johan Hedberg744cf192011-11-08 20:40:14 +02002330 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01002331
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002332 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002333 if (!cmd)
2334 return -ENOENT;
2335
2336 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02002337 err = cmd_status(cmd->sk, hdev->id,
2338 MGMT_OP_READ_LOCAL_OOB_DATA, EIO);
Szymon Jancc35938b2011-03-22 13:12:21 +01002339 } else {
2340 struct mgmt_rp_read_local_oob_data rp;
2341
2342 memcpy(rp.hash, hash, sizeof(rp.hash));
2343 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
2344
Johan Hedberg744cf192011-11-08 20:40:14 +02002345 err = cmd_complete(cmd->sk, hdev->id,
2346 MGMT_OP_READ_LOCAL_OOB_DATA,
2347 &rp, sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01002348 }
2349
2350 mgmt_pending_remove(cmd);
2351
2352 return err;
2353}
Johan Hedberge17acd42011-03-30 23:57:16 +03002354
Johan Hedberg744cf192011-11-08 20:40:14 +02002355int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type,
2356 u8 *dev_class, s8 rssi, u8 *eir)
Johan Hedberge17acd42011-03-30 23:57:16 +03002357{
2358 struct mgmt_ev_device_found ev;
2359
2360 memset(&ev, 0, sizeof(ev));
2361
Johan Hedberg4c659c32011-11-07 23:13:39 +02002362 bacpy(&ev.addr.bdaddr, bdaddr);
2363 ev.addr.type = link_to_mgmt(type);
Johan Hedberge17acd42011-03-30 23:57:16 +03002364 ev.rssi = rssi;
2365
2366 if (eir)
2367 memcpy(ev.eir, eir, sizeof(ev.eir));
2368
Andre Guedesf8523592011-09-09 18:56:26 -03002369 if (dev_class)
2370 memcpy(ev.dev_class, dev_class, sizeof(ev.dev_class));
2371
Johan Hedberg744cf192011-11-08 20:40:14 +02002372 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, &ev, sizeof(ev), NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03002373}
Johan Hedberga88a9652011-03-30 13:18:12 +03002374
Johan Hedberg744cf192011-11-08 20:40:14 +02002375int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *name)
Johan Hedberga88a9652011-03-30 13:18:12 +03002376{
2377 struct mgmt_ev_remote_name ev;
2378
2379 memset(&ev, 0, sizeof(ev));
2380
2381 bacpy(&ev.bdaddr, bdaddr);
2382 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
2383
Johan Hedberg744cf192011-11-08 20:40:14 +02002384 return mgmt_event(MGMT_EV_REMOTE_NAME, hdev, &ev, sizeof(ev), NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03002385}
Johan Hedberg314b2382011-04-27 10:29:57 -04002386
Johan Hedberg744cf192011-11-08 20:40:14 +02002387int mgmt_inquiry_failed(struct hci_dev *hdev, u8 status)
Johan Hedberg164a6e72011-11-01 17:06:44 +02002388{
2389 struct pending_cmd *cmd;
2390 int err;
2391
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002392 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02002393 if (!cmd)
2394 return -ENOENT;
2395
Johan Hedberg744cf192011-11-08 20:40:14 +02002396 err = cmd_status(cmd->sk, hdev->id, cmd->opcode, status);
Johan Hedberg164a6e72011-11-01 17:06:44 +02002397 mgmt_pending_remove(cmd);
2398
2399 return err;
2400}
2401
Johan Hedberg744cf192011-11-08 20:40:14 +02002402int mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04002403{
Johan Hedberg164a6e72011-11-01 17:06:44 +02002404 struct pending_cmd *cmd;
2405
2406 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002407 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02002408 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002409 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02002410
2411 if (cmd != NULL) {
Johan Hedberg744cf192011-11-08 20:40:14 +02002412 cmd_complete(cmd->sk, hdev->id, cmd->opcode, NULL, 0);
Johan Hedberg164a6e72011-11-01 17:06:44 +02002413 mgmt_pending_remove(cmd);
2414 }
2415
Johan Hedberg744cf192011-11-08 20:40:14 +02002416 return mgmt_event(MGMT_EV_DISCOVERING, hdev, &discovering,
Johan Hedberg314b2382011-04-27 10:29:57 -04002417 sizeof(discovering), NULL);
2418}
Antti Julku5e762442011-08-25 16:48:02 +03002419
Johan Hedberg744cf192011-11-08 20:40:14 +02002420int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr)
Antti Julku5e762442011-08-25 16:48:02 +03002421{
2422 struct pending_cmd *cmd;
2423 struct mgmt_ev_device_blocked ev;
2424
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002425 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002426
2427 bacpy(&ev.bdaddr, bdaddr);
2428
Johan Hedberg744cf192011-11-08 20:40:14 +02002429 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
2430 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03002431}
2432
Johan Hedberg744cf192011-11-08 20:40:14 +02002433int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr)
Antti Julku5e762442011-08-25 16:48:02 +03002434{
2435 struct pending_cmd *cmd;
2436 struct mgmt_ev_device_unblocked ev;
2437
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002438 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002439
2440 bacpy(&ev.bdaddr, bdaddr);
2441
Johan Hedberg744cf192011-11-08 20:40:14 +02002442 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
2443 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03002444}