blob: be4c3d03d8084796e79a8daaf58a8c7d73ff0172 [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 Jancb8534e02011-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 Hedberg55ed8ca12011-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 Hedberg55ed8ca12011-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 Hedberg55ed8ca12011-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 Hedberg55ed8ca12011-01-17 14:41:05 +0200934 }
935
Szymon Janc4e51eae2011-02-25 19:05:48 +0100936 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca12011-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 Hedberg55ed8ca12011-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 Hedberg55ed8ca12011-01-17 14:41:05 +0200941 key_count);
942
Andre Guedes8c156c32011-07-07 10:30:36 -0300943 hci_dev_lock_bh(hdev);
Johan Hedberg55ed8ca12011-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 Hedberg55ed8ca12011-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 Hedberg55ed8ca12011-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 Hedberg55ed8ca12011-01-17 14:41:05 +0200962 hci_dev_put(hdev);
963
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -0300964 return 0;
Johan Hedberg55ed8ca12011-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 Hedberg55ed8ca12011-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 Hedberg55ed8ca12011-01-17 14:41:05 +0200972 struct hci_conn *conn;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200973 int err;
974
975 cp = (void *) data;
Johan Hedberg55ed8ca12011-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 Hedberg55ed8ca12011-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 Hedberg55ed8ca12011-01-17 14:41:05 +0200983
Andre Guedes8c156c32011-07-07 10:30:36 -0300984 hci_dev_lock_bh(hdev);
Johan Hedberg55ed8ca12011-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 Hedberg55ed8ca12011-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 Hedberg55ed8ca12011-01-17 14:41:05 +02001004 }
1005
1006unlock:
Andre Guedes8c156c32011-07-07 10:30:36 -03001007 hci_dev_unlock_bh(hdev);
Johan Hedberg55ed8ca12011-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 Jancb8534e02011-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 Jancb8534e02011-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;
Johan Hedberg56e5cb82011-11-08 20:40:16 +02001338 struct hci_dev *hdev = conn->hdev;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001339
1340 BT_DBG("status %u", status);
1341
Johan Hedberg56e5cb82011-11-08 20:40:16 +02001342 hci_dev_lock_bh(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001343
Johan Hedberg56e5cb82011-11-08 20:40:16 +02001344 cmd = find_pairing(conn);
1345 if (!cmd)
1346 BT_DBG("Unable to find a pending command");
1347 else
1348 pairing_complete(cmd, status);
1349
1350 hci_dev_unlock_bh(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001351}
1352
Szymon Janc4e51eae2011-02-25 19:05:48 +01001353static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001354{
1355 struct hci_dev *hdev;
1356 struct mgmt_cp_pair_device *cp;
1357 struct pending_cmd *cmd;
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001358 struct adv_entry *entry;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001359 u8 sec_level, auth_type;
1360 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001361 int err;
1362
1363 BT_DBG("");
1364
1365 cp = (void *) data;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001366
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001367 if (len != sizeof(*cp))
1368 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, EINVAL);
1369
Szymon Janc4e51eae2011-02-25 19:05:48 +01001370 hdev = hci_dev_get(index);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001371 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001372 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, ENODEV);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001373
Andre Guedes8c156c32011-07-07 10:30:36 -03001374 hci_dev_lock_bh(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001375
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001376 sec_level = BT_SECURITY_MEDIUM;
1377 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001378 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001379 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03001380 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001381
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001382 entry = hci_find_adv_entry(hdev, &cp->bdaddr);
1383 if (entry)
1384 conn = hci_connect(hdev, LE_LINK, &cp->bdaddr, sec_level,
1385 auth_type);
1386 else
1387 conn = hci_connect(hdev, ACL_LINK, &cp->bdaddr, sec_level,
1388 auth_type);
1389
Ville Tervo30e76272011-02-22 16:10:53 -03001390 if (IS_ERR(conn)) {
1391 err = PTR_ERR(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001392 goto unlock;
1393 }
1394
1395 if (conn->connect_cfm_cb) {
1396 hci_conn_put(conn);
Szymon Janc4e51eae2011-02-25 19:05:48 +01001397 err = cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, EBUSY);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001398 goto unlock;
1399 }
1400
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001401 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001402 if (!cmd) {
1403 err = -ENOMEM;
1404 hci_conn_put(conn);
1405 goto unlock;
1406 }
1407
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001408 /* For LE, just connecting isn't a proof that the pairing finished */
1409 if (!entry)
1410 conn->connect_cfm_cb = pairing_complete_cb;
1411
Johan Hedberge9a416b2011-02-19 12:05:56 -03001412 conn->security_cfm_cb = pairing_complete_cb;
1413 conn->disconn_cfm_cb = pairing_complete_cb;
1414 conn->io_capability = cp->io_cap;
1415 cmd->user_data = conn;
1416
1417 if (conn->state == BT_CONNECTED &&
1418 hci_conn_security(conn, sec_level, auth_type))
1419 pairing_complete(cmd, 0);
1420
1421 err = 0;
1422
1423unlock:
Andre Guedes8c156c32011-07-07 10:30:36 -03001424 hci_dev_unlock_bh(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001425 hci_dev_put(hdev);
1426
1427 return err;
1428}
1429
Szymon Janc4e51eae2011-02-25 19:05:48 +01001430static int user_confirm_reply(struct sock *sk, u16 index, unsigned char *data,
1431 u16 len, int success)
Johan Hedberga5c29682011-02-19 12:05:57 -03001432{
1433 struct mgmt_cp_user_confirm_reply *cp = (void *) data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001434 u16 mgmt_op, hci_op;
Johan Hedberga5c29682011-02-19 12:05:57 -03001435 struct pending_cmd *cmd;
1436 struct hci_dev *hdev;
1437 int err;
1438
1439 BT_DBG("");
1440
Johan Hedberga5c29682011-02-19 12:05:57 -03001441 if (success) {
1442 mgmt_op = MGMT_OP_USER_CONFIRM_REPLY;
1443 hci_op = HCI_OP_USER_CONFIRM_REPLY;
1444 } else {
1445 mgmt_op = MGMT_OP_USER_CONFIRM_NEG_REPLY;
1446 hci_op = HCI_OP_USER_CONFIRM_NEG_REPLY;
1447 }
1448
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001449 if (len != sizeof(*cp))
1450 return cmd_status(sk, index, mgmt_op, EINVAL);
1451
Szymon Janc4e51eae2011-02-25 19:05:48 +01001452 hdev = hci_dev_get(index);
Johan Hedberga5c29682011-02-19 12:05:57 -03001453 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001454 return cmd_status(sk, index, mgmt_op, ENODEV);
Johan Hedberga5c29682011-02-19 12:05:57 -03001455
Andre Guedes8c156c32011-07-07 10:30:36 -03001456 hci_dev_lock_bh(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02001457
Johan Hedberga5c29682011-02-19 12:05:57 -03001458 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001459 err = cmd_status(sk, index, mgmt_op, ENETDOWN);
Johan Hedberga5c29682011-02-19 12:05:57 -03001460 goto failed;
1461 }
1462
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001463 cmd = mgmt_pending_add(sk, mgmt_op, hdev, data, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03001464 if (!cmd) {
1465 err = -ENOMEM;
1466 goto failed;
1467 }
1468
1469 err = hci_send_cmd(hdev, hci_op, sizeof(cp->bdaddr), &cp->bdaddr);
Johan Hedberga664b5b2011-02-19 12:06:02 -03001470 if (err < 0)
1471 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03001472
1473failed:
Andre Guedes8c156c32011-07-07 10:30:36 -03001474 hci_dev_unlock_bh(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03001475 hci_dev_put(hdev);
1476
1477 return err;
1478}
1479
Johan Hedbergb312b1612011-03-16 14:29:37 +02001480static int set_local_name(struct sock *sk, u16 index, unsigned char *data,
1481 u16 len)
1482{
1483 struct mgmt_cp_set_local_name *mgmt_cp = (void *) data;
1484 struct hci_cp_write_local_name hci_cp;
1485 struct hci_dev *hdev;
1486 struct pending_cmd *cmd;
1487 int err;
1488
1489 BT_DBG("");
1490
1491 if (len != sizeof(*mgmt_cp))
1492 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, EINVAL);
1493
1494 hdev = hci_dev_get(index);
1495 if (!hdev)
1496 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, ENODEV);
1497
Andre Guedes8c156c32011-07-07 10:30:36 -03001498 hci_dev_lock_bh(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001499
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001500 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001501 if (!cmd) {
1502 err = -ENOMEM;
1503 goto failed;
1504 }
1505
1506 memcpy(hci_cp.name, mgmt_cp->name, sizeof(hci_cp.name));
1507 err = hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(hci_cp),
1508 &hci_cp);
1509 if (err < 0)
1510 mgmt_pending_remove(cmd);
1511
1512failed:
Andre Guedes8c156c32011-07-07 10:30:36 -03001513 hci_dev_unlock_bh(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001514 hci_dev_put(hdev);
1515
1516 return err;
1517}
1518
Szymon Jancc35938b2011-03-22 13:12:21 +01001519static int read_local_oob_data(struct sock *sk, u16 index)
1520{
1521 struct hci_dev *hdev;
1522 struct pending_cmd *cmd;
1523 int err;
1524
1525 BT_DBG("hci%u", index);
1526
1527 hdev = hci_dev_get(index);
1528 if (!hdev)
1529 return cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
1530 ENODEV);
1531
Andre Guedes8c156c32011-07-07 10:30:36 -03001532 hci_dev_lock_bh(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01001533
1534 if (!test_bit(HCI_UP, &hdev->flags)) {
1535 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
1536 ENETDOWN);
1537 goto unlock;
1538 }
1539
1540 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
1541 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
1542 EOPNOTSUPP);
1543 goto unlock;
1544 }
1545
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001546 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Szymon Jancc35938b2011-03-22 13:12:21 +01001547 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA, EBUSY);
1548 goto unlock;
1549 }
1550
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001551 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01001552 if (!cmd) {
1553 err = -ENOMEM;
1554 goto unlock;
1555 }
1556
1557 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
1558 if (err < 0)
1559 mgmt_pending_remove(cmd);
1560
1561unlock:
Andre Guedes8c156c32011-07-07 10:30:36 -03001562 hci_dev_unlock_bh(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01001563 hci_dev_put(hdev);
1564
1565 return err;
1566}
1567
Szymon Janc2763eda2011-03-22 13:12:22 +01001568static int add_remote_oob_data(struct sock *sk, u16 index, unsigned char *data,
1569 u16 len)
1570{
1571 struct hci_dev *hdev;
1572 struct mgmt_cp_add_remote_oob_data *cp = (void *) data;
1573 int err;
1574
1575 BT_DBG("hci%u ", index);
1576
1577 if (len != sizeof(*cp))
1578 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
1579 EINVAL);
1580
1581 hdev = hci_dev_get(index);
1582 if (!hdev)
1583 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
1584 ENODEV);
1585
Andre Guedes8c156c32011-07-07 10:30:36 -03001586 hci_dev_lock_bh(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001587
1588 err = hci_add_remote_oob_data(hdev, &cp->bdaddr, cp->hash,
1589 cp->randomizer);
1590 if (err < 0)
1591 err = cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, -err);
1592 else
1593 err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, NULL,
1594 0);
1595
Andre Guedes8c156c32011-07-07 10:30:36 -03001596 hci_dev_unlock_bh(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001597 hci_dev_put(hdev);
1598
1599 return err;
1600}
1601
1602static int remove_remote_oob_data(struct sock *sk, u16 index,
1603 unsigned char *data, u16 len)
1604{
1605 struct hci_dev *hdev;
1606 struct mgmt_cp_remove_remote_oob_data *cp = (void *) data;
1607 int err;
1608
1609 BT_DBG("hci%u ", index);
1610
1611 if (len != sizeof(*cp))
1612 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
1613 EINVAL);
1614
1615 hdev = hci_dev_get(index);
1616 if (!hdev)
1617 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
1618 ENODEV);
1619
Andre Guedes8c156c32011-07-07 10:30:36 -03001620 hci_dev_lock_bh(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001621
1622 err = hci_remove_remote_oob_data(hdev, &cp->bdaddr);
1623 if (err < 0)
1624 err = cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
1625 -err);
1626 else
1627 err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
1628 NULL, 0);
1629
Andre Guedes8c156c32011-07-07 10:30:36 -03001630 hci_dev_unlock_bh(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001631 hci_dev_put(hdev);
1632
1633 return err;
1634}
1635
Johan Hedberg14a53662011-04-27 10:29:56 -04001636static int start_discovery(struct sock *sk, u16 index)
1637{
Johan Hedberg14a53662011-04-27 10:29:56 -04001638 struct pending_cmd *cmd;
1639 struct hci_dev *hdev;
1640 int err;
1641
1642 BT_DBG("hci%u", index);
1643
1644 hdev = hci_dev_get(index);
1645 if (!hdev)
1646 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY, ENODEV);
1647
1648 hci_dev_lock_bh(hdev);
1649
Johan Hedbergbd2d1332011-11-07 23:13:37 +02001650 if (!test_bit(HCI_UP, &hdev->flags)) {
1651 err = cmd_status(sk, index, MGMT_OP_START_DISCOVERY, ENETDOWN);
1652 goto failed;
1653 }
1654
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001655 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04001656 if (!cmd) {
1657 err = -ENOMEM;
1658 goto failed;
1659 }
1660
Andre Guedes2519a1f2011-11-07 11:45:24 -03001661 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
Johan Hedberg14a53662011-04-27 10:29:56 -04001662 if (err < 0)
1663 mgmt_pending_remove(cmd);
1664
1665failed:
1666 hci_dev_unlock_bh(hdev);
1667 hci_dev_put(hdev);
1668
1669 return err;
1670}
1671
1672static int stop_discovery(struct sock *sk, u16 index)
1673{
1674 struct hci_dev *hdev;
1675 struct pending_cmd *cmd;
1676 int err;
1677
1678 BT_DBG("hci%u", index);
1679
1680 hdev = hci_dev_get(index);
1681 if (!hdev)
1682 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY, ENODEV);
1683
1684 hci_dev_lock_bh(hdev);
1685
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001686 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04001687 if (!cmd) {
1688 err = -ENOMEM;
1689 goto failed;
1690 }
1691
Andre Guedes023d50492011-11-04 14:16:52 -03001692 err = hci_cancel_inquiry(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04001693 if (err < 0)
1694 mgmt_pending_remove(cmd);
1695
1696failed:
1697 hci_dev_unlock_bh(hdev);
1698 hci_dev_put(hdev);
1699
1700 return err;
1701}
1702
Antti Julku7fbec222011-06-15 12:01:15 +03001703static int block_device(struct sock *sk, u16 index, unsigned char *data,
1704 u16 len)
1705{
1706 struct hci_dev *hdev;
Antti Julku5e762442011-08-25 16:48:02 +03001707 struct mgmt_cp_block_device *cp = (void *) data;
Antti Julku7fbec222011-06-15 12:01:15 +03001708 int err;
1709
1710 BT_DBG("hci%u", index);
1711
Antti Julku7fbec222011-06-15 12:01:15 +03001712 if (len != sizeof(*cp))
1713 return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
1714 EINVAL);
1715
1716 hdev = hci_dev_get(index);
1717 if (!hdev)
1718 return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
1719 ENODEV);
1720
Antti Julku5e762442011-08-25 16:48:02 +03001721 hci_dev_lock_bh(hdev);
1722
Antti Julku7fbec222011-06-15 12:01:15 +03001723 err = hci_blacklist_add(hdev, &cp->bdaddr);
Antti Julku7fbec222011-06-15 12:01:15 +03001724 if (err < 0)
1725 err = cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE, -err);
1726 else
1727 err = cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE,
1728 NULL, 0);
Antti Julku5e762442011-08-25 16:48:02 +03001729
Antti Julku5e762442011-08-25 16:48:02 +03001730 hci_dev_unlock_bh(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03001731 hci_dev_put(hdev);
1732
1733 return err;
1734}
1735
1736static int unblock_device(struct sock *sk, u16 index, unsigned char *data,
1737 u16 len)
1738{
1739 struct hci_dev *hdev;
Antti Julku5e762442011-08-25 16:48:02 +03001740 struct mgmt_cp_unblock_device *cp = (void *) data;
Antti Julku7fbec222011-06-15 12:01:15 +03001741 int err;
1742
1743 BT_DBG("hci%u", index);
1744
Antti Julku7fbec222011-06-15 12:01:15 +03001745 if (len != sizeof(*cp))
1746 return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
1747 EINVAL);
1748
1749 hdev = hci_dev_get(index);
1750 if (!hdev)
1751 return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
1752 ENODEV);
1753
Antti Julku5e762442011-08-25 16:48:02 +03001754 hci_dev_lock_bh(hdev);
1755
Antti Julku7fbec222011-06-15 12:01:15 +03001756 err = hci_blacklist_del(hdev, &cp->bdaddr);
1757
1758 if (err < 0)
1759 err = cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE, -err);
1760 else
1761 err = cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE,
1762 NULL, 0);
Antti Julku5e762442011-08-25 16:48:02 +03001763
Antti Julku5e762442011-08-25 16:48:02 +03001764 hci_dev_unlock_bh(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03001765 hci_dev_put(hdev);
1766
1767 return err;
1768}
1769
Antti Julkuf6422ec2011-06-22 13:11:56 +03001770static int set_fast_connectable(struct sock *sk, u16 index,
1771 unsigned char *data, u16 len)
1772{
1773 struct hci_dev *hdev;
1774 struct mgmt_cp_set_fast_connectable *cp = (void *) data;
1775 struct hci_cp_write_page_scan_activity acp;
1776 u8 type;
1777 int err;
1778
1779 BT_DBG("hci%u", index);
1780
1781 if (len != sizeof(*cp))
1782 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
1783 EINVAL);
1784
1785 hdev = hci_dev_get(index);
1786 if (!hdev)
1787 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
1788 ENODEV);
1789
1790 hci_dev_lock(hdev);
1791
1792 if (cp->enable) {
1793 type = PAGE_SCAN_TYPE_INTERLACED;
1794 acp.interval = 0x0024; /* 22.5 msec page scan interval */
1795 } else {
1796 type = PAGE_SCAN_TYPE_STANDARD; /* default */
1797 acp.interval = 0x0800; /* default 1.28 sec page scan */
1798 }
1799
1800 acp.window = 0x0012; /* default 11.25 msec page scan window */
1801
1802 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
1803 sizeof(acp), &acp);
1804 if (err < 0) {
1805 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
1806 -err);
1807 goto done;
1808 }
1809
1810 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
1811 if (err < 0) {
1812 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
1813 -err);
1814 goto done;
1815 }
1816
1817 err = cmd_complete(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
1818 NULL, 0);
1819done:
1820 hci_dev_unlock(hdev);
1821 hci_dev_put(hdev);
1822
1823 return err;
1824}
1825
Johan Hedberg03811012010-12-08 00:21:06 +02001826int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
1827{
1828 unsigned char *buf;
1829 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001830 u16 opcode, index, len;
Johan Hedberg03811012010-12-08 00:21:06 +02001831 int err;
1832
1833 BT_DBG("got %zu bytes", msglen);
1834
1835 if (msglen < sizeof(*hdr))
1836 return -EINVAL;
1837
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03001838 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02001839 if (!buf)
1840 return -ENOMEM;
1841
1842 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
1843 err = -EFAULT;
1844 goto done;
1845 }
1846
1847 hdr = (struct mgmt_hdr *) buf;
1848 opcode = get_unaligned_le16(&hdr->opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01001849 index = get_unaligned_le16(&hdr->index);
Johan Hedberg03811012010-12-08 00:21:06 +02001850 len = get_unaligned_le16(&hdr->len);
1851
1852 if (len != msglen - sizeof(*hdr)) {
1853 err = -EINVAL;
1854 goto done;
1855 }
1856
1857 switch (opcode) {
Johan Hedberg02d98122010-12-13 21:07:04 +02001858 case MGMT_OP_READ_VERSION:
1859 err = read_version(sk);
1860 break;
Johan Hedbergfaba42e2010-12-13 21:07:05 +02001861 case MGMT_OP_READ_INDEX_LIST:
1862 err = read_index_list(sk);
1863 break;
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001864 case MGMT_OP_READ_INFO:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001865 err = read_controller_info(sk, index);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001866 break;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001867 case MGMT_OP_SET_POWERED:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001868 err = set_powered(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001869 break;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001870 case MGMT_OP_SET_DISCOVERABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001871 err = set_discoverable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001872 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001873 case MGMT_OP_SET_CONNECTABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001874 err = set_connectable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001875 break;
Johan Hedbergc542a062011-01-26 13:11:03 +02001876 case MGMT_OP_SET_PAIRABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001877 err = set_pairable(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergc542a062011-01-26 13:11:03 +02001878 break;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001879 case MGMT_OP_ADD_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001880 err = add_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001881 break;
1882 case MGMT_OP_REMOVE_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001883 err = remove_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001884 break;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001885 case MGMT_OP_SET_DEV_CLASS:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001886 err = set_dev_class(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001887 break;
1888 case MGMT_OP_SET_SERVICE_CACHE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001889 err = set_service_cache(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001890 break;
Johan Hedberg86742e12011-11-07 23:13:38 +02001891 case MGMT_OP_LOAD_LINK_KEYS:
1892 err = load_link_keys(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001893 break;
Johan Hedberg86742e12011-11-07 23:13:38 +02001894 case MGMT_OP_REMOVE_KEYS:
1895 err = remove_keys(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001896 break;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001897 case MGMT_OP_DISCONNECT:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001898 err = disconnect(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001899 break;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001900 case MGMT_OP_GET_CONNECTIONS:
Szymon Janc8ce62842011-03-01 16:55:32 +01001901 err = get_connections(sk, index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001902 break;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001903 case MGMT_OP_PIN_CODE_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001904 err = pin_code_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001905 break;
1906 case MGMT_OP_PIN_CODE_NEG_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001907 err = pin_code_neg_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001908 break;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001909 case MGMT_OP_SET_IO_CAPABILITY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001910 err = set_io_capability(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001911 break;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001912 case MGMT_OP_PAIR_DEVICE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001913 err = pair_device(sk, index, buf + sizeof(*hdr), len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001914 break;
Johan Hedberga5c29682011-02-19 12:05:57 -03001915 case MGMT_OP_USER_CONFIRM_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001916 err = user_confirm_reply(sk, index, buf + sizeof(*hdr), len, 1);
Johan Hedberga5c29682011-02-19 12:05:57 -03001917 break;
1918 case MGMT_OP_USER_CONFIRM_NEG_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001919 err = user_confirm_reply(sk, index, buf + sizeof(*hdr), len, 0);
Johan Hedberga5c29682011-02-19 12:05:57 -03001920 break;
Johan Hedbergb312b1612011-03-16 14:29:37 +02001921 case MGMT_OP_SET_LOCAL_NAME:
1922 err = set_local_name(sk, index, buf + sizeof(*hdr), len);
1923 break;
Szymon Jancc35938b2011-03-22 13:12:21 +01001924 case MGMT_OP_READ_LOCAL_OOB_DATA:
1925 err = read_local_oob_data(sk, index);
1926 break;
Szymon Janc2763eda2011-03-22 13:12:22 +01001927 case MGMT_OP_ADD_REMOTE_OOB_DATA:
1928 err = add_remote_oob_data(sk, index, buf + sizeof(*hdr), len);
1929 break;
1930 case MGMT_OP_REMOVE_REMOTE_OOB_DATA:
1931 err = remove_remote_oob_data(sk, index, buf + sizeof(*hdr),
1932 len);
1933 break;
Johan Hedberg14a53662011-04-27 10:29:56 -04001934 case MGMT_OP_START_DISCOVERY:
1935 err = start_discovery(sk, index);
1936 break;
1937 case MGMT_OP_STOP_DISCOVERY:
1938 err = stop_discovery(sk, index);
1939 break;
Antti Julku7fbec222011-06-15 12:01:15 +03001940 case MGMT_OP_BLOCK_DEVICE:
1941 err = block_device(sk, index, buf + sizeof(*hdr), len);
1942 break;
1943 case MGMT_OP_UNBLOCK_DEVICE:
1944 err = unblock_device(sk, index, buf + sizeof(*hdr), len);
1945 break;
Antti Julkuf6422ec2011-06-22 13:11:56 +03001946 case MGMT_OP_SET_FAST_CONNECTABLE:
1947 err = set_fast_connectable(sk, index, buf + sizeof(*hdr),
1948 len);
1949 break;
Johan Hedberg03811012010-12-08 00:21:06 +02001950 default:
1951 BT_DBG("Unknown op %u", opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01001952 err = cmd_status(sk, index, opcode, 0x01);
Johan Hedberg03811012010-12-08 00:21:06 +02001953 break;
1954 }
1955
Johan Hedberge41d8b42010-12-13 21:07:03 +02001956 if (err < 0)
1957 goto done;
1958
Johan Hedberg03811012010-12-08 00:21:06 +02001959 err = msglen;
1960
1961done:
1962 kfree(buf);
1963 return err;
1964}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001965
Johan Hedbergb24752f2011-11-03 14:40:33 +02001966static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
1967{
1968 u8 *status = data;
1969
1970 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
1971 mgmt_pending_remove(cmd);
1972}
1973
Johan Hedberg744cf192011-11-08 20:40:14 +02001974int mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001975{
Johan Hedberg744cf192011-11-08 20:40:14 +02001976 return mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001977}
1978
Johan Hedberg744cf192011-11-08 20:40:14 +02001979int mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001980{
Johan Hedbergb24752f2011-11-03 14:40:33 +02001981 u8 status = ENODEV;
1982
Johan Hedberg744cf192011-11-08 20:40:14 +02001983 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02001984
Johan Hedberg744cf192011-11-08 20:40:14 +02001985 return mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001986}
1987
Johan Hedberg73f22f62010-12-29 16:00:25 +02001988struct cmd_lookup {
Johan Hedberg72a734e2010-12-30 00:38:22 +02001989 u8 val;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001990 struct sock *sk;
1991};
1992
Johan Hedberg72a734e2010-12-30 00:38:22 +02001993static void mode_rsp(struct pending_cmd *cmd, void *data)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001994{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01001995 struct mgmt_mode *cp = cmd->param;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001996 struct cmd_lookup *match = data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001997
Johan Hedberg72a734e2010-12-30 00:38:22 +02001998 if (cp->val != match->val)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001999 return;
2000
Johan Hedberg053f0212011-01-26 13:07:10 +02002001 send_mode_rsp(cmd->sk, cmd->opcode, cmd->index, cp->val);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002002
2003 list_del(&cmd->list);
2004
2005 if (match->sk == NULL) {
2006 match->sk = cmd->sk;
2007 sock_hold(match->sk);
2008 }
2009
2010 mgmt_pending_free(cmd);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002011}
Johan Hedberg5add6af2010-12-16 10:00:37 +02002012
Johan Hedberg744cf192011-11-08 20:40:14 +02002013int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg5add6af2010-12-16 10:00:37 +02002014{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002015 struct mgmt_mode ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002016 struct cmd_lookup match = { powered, NULL };
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002017 int ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002018
Johan Hedberg744cf192011-11-08 20:40:14 +02002019 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, mode_rsp, &match);
Johan Hedberg5add6af2010-12-16 10:00:37 +02002020
Johan Hedbergb24752f2011-11-03 14:40:33 +02002021 if (!powered) {
2022 u8 status = ENETDOWN;
Johan Hedberg744cf192011-11-08 20:40:14 +02002023 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002024 }
2025
Johan Hedberg72a734e2010-12-30 00:38:22 +02002026 ev.val = powered;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002027
Johan Hedberg744cf192011-11-08 20:40:14 +02002028 ret = mgmt_event(MGMT_EV_POWERED, hdev, &ev, sizeof(ev), match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002029
2030 if (match.sk)
2031 sock_put(match.sk);
2032
2033 return ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002034}
Johan Hedberg73f22f62010-12-29 16:00:25 +02002035
Johan Hedberg744cf192011-11-08 20:40:14 +02002036int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg73f22f62010-12-29 16:00:25 +02002037{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002038 struct mgmt_mode ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002039 struct cmd_lookup match = { discoverable, NULL };
2040 int ret;
2041
Johan Hedberg744cf192011-11-08 20:40:14 +02002042 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, mode_rsp, &match);
Johan Hedberg72a734e2010-12-30 00:38:22 +02002043
Johan Hedberg72a734e2010-12-30 00:38:22 +02002044 ev.val = discoverable;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002045
Johan Hedberg744cf192011-11-08 20:40:14 +02002046 ret = mgmt_event(MGMT_EV_DISCOVERABLE, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01002047 match.sk);
Johan Hedberg73f22f62010-12-29 16:00:25 +02002048
2049 if (match.sk)
2050 sock_put(match.sk);
2051
2052 return ret;
2053}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002054
Johan Hedberg744cf192011-11-08 20:40:14 +02002055int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002056{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002057 struct mgmt_mode ev;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002058 struct cmd_lookup match = { connectable, NULL };
2059 int ret;
2060
Johan Hedberg744cf192011-11-08 20:40:14 +02002061 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev, mode_rsp, &match);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002062
Johan Hedberg72a734e2010-12-30 00:38:22 +02002063 ev.val = connectable;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002064
Johan Hedberg744cf192011-11-08 20:40:14 +02002065 ret = mgmt_event(MGMT_EV_CONNECTABLE, hdev, &ev, sizeof(ev), match.sk);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002066
2067 if (match.sk)
2068 sock_put(match.sk);
2069
2070 return ret;
2071}
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002072
Johan Hedberg744cf192011-11-08 20:40:14 +02002073int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002074{
2075 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02002076 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002077 cmd_status_rsp, &status);
2078
2079 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02002080 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002081 cmd_status_rsp, &status);
2082
2083 return 0;
2084}
2085
Johan Hedberg744cf192011-11-08 20:40:14 +02002086int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
2087 u8 persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002088{
Johan Hedberg86742e12011-11-07 23:13:38 +02002089 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002090
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002091 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002092
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002093 ev.store_hint = persistent;
2094 bacpy(&ev.key.bdaddr, &key->bdaddr);
2095 ev.key.type = key->type;
2096 memcpy(ev.key.val, key->val, 16);
2097 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002098
Johan Hedberg744cf192011-11-08 20:40:14 +02002099 return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002100}
Johan Hedbergf7520542011-01-20 12:34:39 +02002101
Johan Hedberg744cf192011-11-08 20:40:14 +02002102int mgmt_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type)
Johan Hedbergf7520542011-01-20 12:34:39 +02002103{
Johan Hedberg4c659c32011-11-07 23:13:39 +02002104 struct mgmt_addr_info ev;
Johan Hedbergf7520542011-01-20 12:34:39 +02002105
Johan Hedbergf7520542011-01-20 12:34:39 +02002106 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg4c659c32011-11-07 23:13:39 +02002107 ev.type = link_to_mgmt(link_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02002108
Johan Hedberg744cf192011-11-08 20:40:14 +02002109 return mgmt_event(MGMT_EV_CONNECTED, hdev, &ev, sizeof(ev), NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02002110}
2111
Johan Hedberg8962ee72011-01-20 12:40:27 +02002112static void disconnect_rsp(struct pending_cmd *cmd, void *data)
2113{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01002114 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002115 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02002116 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002117
Johan Hedberga38528f2011-01-22 06:46:43 +02002118 bacpy(&rp.bdaddr, &cp->bdaddr);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002119
Szymon Janc4e51eae2011-02-25 19:05:48 +01002120 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002121
2122 *sk = cmd->sk;
2123 sock_hold(*sk);
2124
Johan Hedberga664b5b2011-02-19 12:06:02 -03002125 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002126}
2127
Johan Hedberg744cf192011-11-08 20:40:14 +02002128int mgmt_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Johan Hedbergf7520542011-01-20 12:34:39 +02002129{
Johan Hedberg4c659c32011-11-07 23:13:39 +02002130 struct mgmt_addr_info ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002131 struct sock *sk = NULL;
2132 int err;
2133
Johan Hedberg744cf192011-11-08 20:40:14 +02002134 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02002135
Johan Hedbergf7520542011-01-20 12:34:39 +02002136 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg4c659c32011-11-07 23:13:39 +02002137 ev.type = link_to_mgmt(type);
Johan Hedbergf7520542011-01-20 12:34:39 +02002138
Johan Hedberg744cf192011-11-08 20:40:14 +02002139 err = mgmt_event(MGMT_EV_DISCONNECTED, hdev, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002140
2141 if (sk)
2142 sock_put(sk);
2143
2144 return err;
2145}
2146
Johan Hedberg744cf192011-11-08 20:40:14 +02002147int mgmt_disconnect_failed(struct hci_dev *hdev)
Johan Hedberg8962ee72011-01-20 12:40:27 +02002148{
2149 struct pending_cmd *cmd;
2150 int err;
2151
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002152 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002153 if (!cmd)
2154 return -ENOENT;
2155
Johan Hedberg744cf192011-11-08 20:40:14 +02002156 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_DISCONNECT, EIO);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002157
Johan Hedberga664b5b2011-02-19 12:06:02 -03002158 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002159
2160 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02002161}
Johan Hedberg17d5c042011-01-22 06:09:08 +02002162
Johan Hedberg744cf192011-11-08 20:40:14 +02002163int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type,
2164 u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02002165{
2166 struct mgmt_ev_connect_failed ev;
2167
Johan Hedberg4c659c32011-11-07 23:13:39 +02002168 bacpy(&ev.addr.bdaddr, bdaddr);
2169 ev.addr.type = link_to_mgmt(type);
Johan Hedberg17d5c042011-01-22 06:09:08 +02002170 ev.status = status;
2171
Johan Hedberg744cf192011-11-08 20:40:14 +02002172 return mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02002173}
Johan Hedberg980e1a52011-01-22 06:10:07 +02002174
Johan Hedberg744cf192011-11-08 20:40:14 +02002175int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002176{
2177 struct mgmt_ev_pin_code_request ev;
2178
Johan Hedberg980e1a52011-01-22 06:10:07 +02002179 bacpy(&ev.bdaddr, bdaddr);
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02002180 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002181
Johan Hedberg744cf192011-11-08 20:40:14 +02002182 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01002183 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002184}
2185
Johan Hedberg744cf192011-11-08 20:40:14 +02002186int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
2187 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002188{
2189 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002190 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002191 int err;
2192
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002193 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002194 if (!cmd)
2195 return -ENOENT;
2196
Johan Hedbergac56fb12011-02-19 12:05:59 -03002197 bacpy(&rp.bdaddr, bdaddr);
2198 rp.status = status;
2199
Johan Hedberg744cf192011-11-08 20:40:14 +02002200 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY, &rp,
Szymon Janc4e51eae2011-02-25 19:05:48 +01002201 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002202
Johan Hedberga664b5b2011-02-19 12:06:02 -03002203 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002204
2205 return err;
2206}
2207
Johan Hedberg744cf192011-11-08 20:40:14 +02002208int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
2209 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002210{
2211 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002212 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002213 int err;
2214
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002215 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002216 if (!cmd)
2217 return -ENOENT;
2218
Johan Hedbergac56fb12011-02-19 12:05:59 -03002219 bacpy(&rp.bdaddr, bdaddr);
2220 rp.status = status;
2221
Johan Hedberg744cf192011-11-08 20:40:14 +02002222 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY, &rp,
Szymon Janc4e51eae2011-02-25 19:05:48 +01002223 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002224
Johan Hedberga664b5b2011-02-19 12:06:02 -03002225 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002226
2227 return err;
2228}
Johan Hedberga5c29682011-02-19 12:05:57 -03002229
Johan Hedberg744cf192011-11-08 20:40:14 +02002230int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
2231 __le32 value, u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03002232{
2233 struct mgmt_ev_user_confirm_request ev;
2234
Johan Hedberg744cf192011-11-08 20:40:14 +02002235 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03002236
Johan Hedberga5c29682011-02-19 12:05:57 -03002237 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07002238 ev.confirm_hint = confirm_hint;
Johan Hedberga5c29682011-02-19 12:05:57 -03002239 put_unaligned_le32(value, &ev.value);
2240
Johan Hedberg744cf192011-11-08 20:40:14 +02002241 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01002242 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03002243}
2244
Johan Hedberg744cf192011-11-08 20:40:14 +02002245static int confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
2246 u8 status, u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03002247{
2248 struct pending_cmd *cmd;
2249 struct mgmt_rp_user_confirm_reply rp;
2250 int err;
2251
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002252 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002253 if (!cmd)
2254 return -ENOENT;
2255
Johan Hedberga5c29682011-02-19 12:05:57 -03002256 bacpy(&rp.bdaddr, bdaddr);
2257 rp.status = status;
Johan Hedberg744cf192011-11-08 20:40:14 +02002258 err = cmd_complete(cmd->sk, hdev->id, opcode, &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03002259
Johan Hedberga664b5b2011-02-19 12:06:02 -03002260 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002261
2262 return err;
2263}
2264
Johan Hedberg744cf192011-11-08 20:40:14 +02002265int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
2266 u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03002267{
Johan Hedberg744cf192011-11-08 20:40:14 +02002268 return confirm_reply_complete(hdev, bdaddr, status,
Johan Hedberga5c29682011-02-19 12:05:57 -03002269 MGMT_OP_USER_CONFIRM_REPLY);
2270}
2271
Johan Hedberg744cf192011-11-08 20:40:14 +02002272int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev,
2273 bdaddr_t *bdaddr, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03002274{
Johan Hedberg744cf192011-11-08 20:40:14 +02002275 return confirm_reply_complete(hdev, bdaddr, status,
Johan Hedberga5c29682011-02-19 12:05:57 -03002276 MGMT_OP_USER_CONFIRM_NEG_REPLY);
2277}
Johan Hedberg2a611692011-02-19 12:06:00 -03002278
Johan Hedberg744cf192011-11-08 20:40:14 +02002279int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03002280{
2281 struct mgmt_ev_auth_failed ev;
2282
Johan Hedberg2a611692011-02-19 12:06:00 -03002283 bacpy(&ev.bdaddr, bdaddr);
2284 ev.status = status;
2285
Johan Hedberg744cf192011-11-08 20:40:14 +02002286 return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03002287}
Johan Hedbergb312b1612011-03-16 14:29:37 +02002288
Johan Hedberg744cf192011-11-08 20:40:14 +02002289int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02002290{
2291 struct pending_cmd *cmd;
2292 struct mgmt_cp_set_local_name ev;
2293 int err;
2294
2295 memset(&ev, 0, sizeof(ev));
2296 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
2297
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002298 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002299 if (!cmd)
2300 goto send_event;
2301
2302 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02002303 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
2304 EIO);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002305 goto failed;
2306 }
2307
Johan Hedberg744cf192011-11-08 20:40:14 +02002308 update_eir(hdev);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002309
Johan Hedberg744cf192011-11-08 20:40:14 +02002310 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, &ev,
Johan Hedbergb312b1612011-03-16 14:29:37 +02002311 sizeof(ev));
2312 if (err < 0)
2313 goto failed;
2314
2315send_event:
Johan Hedberg744cf192011-11-08 20:40:14 +02002316 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
Johan Hedbergb312b1612011-03-16 14:29:37 +02002317 cmd ? cmd->sk : NULL);
2318
2319failed:
2320 if (cmd)
2321 mgmt_pending_remove(cmd);
2322 return err;
2323}
Szymon Jancc35938b2011-03-22 13:12:21 +01002324
Johan Hedberg744cf192011-11-08 20:40:14 +02002325int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
2326 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01002327{
2328 struct pending_cmd *cmd;
2329 int err;
2330
Johan Hedberg744cf192011-11-08 20:40:14 +02002331 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01002332
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002333 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002334 if (!cmd)
2335 return -ENOENT;
2336
2337 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02002338 err = cmd_status(cmd->sk, hdev->id,
2339 MGMT_OP_READ_LOCAL_OOB_DATA, EIO);
Szymon Jancc35938b2011-03-22 13:12:21 +01002340 } else {
2341 struct mgmt_rp_read_local_oob_data rp;
2342
2343 memcpy(rp.hash, hash, sizeof(rp.hash));
2344 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
2345
Johan Hedberg744cf192011-11-08 20:40:14 +02002346 err = cmd_complete(cmd->sk, hdev->id,
2347 MGMT_OP_READ_LOCAL_OOB_DATA,
2348 &rp, sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01002349 }
2350
2351 mgmt_pending_remove(cmd);
2352
2353 return err;
2354}
Johan Hedberge17acd42011-03-30 23:57:16 +03002355
Johan Hedberg744cf192011-11-08 20:40:14 +02002356int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type,
2357 u8 *dev_class, s8 rssi, u8 *eir)
Johan Hedberge17acd42011-03-30 23:57:16 +03002358{
2359 struct mgmt_ev_device_found ev;
2360
2361 memset(&ev, 0, sizeof(ev));
2362
Johan Hedberg4c659c32011-11-07 23:13:39 +02002363 bacpy(&ev.addr.bdaddr, bdaddr);
2364 ev.addr.type = link_to_mgmt(type);
Johan Hedberge17acd42011-03-30 23:57:16 +03002365 ev.rssi = rssi;
2366
2367 if (eir)
2368 memcpy(ev.eir, eir, sizeof(ev.eir));
2369
Andre Guedesf8523592011-09-09 18:56:26 -03002370 if (dev_class)
2371 memcpy(ev.dev_class, dev_class, sizeof(ev.dev_class));
2372
Johan Hedberg744cf192011-11-08 20:40:14 +02002373 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, &ev, sizeof(ev), NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03002374}
Johan Hedberga88a9652011-03-30 13:18:12 +03002375
Johan Hedberg744cf192011-11-08 20:40:14 +02002376int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *name)
Johan Hedberga88a9652011-03-30 13:18:12 +03002377{
2378 struct mgmt_ev_remote_name ev;
2379
2380 memset(&ev, 0, sizeof(ev));
2381
2382 bacpy(&ev.bdaddr, bdaddr);
2383 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
2384
Johan Hedberg744cf192011-11-08 20:40:14 +02002385 return mgmt_event(MGMT_EV_REMOTE_NAME, hdev, &ev, sizeof(ev), NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03002386}
Johan Hedberg314b2382011-04-27 10:29:57 -04002387
Johan Hedberg744cf192011-11-08 20:40:14 +02002388int mgmt_inquiry_failed(struct hci_dev *hdev, u8 status)
Johan Hedberg164a6e72011-11-01 17:06:44 +02002389{
2390 struct pending_cmd *cmd;
2391 int err;
2392
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002393 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02002394 if (!cmd)
2395 return -ENOENT;
2396
Johan Hedberg744cf192011-11-08 20:40:14 +02002397 err = cmd_status(cmd->sk, hdev->id, cmd->opcode, status);
Johan Hedberg164a6e72011-11-01 17:06:44 +02002398 mgmt_pending_remove(cmd);
2399
2400 return err;
2401}
2402
Johan Hedberg744cf192011-11-08 20:40:14 +02002403int mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04002404{
Johan Hedberg164a6e72011-11-01 17:06:44 +02002405 struct pending_cmd *cmd;
2406
2407 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002408 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02002409 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002410 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02002411
2412 if (cmd != NULL) {
Johan Hedberg744cf192011-11-08 20:40:14 +02002413 cmd_complete(cmd->sk, hdev->id, cmd->opcode, NULL, 0);
Johan Hedberg164a6e72011-11-01 17:06:44 +02002414 mgmt_pending_remove(cmd);
2415 }
2416
Johan Hedberg744cf192011-11-08 20:40:14 +02002417 return mgmt_event(MGMT_EV_DISCOVERING, hdev, &discovering,
Johan Hedberg314b2382011-04-27 10:29:57 -04002418 sizeof(discovering), NULL);
2419}
Antti Julku5e762442011-08-25 16:48:02 +03002420
Johan Hedberg744cf192011-11-08 20:40:14 +02002421int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr)
Antti Julku5e762442011-08-25 16:48:02 +03002422{
2423 struct pending_cmd *cmd;
2424 struct mgmt_ev_device_blocked ev;
2425
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002426 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002427
2428 bacpy(&ev.bdaddr, bdaddr);
2429
Johan Hedberg744cf192011-11-08 20:40:14 +02002430 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
2431 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03002432}
2433
Johan Hedberg744cf192011-11-08 20:40:14 +02002434int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr)
Antti Julku5e762442011-08-25 16:48:02 +03002435{
2436 struct pending_cmd *cmd;
2437 struct mgmt_ev_device_unblocked ev;
2438
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002439 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002440
2441 bacpy(&ev.bdaddr, bdaddr);
2442
Johan Hedberg744cf192011-11-08 20:40:14 +02002443 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
2444 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03002445}