blob: dddb19057d11bcf7ffd4bd210fe6e3ab1acdbaa2 [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;
Johan Hedbergfc2f4b12011-11-09 13:58:56 +020039 u16 opcode;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020040 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))
Johan Hedberge0f93092011-11-09 01:44:22 +0200152 cancel_delayed_work(&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 Hedbergeec8d2b2010-12-16 10:17:38 +0200271 cb(cmd, data);
272 }
273}
274
Johan Hedberg2e58ef32011-11-08 20:40:15 +0200275static struct pending_cmd *mgmt_pending_find(u16 opcode, struct hci_dev *hdev)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200276{
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200277 struct pending_cmd *cmd;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200278
Johan Hedberg2e58ef32011-11-08 20:40:15 +0200279 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberg2aeabcb2011-11-09 13:58:57 +0200280 if (cmd->opcode == opcode)
281 return cmd;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200282 }
283
284 return NULL;
285}
286
Johan Hedberga664b5b2011-02-19 12:06:02 -0300287static void mgmt_pending_remove(struct pending_cmd *cmd)
Johan Hedberg73f22f62010-12-29 16:00:25 +0200288{
Johan Hedberg73f22f62010-12-29 16:00:25 +0200289 list_del(&cmd->list);
290 mgmt_pending_free(cmd);
291}
292
Szymon Janc4e51eae2011-02-25 19:05:48 +0100293static int set_powered(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200294{
Johan Hedberg72a734e2010-12-30 00:38:22 +0200295 struct mgmt_mode *cp;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200296 struct hci_dev *hdev;
Johan Hedberg366a0332011-02-19 12:05:55 -0300297 struct pending_cmd *cmd;
Johan Hedberg366a0332011-02-19 12:05:55 -0300298 int err, up;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200299
300 cp = (void *) data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200301
Szymon Janc4e51eae2011-02-25 19:05:48 +0100302 BT_DBG("request for hci%u", index);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200303
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100304 if (len != sizeof(*cp))
305 return cmd_status(sk, index, MGMT_OP_SET_POWERED, EINVAL);
306
Szymon Janc4e51eae2011-02-25 19:05:48 +0100307 hdev = hci_dev_get(index);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200308 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100309 return cmd_status(sk, index, MGMT_OP_SET_POWERED, ENODEV);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200310
Andre Guedes8c156c32011-07-07 10:30:36 -0300311 hci_dev_lock_bh(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200312
313 up = test_bit(HCI_UP, &hdev->flags);
Johan Hedberg72a734e2010-12-30 00:38:22 +0200314 if ((cp->val && up) || (!cp->val && !up)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100315 err = cmd_status(sk, index, MGMT_OP_SET_POWERED, EALREADY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200316 goto failed;
317 }
318
Johan Hedberg2e58ef32011-11-08 20:40:15 +0200319 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100320 err = cmd_status(sk, index, MGMT_OP_SET_POWERED, EBUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200321 goto failed;
322 }
323
Johan Hedberg2e58ef32011-11-08 20:40:15 +0200324 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -0300325 if (!cmd) {
326 err = -ENOMEM;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200327 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -0300328 }
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200329
Johan Hedberg72a734e2010-12-30 00:38:22 +0200330 if (cp->val)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200331 queue_work(hdev->workqueue, &hdev->power_on);
332 else
Johan Hedberg32435532011-11-07 22:16:04 +0200333 queue_work(hdev->workqueue, &hdev->power_off.work);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200334
Johan Hedberg366a0332011-02-19 12:05:55 -0300335 err = 0;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200336
337failed:
Andre Guedes8c156c32011-07-07 10:30:36 -0300338 hci_dev_unlock_bh(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200339 hci_dev_put(hdev);
Johan Hedberg366a0332011-02-19 12:05:55 -0300340 return err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200341}
342
Szymon Janc4e51eae2011-02-25 19:05:48 +0100343static int set_discoverable(struct sock *sk, u16 index, unsigned char *data,
344 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +0200345{
Johan Hedberg16ab91a2011-11-07 22:16:02 +0200346 struct mgmt_cp_set_discoverable *cp;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200347 struct hci_dev *hdev;
Johan Hedberg366a0332011-02-19 12:05:55 -0300348 struct pending_cmd *cmd;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200349 u8 scan;
350 int err;
351
352 cp = (void *) data;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200353
Szymon Janc4e51eae2011-02-25 19:05:48 +0100354 BT_DBG("request for hci%u", index);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200355
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100356 if (len != sizeof(*cp))
357 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, EINVAL);
358
Szymon Janc4e51eae2011-02-25 19:05:48 +0100359 hdev = hci_dev_get(index);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200360 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100361 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, ENODEV);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200362
Andre Guedes8c156c32011-07-07 10:30:36 -0300363 hci_dev_lock_bh(hdev);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200364
365 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100366 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, ENETDOWN);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200367 goto failed;
368 }
369
Johan Hedberg2e58ef32011-11-08 20:40:15 +0200370 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
371 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100372 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, EBUSY);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200373 goto failed;
374 }
375
Johan Hedberg72a734e2010-12-30 00:38:22 +0200376 if (cp->val == test_bit(HCI_ISCAN, &hdev->flags) &&
Johan Hedberg73f22f62010-12-29 16:00:25 +0200377 test_bit(HCI_PSCAN, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100378 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, EALREADY);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200379 goto failed;
380 }
381
Johan Hedberg2e58ef32011-11-08 20:40:15 +0200382 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -0300383 if (!cmd) {
384 err = -ENOMEM;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200385 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -0300386 }
Johan Hedberg73f22f62010-12-29 16:00:25 +0200387
388 scan = SCAN_PAGE;
389
Johan Hedberg72a734e2010-12-30 00:38:22 +0200390 if (cp->val)
Johan Hedberg73f22f62010-12-29 16:00:25 +0200391 scan |= SCAN_INQUIRY;
Johan Hedberg16ab91a2011-11-07 22:16:02 +0200392 else
Johan Hedberge0f93092011-11-09 01:44:22 +0200393 cancel_delayed_work(&hdev->discov_off);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200394
395 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
396 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -0300397 mgmt_pending_remove(cmd);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200398
Johan Hedberg16ab91a2011-11-07 22:16:02 +0200399 if (cp->val)
400 hdev->discov_timeout = get_unaligned_le16(&cp->timeout);
401
Johan Hedberg73f22f62010-12-29 16:00:25 +0200402failed:
Andre Guedes8c156c32011-07-07 10:30:36 -0300403 hci_dev_unlock_bh(hdev);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200404 hci_dev_put(hdev);
405
406 return err;
407}
408
Szymon Janc4e51eae2011-02-25 19:05:48 +0100409static int set_connectable(struct sock *sk, u16 index, unsigned char *data,
410 u16 len)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200411{
Johan Hedberg72a734e2010-12-30 00:38:22 +0200412 struct mgmt_mode *cp;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200413 struct hci_dev *hdev;
Johan Hedberg366a0332011-02-19 12:05:55 -0300414 struct pending_cmd *cmd;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200415 u8 scan;
416 int err;
417
418 cp = (void *) data;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200419
Szymon Janc4e51eae2011-02-25 19:05:48 +0100420 BT_DBG("request for hci%u", index);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200421
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100422 if (len != sizeof(*cp))
423 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, EINVAL);
424
Szymon Janc4e51eae2011-02-25 19:05:48 +0100425 hdev = hci_dev_get(index);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200426 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100427 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, ENODEV);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200428
Andre Guedes8c156c32011-07-07 10:30:36 -0300429 hci_dev_lock_bh(hdev);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200430
431 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100432 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, ENETDOWN);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200433 goto failed;
434 }
435
Johan Hedberg2e58ef32011-11-08 20:40:15 +0200436 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
437 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100438 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, EBUSY);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200439 goto failed;
440 }
441
Johan Hedberg72a734e2010-12-30 00:38:22 +0200442 if (cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100443 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, EALREADY);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200444 goto failed;
445 }
446
Johan Hedberg2e58ef32011-11-08 20:40:15 +0200447 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -0300448 if (!cmd) {
449 err = -ENOMEM;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200450 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -0300451 }
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200452
Johan Hedberg72a734e2010-12-30 00:38:22 +0200453 if (cp->val)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200454 scan = SCAN_PAGE;
455 else
456 scan = 0;
457
458 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
459 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -0300460 mgmt_pending_remove(cmd);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200461
462failed:
Andre Guedes8c156c32011-07-07 10:30:36 -0300463 hci_dev_unlock_bh(hdev);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200464 hci_dev_put(hdev);
465
466 return err;
467}
468
Johan Hedberg744cf192011-11-08 20:40:14 +0200469static int mgmt_event(u16 event, struct hci_dev *hdev, void *data,
470 u16 data_len, struct sock *skip_sk)
Johan Hedbergc542a062011-01-26 13:11:03 +0200471{
472 struct sk_buff *skb;
473 struct mgmt_hdr *hdr;
474
475 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_ATOMIC);
476 if (!skb)
477 return -ENOMEM;
478
479 bt_cb(skb)->channel = HCI_CHANNEL_CONTROL;
480
481 hdr = (void *) skb_put(skb, sizeof(*hdr));
482 hdr->opcode = cpu_to_le16(event);
Johan Hedberg744cf192011-11-08 20:40:14 +0200483 if (hdev)
484 hdr->index = cpu_to_le16(hdev->id);
485 else
486 hdr->index = cpu_to_le16(MGMT_INDEX_NONE);
Johan Hedbergc542a062011-01-26 13:11:03 +0200487 hdr->len = cpu_to_le16(data_len);
488
Szymon Janc4e51eae2011-02-25 19:05:48 +0100489 if (data)
490 memcpy(skb_put(skb, data_len), data, data_len);
Johan Hedbergc542a062011-01-26 13:11:03 +0200491
492 hci_send_to_sock(NULL, skb, skip_sk);
493 kfree_skb(skb);
494
495 return 0;
496}
497
Johan Hedberg053f0212011-01-26 13:07:10 +0200498static int send_mode_rsp(struct sock *sk, u16 opcode, u16 index, u8 val)
499{
Johan Hedberga38528f2011-01-22 06:46:43 +0200500 struct mgmt_mode rp;
Johan Hedberg053f0212011-01-26 13:07:10 +0200501
Johan Hedberga38528f2011-01-22 06:46:43 +0200502 rp.val = val;
Johan Hedberg053f0212011-01-26 13:07:10 +0200503
Szymon Janc4e51eae2011-02-25 19:05:48 +0100504 return cmd_complete(sk, index, opcode, &rp, sizeof(rp));
Johan Hedberg053f0212011-01-26 13:07:10 +0200505}
506
Szymon Janc4e51eae2011-02-25 19:05:48 +0100507static int set_pairable(struct sock *sk, u16 index, unsigned char *data,
508 u16 len)
Johan Hedbergc542a062011-01-26 13:11:03 +0200509{
510 struct mgmt_mode *cp, ev;
511 struct hci_dev *hdev;
Johan Hedbergc542a062011-01-26 13:11:03 +0200512 int err;
513
514 cp = (void *) data;
Johan Hedbergc542a062011-01-26 13:11:03 +0200515
Szymon Janc4e51eae2011-02-25 19:05:48 +0100516 BT_DBG("request for hci%u", index);
Johan Hedbergc542a062011-01-26 13:11:03 +0200517
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100518 if (len != sizeof(*cp))
519 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE, EINVAL);
520
Szymon Janc4e51eae2011-02-25 19:05:48 +0100521 hdev = hci_dev_get(index);
Johan Hedbergc542a062011-01-26 13:11:03 +0200522 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100523 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE, ENODEV);
Johan Hedbergc542a062011-01-26 13:11:03 +0200524
Andre Guedes8c156c32011-07-07 10:30:36 -0300525 hci_dev_lock_bh(hdev);
Johan Hedbergc542a062011-01-26 13:11:03 +0200526
527 if (cp->val)
528 set_bit(HCI_PAIRABLE, &hdev->flags);
529 else
530 clear_bit(HCI_PAIRABLE, &hdev->flags);
531
Szymon Janc4e51eae2011-02-25 19:05:48 +0100532 err = send_mode_rsp(sk, MGMT_OP_SET_PAIRABLE, index, cp->val);
Johan Hedbergc542a062011-01-26 13:11:03 +0200533 if (err < 0)
534 goto failed;
535
Johan Hedbergc542a062011-01-26 13:11:03 +0200536 ev.val = cp->val;
537
Johan Hedberg744cf192011-11-08 20:40:14 +0200538 err = mgmt_event(MGMT_EV_PAIRABLE, hdev, &ev, sizeof(ev), sk);
Johan Hedbergc542a062011-01-26 13:11:03 +0200539
540failed:
Andre Guedes8c156c32011-07-07 10:30:36 -0300541 hci_dev_unlock_bh(hdev);
Johan Hedbergc542a062011-01-26 13:11:03 +0200542 hci_dev_put(hdev);
543
544 return err;
545}
546
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300547#define EIR_FLAGS 0x01 /* flags */
548#define EIR_UUID16_SOME 0x02 /* 16-bit UUID, more available */
549#define EIR_UUID16_ALL 0x03 /* 16-bit UUID, all listed */
550#define EIR_UUID32_SOME 0x04 /* 32-bit UUID, more available */
551#define EIR_UUID32_ALL 0x05 /* 32-bit UUID, all listed */
552#define EIR_UUID128_SOME 0x06 /* 128-bit UUID, more available */
553#define EIR_UUID128_ALL 0x07 /* 128-bit UUID, all listed */
554#define EIR_NAME_SHORT 0x08 /* shortened local name */
555#define EIR_NAME_COMPLETE 0x09 /* complete local name */
556#define EIR_TX_POWER 0x0A /* transmit power level */
557#define EIR_DEVICE_ID 0x10 /* device ID */
558
559#define PNP_INFO_SVCLASS_ID 0x1200
560
561static u8 bluetooth_base_uuid[] = {
562 0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80,
563 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
564};
565
566static u16 get_uuid16(u8 *uuid128)
567{
568 u32 val;
569 int i;
570
571 for (i = 0; i < 12; i++) {
572 if (bluetooth_base_uuid[i] != uuid128[i])
573 return 0;
574 }
575
576 memcpy(&val, &uuid128[12], 4);
577
578 val = le32_to_cpu(val);
579 if (val > 0xffff)
580 return 0;
581
582 return (u16) val;
583}
584
585static void create_eir(struct hci_dev *hdev, u8 *data)
586{
587 u8 *ptr = data;
588 u16 eir_len = 0;
589 u16 uuid16_list[HCI_MAX_EIR_LENGTH / sizeof(u16)];
590 int i, truncated = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200591 struct bt_uuid *uuid;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300592 size_t name_len;
593
594 name_len = strlen(hdev->dev_name);
595
596 if (name_len > 0) {
597 /* EIR Data type */
598 if (name_len > 48) {
599 name_len = 48;
600 ptr[1] = EIR_NAME_SHORT;
601 } else
602 ptr[1] = EIR_NAME_COMPLETE;
603
604 /* EIR Data length */
605 ptr[0] = name_len + 1;
606
607 memcpy(ptr + 2, hdev->dev_name, name_len);
608
609 eir_len += (name_len + 2);
610 ptr += (name_len + 2);
611 }
612
613 memset(uuid16_list, 0, sizeof(uuid16_list));
614
615 /* Group all UUID16 types */
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200616 list_for_each_entry(uuid, &hdev->uuids, list) {
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300617 u16 uuid16;
618
619 uuid16 = get_uuid16(uuid->uuid);
620 if (uuid16 == 0)
621 return;
622
623 if (uuid16 < 0x1100)
624 continue;
625
626 if (uuid16 == PNP_INFO_SVCLASS_ID)
627 continue;
628
629 /* Stop if not enough space to put next UUID */
630 if (eir_len + 2 + sizeof(u16) > HCI_MAX_EIR_LENGTH) {
631 truncated = 1;
632 break;
633 }
634
635 /* Check for duplicates */
636 for (i = 0; uuid16_list[i] != 0; i++)
637 if (uuid16_list[i] == uuid16)
638 break;
639
640 if (uuid16_list[i] == 0) {
641 uuid16_list[i] = uuid16;
642 eir_len += sizeof(u16);
643 }
644 }
645
646 if (uuid16_list[0] != 0) {
647 u8 *length = ptr;
648
649 /* EIR Data type */
650 ptr[1] = truncated ? EIR_UUID16_SOME : EIR_UUID16_ALL;
651
652 ptr += 2;
653 eir_len += 2;
654
655 for (i = 0; uuid16_list[i] != 0; i++) {
656 *ptr++ = (uuid16_list[i] & 0x00ff);
657 *ptr++ = (uuid16_list[i] & 0xff00) >> 8;
658 }
659
660 /* EIR Data length */
661 *length = (i * sizeof(u16)) + 1;
662 }
663}
664
665static int update_eir(struct hci_dev *hdev)
666{
667 struct hci_cp_write_eir cp;
668
669 if (!(hdev->features[6] & LMP_EXT_INQ))
670 return 0;
671
672 if (hdev->ssp_mode == 0)
673 return 0;
674
675 if (test_bit(HCI_SERVICE_CACHE, &hdev->flags))
676 return 0;
677
678 memset(&cp, 0, sizeof(cp));
679
680 create_eir(hdev, cp.data);
681
682 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
683 return 0;
684
685 memcpy(hdev->eir, cp.data, sizeof(cp.data));
686
687 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
688}
689
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200690static u8 get_service_classes(struct hci_dev *hdev)
691{
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300692 struct bt_uuid *uuid;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200693 u8 val = 0;
694
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300695 list_for_each_entry(uuid, &hdev->uuids, list)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200696 val |= uuid->svc_hint;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200697
698 return val;
699}
700
701static int update_class(struct hci_dev *hdev)
702{
703 u8 cod[3];
704
705 BT_DBG("%s", hdev->name);
706
707 if (test_bit(HCI_SERVICE_CACHE, &hdev->flags))
708 return 0;
709
710 cod[0] = hdev->minor_class;
711 cod[1] = hdev->major_class;
712 cod[2] = get_service_classes(hdev);
713
714 if (memcmp(cod, hdev->dev_class, 3) == 0)
715 return 0;
716
717 return hci_send_cmd(hdev, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
718}
719
Szymon Janc4e51eae2011-02-25 19:05:48 +0100720static int add_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200721{
722 struct mgmt_cp_add_uuid *cp;
723 struct hci_dev *hdev;
724 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200725 int err;
726
727 cp = (void *) data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200728
Szymon Janc4e51eae2011-02-25 19:05:48 +0100729 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200730
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100731 if (len != sizeof(*cp))
732 return cmd_status(sk, index, MGMT_OP_ADD_UUID, EINVAL);
733
Szymon Janc4e51eae2011-02-25 19:05:48 +0100734 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200735 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100736 return cmd_status(sk, index, MGMT_OP_ADD_UUID, ENODEV);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200737
Andre Guedes8c156c32011-07-07 10:30:36 -0300738 hci_dev_lock_bh(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200739
740 uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC);
741 if (!uuid) {
742 err = -ENOMEM;
743 goto failed;
744 }
745
746 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200747 uuid->svc_hint = cp->svc_hint;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200748
749 list_add(&uuid->list, &hdev->uuids);
750
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200751 err = update_class(hdev);
752 if (err < 0)
753 goto failed;
754
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300755 err = update_eir(hdev);
756 if (err < 0)
757 goto failed;
758
Szymon Janc4e51eae2011-02-25 19:05:48 +0100759 err = cmd_complete(sk, index, MGMT_OP_ADD_UUID, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200760
761failed:
Andre Guedes8c156c32011-07-07 10:30:36 -0300762 hci_dev_unlock_bh(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200763 hci_dev_put(hdev);
764
765 return err;
766}
767
Szymon Janc4e51eae2011-02-25 19:05:48 +0100768static int remove_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200769{
770 struct list_head *p, *n;
Szymon Janc779cb852011-02-25 19:05:47 +0100771 struct mgmt_cp_remove_uuid *cp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200772 struct hci_dev *hdev;
773 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 +0200774 int err, found;
775
776 cp = (void *) data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200777
Szymon Janc4e51eae2011-02-25 19:05:48 +0100778 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200779
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100780 if (len != sizeof(*cp))
781 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID, EINVAL);
782
Szymon Janc4e51eae2011-02-25 19:05:48 +0100783 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200784 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100785 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID, ENODEV);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200786
Andre Guedes8c156c32011-07-07 10:30:36 -0300787 hci_dev_lock_bh(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200788
789 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
790 err = hci_uuids_clear(hdev);
791 goto unlock;
792 }
793
794 found = 0;
795
796 list_for_each_safe(p, n, &hdev->uuids) {
797 struct bt_uuid *match = list_entry(p, struct bt_uuid, list);
798
799 if (memcmp(match->uuid, cp->uuid, 16) != 0)
800 continue;
801
802 list_del(&match->list);
803 found++;
804 }
805
806 if (found == 0) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100807 err = cmd_status(sk, index, MGMT_OP_REMOVE_UUID, ENOENT);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200808 goto unlock;
809 }
810
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200811 err = update_class(hdev);
812 if (err < 0)
813 goto unlock;
814
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300815 err = update_eir(hdev);
816 if (err < 0)
817 goto unlock;
818
Szymon Janc4e51eae2011-02-25 19:05:48 +0100819 err = cmd_complete(sk, index, MGMT_OP_REMOVE_UUID, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200820
821unlock:
Andre Guedes8c156c32011-07-07 10:30:36 -0300822 hci_dev_unlock_bh(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200823 hci_dev_put(hdev);
824
825 return err;
826}
827
Szymon Janc4e51eae2011-02-25 19:05:48 +0100828static int set_dev_class(struct sock *sk, u16 index, unsigned char *data,
829 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200830{
831 struct hci_dev *hdev;
832 struct mgmt_cp_set_dev_class *cp;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200833 int err;
834
835 cp = (void *) data;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200836
Szymon Janc4e51eae2011-02-25 19:05:48 +0100837 BT_DBG("request for hci%u", index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200838
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100839 if (len != sizeof(*cp))
840 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS, EINVAL);
841
Szymon Janc4e51eae2011-02-25 19:05:48 +0100842 hdev = hci_dev_get(index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200843 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100844 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS, ENODEV);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200845
Andre Guedes8c156c32011-07-07 10:30:36 -0300846 hci_dev_lock_bh(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200847
848 hdev->major_class = cp->major;
849 hdev->minor_class = cp->minor;
850
851 err = update_class(hdev);
852
853 if (err == 0)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100854 err = cmd_complete(sk, index, MGMT_OP_SET_DEV_CLASS, NULL, 0);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200855
Andre Guedes8c156c32011-07-07 10:30:36 -0300856 hci_dev_unlock_bh(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200857 hci_dev_put(hdev);
858
859 return err;
860}
861
Szymon Janc4e51eae2011-02-25 19:05:48 +0100862static int set_service_cache(struct sock *sk, u16 index, unsigned char *data,
863 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200864{
865 struct hci_dev *hdev;
866 struct mgmt_cp_set_service_cache *cp;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200867 int err;
868
869 cp = (void *) data;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200870
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100871 if (len != sizeof(*cp))
Szymon Jancb8534e02011-03-01 16:55:34 +0100872 return cmd_status(sk, index, MGMT_OP_SET_SERVICE_CACHE, EINVAL);
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100873
Szymon Janc4e51eae2011-02-25 19:05:48 +0100874 hdev = hci_dev_get(index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200875 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100876 return cmd_status(sk, index, MGMT_OP_SET_SERVICE_CACHE, ENODEV);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200877
Andre Guedes8c156c32011-07-07 10:30:36 -0300878 hci_dev_lock_bh(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200879
Szymon Janc4e51eae2011-02-25 19:05:48 +0100880 BT_DBG("hci%u enable %d", index, cp->enable);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200881
882 if (cp->enable) {
883 set_bit(HCI_SERVICE_CACHE, &hdev->flags);
884 err = 0;
885 } else {
886 clear_bit(HCI_SERVICE_CACHE, &hdev->flags);
887 err = update_class(hdev);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300888 if (err == 0)
889 err = update_eir(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200890 }
891
892 if (err == 0)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100893 err = cmd_complete(sk, index, MGMT_OP_SET_SERVICE_CACHE, NULL,
894 0);
Gustavo F. Padovane5b82e52011-10-15 18:03:15 -0300895 else
896 cmd_status(sk, index, MGMT_OP_SET_SERVICE_CACHE, -err);
897
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200898
Andre Guedes8c156c32011-07-07 10:30:36 -0300899 hci_dev_unlock_bh(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200900 hci_dev_put(hdev);
901
902 return err;
903}
904
Johan Hedberg86742e12011-11-07 23:13:38 +0200905static int load_link_keys(struct sock *sk, u16 index, unsigned char *data,
906 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200907{
908 struct hci_dev *hdev;
Johan Hedberg86742e12011-11-07 23:13:38 +0200909 struct mgmt_cp_load_link_keys *cp;
Szymon Janc4e51eae2011-02-25 19:05:48 +0100910 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -0300911 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200912
913 cp = (void *) data;
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100914
915 if (len < sizeof(*cp))
Johan Hedberg86742e12011-11-07 23:13:38 +0200916 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS, EINVAL);
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100917
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200918 key_count = get_unaligned_le16(&cp->key_count);
919
Johan Hedberg86742e12011-11-07 23:13:38 +0200920 expected_len = sizeof(*cp) + key_count *
921 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -0300922 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +0200923 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -0300924 len, expected_len);
Johan Hedberg86742e12011-11-07 23:13:38 +0200925 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS, EINVAL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200926 }
927
Szymon Janc4e51eae2011-02-25 19:05:48 +0100928 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200929 if (!hdev)
Johan Hedberg86742e12011-11-07 23:13:38 +0200930 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS, ENODEV);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200931
Szymon Janc4e51eae2011-02-25 19:05:48 +0100932 BT_DBG("hci%u debug_keys %u key_count %u", index, cp->debug_keys,
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200933 key_count);
934
Andre Guedes8c156c32011-07-07 10:30:36 -0300935 hci_dev_lock_bh(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200936
937 hci_link_keys_clear(hdev);
938
939 set_bit(HCI_LINK_KEYS, &hdev->flags);
940
941 if (cp->debug_keys)
942 set_bit(HCI_DEBUG_KEYS, &hdev->flags);
943 else
944 clear_bit(HCI_DEBUG_KEYS, &hdev->flags);
945
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -0300946 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +0200947 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200948
Johan Hedbergd25e28a2011-04-28 11:28:59 -0700949 hci_add_link_key(hdev, NULL, 0, &key->bdaddr, key->val, key->type,
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200950 key->pin_len);
951 }
952
Andre Guedes8c156c32011-07-07 10:30:36 -0300953 hci_dev_unlock_bh(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200954 hci_dev_put(hdev);
955
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -0300956 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200957}
958
Johan Hedberg86742e12011-11-07 23:13:38 +0200959static int remove_keys(struct sock *sk, u16 index, unsigned char *data,
960 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200961{
962 struct hci_dev *hdev;
Johan Hedberg86742e12011-11-07 23:13:38 +0200963 struct mgmt_cp_remove_keys *cp;
Johan Hedberga8a1d192011-11-10 15:54:38 +0200964 struct mgmt_rp_remove_keys rp;
965 struct hci_cp_disconnect dc;
966 struct pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200967 struct hci_conn *conn;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200968 int err;
969
970 cp = (void *) data;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200971
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100972 if (len != sizeof(*cp))
Johan Hedberg86742e12011-11-07 23:13:38 +0200973 return cmd_status(sk, index, MGMT_OP_REMOVE_KEYS, EINVAL);
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100974
Szymon Janc4e51eae2011-02-25 19:05:48 +0100975 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200976 if (!hdev)
Johan Hedberg86742e12011-11-07 23:13:38 +0200977 return cmd_status(sk, index, MGMT_OP_REMOVE_KEYS, ENODEV);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200978
Andre Guedes8c156c32011-07-07 10:30:36 -0300979 hci_dev_lock_bh(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200980
Johan Hedberga8a1d192011-11-10 15:54:38 +0200981 memset(&rp, 0, sizeof(rp));
982 bacpy(&rp.bdaddr, &cp->bdaddr);
983
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200984 err = hci_remove_link_key(hdev, &cp->bdaddr);
Johan Hedberga8a1d192011-11-10 15:54:38 +0200985 if (err < 0)
986 goto unlock;
987
988 if (!test_bit(HCI_UP, &hdev->flags) || !cp->disconnect) {
989 err = cmd_complete(sk, index, MGMT_OP_REMOVE_KEYS, &rp,
990 sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200991 goto unlock;
992 }
993
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200994 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
Johan Hedberga8a1d192011-11-10 15:54:38 +0200995 if (!conn) {
996 err = cmd_complete(sk, index, MGMT_OP_REMOVE_KEYS, &rp,
997 sizeof(rp));
998 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200999 }
1000
Johan Hedberga8a1d192011-11-10 15:54:38 +02001001 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_KEYS, hdev, cp, sizeof(*cp));
1002 if (!cmd) {
1003 err = -ENOMEM;
1004 goto unlock;
1005 }
1006
1007 put_unaligned_le16(conn->handle, &dc.handle);
1008 dc.reason = 0x13; /* Remote User Terminated Connection */
1009 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1010 if (err < 0)
1011 mgmt_pending_remove(cmd);
1012
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001013unlock:
Johan Hedberga8a1d192011-11-10 15:54:38 +02001014 if (err < 0) {
1015 rp.status = -err;
1016 err = cmd_complete(sk, index, MGMT_OP_REMOVE_KEYS, &rp,
1017 sizeof(rp));
1018 }
Andre Guedes8c156c32011-07-07 10:30:36 -03001019 hci_dev_unlock_bh(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001020 hci_dev_put(hdev);
1021
1022 return err;
1023}
1024
Szymon Janc4e51eae2011-02-25 19:05:48 +01001025static int disconnect(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02001026{
1027 struct hci_dev *hdev;
1028 struct mgmt_cp_disconnect *cp;
1029 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03001030 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001031 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001032 int err;
1033
1034 BT_DBG("");
1035
1036 cp = (void *) data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001037
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001038 if (len != sizeof(*cp))
1039 return cmd_status(sk, index, MGMT_OP_DISCONNECT, EINVAL);
1040
Szymon Janc4e51eae2011-02-25 19:05:48 +01001041 hdev = hci_dev_get(index);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001042 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001043 return cmd_status(sk, index, MGMT_OP_DISCONNECT, ENODEV);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001044
Andre Guedes8c156c32011-07-07 10:30:36 -03001045 hci_dev_lock_bh(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001046
1047 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001048 err = cmd_status(sk, index, MGMT_OP_DISCONNECT, ENETDOWN);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001049 goto failed;
1050 }
1051
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001052 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001053 err = cmd_status(sk, index, MGMT_OP_DISCONNECT, EBUSY);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001054 goto failed;
1055 }
1056
1057 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03001058 if (!conn)
1059 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->bdaddr);
1060
Johan Hedberg8962ee72011-01-20 12:40:27 +02001061 if (!conn) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001062 err = cmd_status(sk, index, MGMT_OP_DISCONNECT, ENOTCONN);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001063 goto failed;
1064 }
1065
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001066 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001067 if (!cmd) {
1068 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001069 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001070 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001071
1072 put_unaligned_le16(conn->handle, &dc.handle);
1073 dc.reason = 0x13; /* Remote User Terminated Connection */
1074
1075 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1076 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001077 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001078
1079failed:
Andre Guedes8c156c32011-07-07 10:30:36 -03001080 hci_dev_unlock_bh(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001081 hci_dev_put(hdev);
1082
1083 return err;
1084}
1085
Johan Hedberg48264f02011-11-09 13:58:58 +02001086static u8 link_to_mgmt(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02001087{
1088 switch (link_type) {
1089 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02001090 switch (addr_type) {
1091 case ADDR_LE_DEV_PUBLIC:
1092 return MGMT_ADDR_LE_PUBLIC;
1093 case ADDR_LE_DEV_RANDOM:
1094 return MGMT_ADDR_LE_RANDOM;
1095 default:
1096 return MGMT_ADDR_INVALID;
1097 }
Johan Hedberg4c659c32011-11-07 23:13:39 +02001098 case ACL_LINK:
1099 return MGMT_ADDR_BREDR;
1100 default:
1101 return MGMT_ADDR_INVALID;
1102 }
1103}
1104
Szymon Janc8ce62842011-03-01 16:55:32 +01001105static int get_connections(struct sock *sk, u16 index)
Johan Hedberg2784eb42011-01-21 13:56:35 +02001106{
Johan Hedberg2784eb42011-01-21 13:56:35 +02001107 struct mgmt_rp_get_connections *rp;
1108 struct hci_dev *hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001109 struct hci_conn *c;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001110 struct list_head *p;
Johan Hedberga38528f2011-01-22 06:46:43 +02001111 size_t rp_len;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001112 u16 count;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001113 int i, err;
1114
1115 BT_DBG("");
1116
Szymon Janc4e51eae2011-02-25 19:05:48 +01001117 hdev = hci_dev_get(index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001118 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001119 return cmd_status(sk, index, MGMT_OP_GET_CONNECTIONS, ENODEV);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001120
Andre Guedes8c156c32011-07-07 10:30:36 -03001121 hci_dev_lock_bh(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001122
1123 count = 0;
1124 list_for_each(p, &hdev->conn_hash.list) {
1125 count++;
1126 }
1127
Johan Hedberg4c659c32011-11-07 23:13:39 +02001128 rp_len = sizeof(*rp) + (count * sizeof(struct mgmt_addr_info));
Johan Hedberga38528f2011-01-22 06:46:43 +02001129 rp = kmalloc(rp_len, GFP_ATOMIC);
1130 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02001131 err = -ENOMEM;
1132 goto unlock;
1133 }
1134
Johan Hedberg2784eb42011-01-21 13:56:35 +02001135 put_unaligned_le16(count, &rp->conn_count);
1136
Johan Hedberg2784eb42011-01-21 13:56:35 +02001137 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001138 list_for_each_entry(c, &hdev->conn_hash.list, list) {
1139 bacpy(&rp->addr[i].bdaddr, &c->dst);
Johan Hedberg48264f02011-11-09 13:58:58 +02001140 rp->addr[i].type = link_to_mgmt(c->type, c->dst_type);
Johan Hedberg4c659c32011-11-07 23:13:39 +02001141 if (rp->addr[i].type == MGMT_ADDR_INVALID)
1142 continue;
1143 i++;
1144 }
1145
1146 /* Recalculate length in case of filtered SCO connections, etc */
1147 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02001148
Szymon Janc4e51eae2011-02-25 19:05:48 +01001149 err = cmd_complete(sk, index, MGMT_OP_GET_CONNECTIONS, rp, rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001150
1151unlock:
Johan Hedberga38528f2011-01-22 06:46:43 +02001152 kfree(rp);
Andre Guedes8c156c32011-07-07 10:30:36 -03001153 hci_dev_unlock_bh(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001154 hci_dev_put(hdev);
1155 return err;
1156}
1157
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001158static int send_pin_code_neg_reply(struct sock *sk, u16 index,
1159 struct hci_dev *hdev, struct mgmt_cp_pin_code_neg_reply *cp)
1160{
1161 struct pending_cmd *cmd;
1162 int err;
1163
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001164 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001165 sizeof(*cp));
1166 if (!cmd)
1167 return -ENOMEM;
1168
1169 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY, sizeof(cp->bdaddr),
1170 &cp->bdaddr);
1171 if (err < 0)
1172 mgmt_pending_remove(cmd);
1173
1174 return err;
1175}
1176
Szymon Janc4e51eae2011-02-25 19:05:48 +01001177static int pin_code_reply(struct sock *sk, u16 index, unsigned char *data,
1178 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001179{
1180 struct hci_dev *hdev;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001181 struct hci_conn *conn;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001182 struct mgmt_cp_pin_code_reply *cp;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001183 struct mgmt_cp_pin_code_neg_reply ncp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001184 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03001185 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001186 int err;
1187
1188 BT_DBG("");
1189
1190 cp = (void *) data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001191
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001192 if (len != sizeof(*cp))
1193 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, EINVAL);
1194
Szymon Janc4e51eae2011-02-25 19:05:48 +01001195 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001196 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001197 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENODEV);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001198
Andre Guedes8c156c32011-07-07 10:30:36 -03001199 hci_dev_lock_bh(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001200
1201 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001202 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENETDOWN);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001203 goto failed;
1204 }
1205
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001206 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
1207 if (!conn) {
1208 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENOTCONN);
1209 goto failed;
1210 }
1211
1212 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
1213 bacpy(&ncp.bdaddr, &cp->bdaddr);
1214
1215 BT_ERR("PIN code is not 16 bytes long");
1216
1217 err = send_pin_code_neg_reply(sk, index, hdev, &ncp);
1218 if (err >= 0)
1219 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1220 EINVAL);
1221
1222 goto failed;
1223 }
1224
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001225 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001226 if (!cmd) {
1227 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001228 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001229 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02001230
1231 bacpy(&reply.bdaddr, &cp->bdaddr);
1232 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02001233 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02001234
1235 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
1236 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001237 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001238
1239failed:
Andre Guedes8c156c32011-07-07 10:30:36 -03001240 hci_dev_unlock_bh(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001241 hci_dev_put(hdev);
1242
1243 return err;
1244}
1245
Szymon Janc4e51eae2011-02-25 19:05:48 +01001246static int pin_code_neg_reply(struct sock *sk, u16 index, unsigned char *data,
1247 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001248{
1249 struct hci_dev *hdev;
1250 struct mgmt_cp_pin_code_neg_reply *cp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001251 int err;
1252
1253 BT_DBG("");
1254
1255 cp = (void *) data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001256
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001257 if (len != sizeof(*cp))
1258 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1259 EINVAL);
1260
Szymon Janc4e51eae2011-02-25 19:05:48 +01001261 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001262 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001263 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1264 ENODEV);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001265
Andre Guedes8c156c32011-07-07 10:30:36 -03001266 hci_dev_lock_bh(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001267
1268 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001269 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1270 ENETDOWN);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001271 goto failed;
1272 }
1273
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001274 err = send_pin_code_neg_reply(sk, index, hdev, cp);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001275
1276failed:
Andre Guedes8c156c32011-07-07 10:30:36 -03001277 hci_dev_unlock_bh(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001278 hci_dev_put(hdev);
1279
1280 return err;
1281}
1282
Szymon Janc4e51eae2011-02-25 19:05:48 +01001283static int set_io_capability(struct sock *sk, u16 index, unsigned char *data,
1284 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001285{
1286 struct hci_dev *hdev;
1287 struct mgmt_cp_set_io_capability *cp;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001288
1289 BT_DBG("");
1290
1291 cp = (void *) data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001292
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001293 if (len != sizeof(*cp))
Szymon Jancb8534e02011-03-01 16:55:34 +01001294 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY, EINVAL);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001295
Szymon Janc4e51eae2011-02-25 19:05:48 +01001296 hdev = hci_dev_get(index);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001297 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001298 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY, ENODEV);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001299
Andre Guedes8c156c32011-07-07 10:30:36 -03001300 hci_dev_lock_bh(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001301
1302 hdev->io_capability = cp->io_capability;
1303
1304 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Szymon Jancb8534e02011-03-01 16:55:34 +01001305 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001306
Andre Guedes8c156c32011-07-07 10:30:36 -03001307 hci_dev_unlock_bh(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001308 hci_dev_put(hdev);
1309
Szymon Janc4e51eae2011-02-25 19:05:48 +01001310 return cmd_complete(sk, index, MGMT_OP_SET_IO_CAPABILITY, NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001311}
1312
Johan Hedberge9a416b2011-02-19 12:05:56 -03001313static inline struct pending_cmd *find_pairing(struct hci_conn *conn)
1314{
1315 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001316 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001317
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001318 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03001319 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
1320 continue;
1321
Johan Hedberge9a416b2011-02-19 12:05:56 -03001322 if (cmd->user_data != conn)
1323 continue;
1324
1325 return cmd;
1326 }
1327
1328 return NULL;
1329}
1330
1331static void pairing_complete(struct pending_cmd *cmd, u8 status)
1332{
1333 struct mgmt_rp_pair_device rp;
1334 struct hci_conn *conn = cmd->user_data;
1335
Johan Hedberge9a416b2011-02-19 12:05:56 -03001336 bacpy(&rp.bdaddr, &conn->dst);
1337 rp.status = status;
1338
Szymon Janc4e51eae2011-02-25 19:05:48 +01001339 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001340
1341 /* So we don't get further callbacks for this connection */
1342 conn->connect_cfm_cb = NULL;
1343 conn->security_cfm_cb = NULL;
1344 conn->disconn_cfm_cb = NULL;
1345
1346 hci_conn_put(conn);
1347
Johan Hedberga664b5b2011-02-19 12:06:02 -03001348 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001349}
1350
1351static void pairing_complete_cb(struct hci_conn *conn, u8 status)
1352{
1353 struct pending_cmd *cmd;
1354
1355 BT_DBG("status %u", status);
1356
Johan Hedberg56e5cb82011-11-08 20:40:16 +02001357 cmd = find_pairing(conn);
1358 if (!cmd)
1359 BT_DBG("Unable to find a pending command");
1360 else
1361 pairing_complete(cmd, status);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001362}
1363
Szymon Janc4e51eae2011-02-25 19:05:48 +01001364static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001365{
1366 struct hci_dev *hdev;
1367 struct mgmt_cp_pair_device *cp;
1368 struct pending_cmd *cmd;
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001369 struct adv_entry *entry;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001370 u8 sec_level, auth_type;
1371 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001372 int err;
1373
1374 BT_DBG("");
1375
1376 cp = (void *) data;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001377
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001378 if (len != sizeof(*cp))
1379 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, EINVAL);
1380
Szymon Janc4e51eae2011-02-25 19:05:48 +01001381 hdev = hci_dev_get(index);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001382 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001383 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, ENODEV);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001384
Andre Guedes8c156c32011-07-07 10:30:36 -03001385 hci_dev_lock_bh(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001386
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001387 sec_level = BT_SECURITY_MEDIUM;
1388 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001389 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001390 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03001391 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001392
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001393 entry = hci_find_adv_entry(hdev, &cp->bdaddr);
1394 if (entry)
1395 conn = hci_connect(hdev, LE_LINK, &cp->bdaddr, sec_level,
1396 auth_type);
1397 else
1398 conn = hci_connect(hdev, ACL_LINK, &cp->bdaddr, sec_level,
1399 auth_type);
1400
Ville Tervo30e76272011-02-22 16:10:53 -03001401 if (IS_ERR(conn)) {
1402 err = PTR_ERR(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001403 goto unlock;
1404 }
1405
1406 if (conn->connect_cfm_cb) {
1407 hci_conn_put(conn);
Szymon Janc4e51eae2011-02-25 19:05:48 +01001408 err = cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, EBUSY);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001409 goto unlock;
1410 }
1411
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001412 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001413 if (!cmd) {
1414 err = -ENOMEM;
1415 hci_conn_put(conn);
1416 goto unlock;
1417 }
1418
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001419 /* For LE, just connecting isn't a proof that the pairing finished */
1420 if (!entry)
1421 conn->connect_cfm_cb = pairing_complete_cb;
1422
Johan Hedberge9a416b2011-02-19 12:05:56 -03001423 conn->security_cfm_cb = pairing_complete_cb;
1424 conn->disconn_cfm_cb = pairing_complete_cb;
1425 conn->io_capability = cp->io_cap;
1426 cmd->user_data = conn;
1427
1428 if (conn->state == BT_CONNECTED &&
1429 hci_conn_security(conn, sec_level, auth_type))
1430 pairing_complete(cmd, 0);
1431
1432 err = 0;
1433
1434unlock:
Andre Guedes8c156c32011-07-07 10:30:36 -03001435 hci_dev_unlock_bh(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001436 hci_dev_put(hdev);
1437
1438 return err;
1439}
1440
Szymon Janc4e51eae2011-02-25 19:05:48 +01001441static int user_confirm_reply(struct sock *sk, u16 index, unsigned char *data,
1442 u16 len, int success)
Johan Hedberga5c29682011-02-19 12:05:57 -03001443{
1444 struct mgmt_cp_user_confirm_reply *cp = (void *) data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001445 u16 mgmt_op, hci_op;
Johan Hedberga5c29682011-02-19 12:05:57 -03001446 struct pending_cmd *cmd;
1447 struct hci_dev *hdev;
1448 int err;
1449
1450 BT_DBG("");
1451
Johan Hedberga5c29682011-02-19 12:05:57 -03001452 if (success) {
1453 mgmt_op = MGMT_OP_USER_CONFIRM_REPLY;
1454 hci_op = HCI_OP_USER_CONFIRM_REPLY;
1455 } else {
1456 mgmt_op = MGMT_OP_USER_CONFIRM_NEG_REPLY;
1457 hci_op = HCI_OP_USER_CONFIRM_NEG_REPLY;
1458 }
1459
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001460 if (len != sizeof(*cp))
1461 return cmd_status(sk, index, mgmt_op, EINVAL);
1462
Szymon Janc4e51eae2011-02-25 19:05:48 +01001463 hdev = hci_dev_get(index);
Johan Hedberga5c29682011-02-19 12:05:57 -03001464 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001465 return cmd_status(sk, index, mgmt_op, ENODEV);
Johan Hedberga5c29682011-02-19 12:05:57 -03001466
Andre Guedes8c156c32011-07-07 10:30:36 -03001467 hci_dev_lock_bh(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02001468
Johan Hedberga5c29682011-02-19 12:05:57 -03001469 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001470 err = cmd_status(sk, index, mgmt_op, ENETDOWN);
Johan Hedberga5c29682011-02-19 12:05:57 -03001471 goto failed;
1472 }
1473
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001474 cmd = mgmt_pending_add(sk, mgmt_op, hdev, data, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03001475 if (!cmd) {
1476 err = -ENOMEM;
1477 goto failed;
1478 }
1479
1480 err = hci_send_cmd(hdev, hci_op, sizeof(cp->bdaddr), &cp->bdaddr);
Johan Hedberga664b5b2011-02-19 12:06:02 -03001481 if (err < 0)
1482 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03001483
1484failed:
Andre Guedes8c156c32011-07-07 10:30:36 -03001485 hci_dev_unlock_bh(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03001486 hci_dev_put(hdev);
1487
1488 return err;
1489}
1490
Johan Hedbergb312b1612011-03-16 14:29:37 +02001491static int set_local_name(struct sock *sk, u16 index, unsigned char *data,
1492 u16 len)
1493{
1494 struct mgmt_cp_set_local_name *mgmt_cp = (void *) data;
1495 struct hci_cp_write_local_name hci_cp;
1496 struct hci_dev *hdev;
1497 struct pending_cmd *cmd;
1498 int err;
1499
1500 BT_DBG("");
1501
1502 if (len != sizeof(*mgmt_cp))
1503 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, EINVAL);
1504
1505 hdev = hci_dev_get(index);
1506 if (!hdev)
1507 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, ENODEV);
1508
Andre Guedes8c156c32011-07-07 10:30:36 -03001509 hci_dev_lock_bh(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001510
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001511 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001512 if (!cmd) {
1513 err = -ENOMEM;
1514 goto failed;
1515 }
1516
1517 memcpy(hci_cp.name, mgmt_cp->name, sizeof(hci_cp.name));
1518 err = hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(hci_cp),
1519 &hci_cp);
1520 if (err < 0)
1521 mgmt_pending_remove(cmd);
1522
1523failed:
Andre Guedes8c156c32011-07-07 10:30:36 -03001524 hci_dev_unlock_bh(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001525 hci_dev_put(hdev);
1526
1527 return err;
1528}
1529
Szymon Jancc35938b2011-03-22 13:12:21 +01001530static int read_local_oob_data(struct sock *sk, u16 index)
1531{
1532 struct hci_dev *hdev;
1533 struct pending_cmd *cmd;
1534 int err;
1535
1536 BT_DBG("hci%u", index);
1537
1538 hdev = hci_dev_get(index);
1539 if (!hdev)
1540 return cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
1541 ENODEV);
1542
Andre Guedes8c156c32011-07-07 10:30:36 -03001543 hci_dev_lock_bh(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01001544
1545 if (!test_bit(HCI_UP, &hdev->flags)) {
1546 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
1547 ENETDOWN);
1548 goto unlock;
1549 }
1550
1551 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
1552 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
1553 EOPNOTSUPP);
1554 goto unlock;
1555 }
1556
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001557 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Szymon Jancc35938b2011-03-22 13:12:21 +01001558 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA, EBUSY);
1559 goto unlock;
1560 }
1561
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001562 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01001563 if (!cmd) {
1564 err = -ENOMEM;
1565 goto unlock;
1566 }
1567
1568 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
1569 if (err < 0)
1570 mgmt_pending_remove(cmd);
1571
1572unlock:
Andre Guedes8c156c32011-07-07 10:30:36 -03001573 hci_dev_unlock_bh(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01001574 hci_dev_put(hdev);
1575
1576 return err;
1577}
1578
Szymon Janc2763eda2011-03-22 13:12:22 +01001579static int add_remote_oob_data(struct sock *sk, u16 index, unsigned char *data,
1580 u16 len)
1581{
1582 struct hci_dev *hdev;
1583 struct mgmt_cp_add_remote_oob_data *cp = (void *) data;
1584 int err;
1585
1586 BT_DBG("hci%u ", index);
1587
1588 if (len != sizeof(*cp))
1589 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
1590 EINVAL);
1591
1592 hdev = hci_dev_get(index);
1593 if (!hdev)
1594 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
1595 ENODEV);
1596
Andre Guedes8c156c32011-07-07 10:30:36 -03001597 hci_dev_lock_bh(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001598
1599 err = hci_add_remote_oob_data(hdev, &cp->bdaddr, cp->hash,
1600 cp->randomizer);
1601 if (err < 0)
1602 err = cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, -err);
1603 else
1604 err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, NULL,
1605 0);
1606
Andre Guedes8c156c32011-07-07 10:30:36 -03001607 hci_dev_unlock_bh(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001608 hci_dev_put(hdev);
1609
1610 return err;
1611}
1612
1613static int remove_remote_oob_data(struct sock *sk, u16 index,
1614 unsigned char *data, u16 len)
1615{
1616 struct hci_dev *hdev;
1617 struct mgmt_cp_remove_remote_oob_data *cp = (void *) data;
1618 int err;
1619
1620 BT_DBG("hci%u ", index);
1621
1622 if (len != sizeof(*cp))
1623 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
1624 EINVAL);
1625
1626 hdev = hci_dev_get(index);
1627 if (!hdev)
1628 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
1629 ENODEV);
1630
Andre Guedes8c156c32011-07-07 10:30:36 -03001631 hci_dev_lock_bh(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001632
1633 err = hci_remove_remote_oob_data(hdev, &cp->bdaddr);
1634 if (err < 0)
1635 err = cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
1636 -err);
1637 else
1638 err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
1639 NULL, 0);
1640
Andre Guedes8c156c32011-07-07 10:30:36 -03001641 hci_dev_unlock_bh(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001642 hci_dev_put(hdev);
1643
1644 return err;
1645}
1646
Johan Hedberg14a53662011-04-27 10:29:56 -04001647static int start_discovery(struct sock *sk, u16 index)
1648{
Johan Hedberg14a53662011-04-27 10:29:56 -04001649 struct pending_cmd *cmd;
1650 struct hci_dev *hdev;
1651 int err;
1652
1653 BT_DBG("hci%u", index);
1654
1655 hdev = hci_dev_get(index);
1656 if (!hdev)
1657 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY, ENODEV);
1658
1659 hci_dev_lock_bh(hdev);
1660
Johan Hedbergbd2d1332011-11-07 23:13:37 +02001661 if (!test_bit(HCI_UP, &hdev->flags)) {
1662 err = cmd_status(sk, index, MGMT_OP_START_DISCOVERY, ENETDOWN);
1663 goto failed;
1664 }
1665
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001666 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04001667 if (!cmd) {
1668 err = -ENOMEM;
1669 goto failed;
1670 }
1671
Andre Guedes2519a1f2011-11-07 11:45:24 -03001672 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
Johan Hedberg14a53662011-04-27 10:29:56 -04001673 if (err < 0)
1674 mgmt_pending_remove(cmd);
1675
1676failed:
1677 hci_dev_unlock_bh(hdev);
1678 hci_dev_put(hdev);
1679
1680 return err;
1681}
1682
1683static int stop_discovery(struct sock *sk, u16 index)
1684{
1685 struct hci_dev *hdev;
1686 struct pending_cmd *cmd;
1687 int err;
1688
1689 BT_DBG("hci%u", index);
1690
1691 hdev = hci_dev_get(index);
1692 if (!hdev)
1693 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY, ENODEV);
1694
1695 hci_dev_lock_bh(hdev);
1696
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001697 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04001698 if (!cmd) {
1699 err = -ENOMEM;
1700 goto failed;
1701 }
1702
Andre Guedes023d50492011-11-04 14:16:52 -03001703 err = hci_cancel_inquiry(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04001704 if (err < 0)
1705 mgmt_pending_remove(cmd);
1706
1707failed:
1708 hci_dev_unlock_bh(hdev);
1709 hci_dev_put(hdev);
1710
1711 return err;
1712}
1713
Antti Julku7fbec222011-06-15 12:01:15 +03001714static int block_device(struct sock *sk, u16 index, unsigned char *data,
1715 u16 len)
1716{
1717 struct hci_dev *hdev;
Antti Julku5e762442011-08-25 16:48:02 +03001718 struct mgmt_cp_block_device *cp = (void *) data;
Antti Julku7fbec222011-06-15 12:01:15 +03001719 int err;
1720
1721 BT_DBG("hci%u", index);
1722
Antti Julku7fbec222011-06-15 12:01:15 +03001723 if (len != sizeof(*cp))
1724 return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
1725 EINVAL);
1726
1727 hdev = hci_dev_get(index);
1728 if (!hdev)
1729 return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
1730 ENODEV);
1731
Antti Julku5e762442011-08-25 16:48:02 +03001732 hci_dev_lock_bh(hdev);
1733
Antti Julku7fbec222011-06-15 12:01:15 +03001734 err = hci_blacklist_add(hdev, &cp->bdaddr);
Antti Julku7fbec222011-06-15 12:01:15 +03001735 if (err < 0)
1736 err = cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE, -err);
1737 else
1738 err = cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE,
1739 NULL, 0);
Antti Julku5e762442011-08-25 16:48:02 +03001740
Antti Julku5e762442011-08-25 16:48:02 +03001741 hci_dev_unlock_bh(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03001742 hci_dev_put(hdev);
1743
1744 return err;
1745}
1746
1747static int unblock_device(struct sock *sk, u16 index, unsigned char *data,
1748 u16 len)
1749{
1750 struct hci_dev *hdev;
Antti Julku5e762442011-08-25 16:48:02 +03001751 struct mgmt_cp_unblock_device *cp = (void *) data;
Antti Julku7fbec222011-06-15 12:01:15 +03001752 int err;
1753
1754 BT_DBG("hci%u", index);
1755
Antti Julku7fbec222011-06-15 12:01:15 +03001756 if (len != sizeof(*cp))
1757 return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
1758 EINVAL);
1759
1760 hdev = hci_dev_get(index);
1761 if (!hdev)
1762 return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
1763 ENODEV);
1764
Antti Julku5e762442011-08-25 16:48:02 +03001765 hci_dev_lock_bh(hdev);
1766
Antti Julku7fbec222011-06-15 12:01:15 +03001767 err = hci_blacklist_del(hdev, &cp->bdaddr);
1768
1769 if (err < 0)
1770 err = cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE, -err);
1771 else
1772 err = cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE,
1773 NULL, 0);
Antti Julku5e762442011-08-25 16:48:02 +03001774
Antti Julku5e762442011-08-25 16:48:02 +03001775 hci_dev_unlock_bh(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03001776 hci_dev_put(hdev);
1777
1778 return err;
1779}
1780
Antti Julkuf6422ec2011-06-22 13:11:56 +03001781static int set_fast_connectable(struct sock *sk, u16 index,
1782 unsigned char *data, u16 len)
1783{
1784 struct hci_dev *hdev;
1785 struct mgmt_cp_set_fast_connectable *cp = (void *) data;
1786 struct hci_cp_write_page_scan_activity acp;
1787 u8 type;
1788 int err;
1789
1790 BT_DBG("hci%u", index);
1791
1792 if (len != sizeof(*cp))
1793 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
1794 EINVAL);
1795
1796 hdev = hci_dev_get(index);
1797 if (!hdev)
1798 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
1799 ENODEV);
1800
1801 hci_dev_lock(hdev);
1802
1803 if (cp->enable) {
1804 type = PAGE_SCAN_TYPE_INTERLACED;
1805 acp.interval = 0x0024; /* 22.5 msec page scan interval */
1806 } else {
1807 type = PAGE_SCAN_TYPE_STANDARD; /* default */
1808 acp.interval = 0x0800; /* default 1.28 sec page scan */
1809 }
1810
1811 acp.window = 0x0012; /* default 11.25 msec page scan window */
1812
1813 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
1814 sizeof(acp), &acp);
1815 if (err < 0) {
1816 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
1817 -err);
1818 goto done;
1819 }
1820
1821 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
1822 if (err < 0) {
1823 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
1824 -err);
1825 goto done;
1826 }
1827
1828 err = cmd_complete(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
1829 NULL, 0);
1830done:
1831 hci_dev_unlock(hdev);
1832 hci_dev_put(hdev);
1833
1834 return err;
1835}
1836
Johan Hedberg03811012010-12-08 00:21:06 +02001837int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
1838{
1839 unsigned char *buf;
1840 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001841 u16 opcode, index, len;
Johan Hedberg03811012010-12-08 00:21:06 +02001842 int err;
1843
1844 BT_DBG("got %zu bytes", msglen);
1845
1846 if (msglen < sizeof(*hdr))
1847 return -EINVAL;
1848
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03001849 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02001850 if (!buf)
1851 return -ENOMEM;
1852
1853 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
1854 err = -EFAULT;
1855 goto done;
1856 }
1857
1858 hdr = (struct mgmt_hdr *) buf;
1859 opcode = get_unaligned_le16(&hdr->opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01001860 index = get_unaligned_le16(&hdr->index);
Johan Hedberg03811012010-12-08 00:21:06 +02001861 len = get_unaligned_le16(&hdr->len);
1862
1863 if (len != msglen - sizeof(*hdr)) {
1864 err = -EINVAL;
1865 goto done;
1866 }
1867
1868 switch (opcode) {
Johan Hedberg02d98122010-12-13 21:07:04 +02001869 case MGMT_OP_READ_VERSION:
1870 err = read_version(sk);
1871 break;
Johan Hedbergfaba42e2010-12-13 21:07:05 +02001872 case MGMT_OP_READ_INDEX_LIST:
1873 err = read_index_list(sk);
1874 break;
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001875 case MGMT_OP_READ_INFO:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001876 err = read_controller_info(sk, index);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001877 break;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001878 case MGMT_OP_SET_POWERED:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001879 err = set_powered(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001880 break;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001881 case MGMT_OP_SET_DISCOVERABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001882 err = set_discoverable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001883 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001884 case MGMT_OP_SET_CONNECTABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001885 err = set_connectable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001886 break;
Johan Hedbergc542a062011-01-26 13:11:03 +02001887 case MGMT_OP_SET_PAIRABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001888 err = set_pairable(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergc542a062011-01-26 13:11:03 +02001889 break;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001890 case MGMT_OP_ADD_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001891 err = add_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001892 break;
1893 case MGMT_OP_REMOVE_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001894 err = remove_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001895 break;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001896 case MGMT_OP_SET_DEV_CLASS:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001897 err = set_dev_class(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001898 break;
1899 case MGMT_OP_SET_SERVICE_CACHE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001900 err = set_service_cache(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001901 break;
Johan Hedberg86742e12011-11-07 23:13:38 +02001902 case MGMT_OP_LOAD_LINK_KEYS:
1903 err = load_link_keys(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001904 break;
Johan Hedberg86742e12011-11-07 23:13:38 +02001905 case MGMT_OP_REMOVE_KEYS:
1906 err = remove_keys(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001907 break;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001908 case MGMT_OP_DISCONNECT:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001909 err = disconnect(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001910 break;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001911 case MGMT_OP_GET_CONNECTIONS:
Szymon Janc8ce62842011-03-01 16:55:32 +01001912 err = get_connections(sk, index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001913 break;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001914 case MGMT_OP_PIN_CODE_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001915 err = pin_code_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001916 break;
1917 case MGMT_OP_PIN_CODE_NEG_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001918 err = pin_code_neg_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001919 break;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001920 case MGMT_OP_SET_IO_CAPABILITY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001921 err = set_io_capability(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001922 break;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001923 case MGMT_OP_PAIR_DEVICE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001924 err = pair_device(sk, index, buf + sizeof(*hdr), len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001925 break;
Johan Hedberga5c29682011-02-19 12:05:57 -03001926 case MGMT_OP_USER_CONFIRM_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001927 err = user_confirm_reply(sk, index, buf + sizeof(*hdr), len, 1);
Johan Hedberga5c29682011-02-19 12:05:57 -03001928 break;
1929 case MGMT_OP_USER_CONFIRM_NEG_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001930 err = user_confirm_reply(sk, index, buf + sizeof(*hdr), len, 0);
Johan Hedberga5c29682011-02-19 12:05:57 -03001931 break;
Johan Hedbergb312b1612011-03-16 14:29:37 +02001932 case MGMT_OP_SET_LOCAL_NAME:
1933 err = set_local_name(sk, index, buf + sizeof(*hdr), len);
1934 break;
Szymon Jancc35938b2011-03-22 13:12:21 +01001935 case MGMT_OP_READ_LOCAL_OOB_DATA:
1936 err = read_local_oob_data(sk, index);
1937 break;
Szymon Janc2763eda2011-03-22 13:12:22 +01001938 case MGMT_OP_ADD_REMOTE_OOB_DATA:
1939 err = add_remote_oob_data(sk, index, buf + sizeof(*hdr), len);
1940 break;
1941 case MGMT_OP_REMOVE_REMOTE_OOB_DATA:
1942 err = remove_remote_oob_data(sk, index, buf + sizeof(*hdr),
1943 len);
1944 break;
Johan Hedberg14a53662011-04-27 10:29:56 -04001945 case MGMT_OP_START_DISCOVERY:
1946 err = start_discovery(sk, index);
1947 break;
1948 case MGMT_OP_STOP_DISCOVERY:
1949 err = stop_discovery(sk, index);
1950 break;
Antti Julku7fbec222011-06-15 12:01:15 +03001951 case MGMT_OP_BLOCK_DEVICE:
1952 err = block_device(sk, index, buf + sizeof(*hdr), len);
1953 break;
1954 case MGMT_OP_UNBLOCK_DEVICE:
1955 err = unblock_device(sk, index, buf + sizeof(*hdr), len);
1956 break;
Antti Julkuf6422ec2011-06-22 13:11:56 +03001957 case MGMT_OP_SET_FAST_CONNECTABLE:
1958 err = set_fast_connectable(sk, index, buf + sizeof(*hdr),
1959 len);
1960 break;
Johan Hedberg03811012010-12-08 00:21:06 +02001961 default:
1962 BT_DBG("Unknown op %u", opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01001963 err = cmd_status(sk, index, opcode, 0x01);
Johan Hedberg03811012010-12-08 00:21:06 +02001964 break;
1965 }
1966
Johan Hedberge41d8b42010-12-13 21:07:03 +02001967 if (err < 0)
1968 goto done;
1969
Johan Hedberg03811012010-12-08 00:21:06 +02001970 err = msglen;
1971
1972done:
1973 kfree(buf);
1974 return err;
1975}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001976
Johan Hedbergb24752f2011-11-03 14:40:33 +02001977static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
1978{
1979 u8 *status = data;
1980
1981 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
1982 mgmt_pending_remove(cmd);
1983}
1984
Johan Hedberg744cf192011-11-08 20:40:14 +02001985int mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001986{
Johan Hedberg744cf192011-11-08 20:40:14 +02001987 return mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001988}
1989
Johan Hedberg744cf192011-11-08 20:40:14 +02001990int mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001991{
Johan Hedbergb24752f2011-11-03 14:40:33 +02001992 u8 status = ENODEV;
1993
Johan Hedberg744cf192011-11-08 20:40:14 +02001994 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02001995
Johan Hedberg744cf192011-11-08 20:40:14 +02001996 return mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001997}
1998
Johan Hedberg73f22f62010-12-29 16:00:25 +02001999struct cmd_lookup {
Johan Hedberg72a734e2010-12-30 00:38:22 +02002000 u8 val;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002001 struct sock *sk;
2002};
2003
Johan Hedberg72a734e2010-12-30 00:38:22 +02002004static void mode_rsp(struct pending_cmd *cmd, void *data)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002005{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01002006 struct mgmt_mode *cp = cmd->param;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002007 struct cmd_lookup *match = data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002008
Johan Hedberg72a734e2010-12-30 00:38:22 +02002009 if (cp->val != match->val)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002010 return;
2011
Johan Hedberg053f0212011-01-26 13:07:10 +02002012 send_mode_rsp(cmd->sk, cmd->opcode, cmd->index, cp->val);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002013
2014 list_del(&cmd->list);
2015
2016 if (match->sk == NULL) {
2017 match->sk = cmd->sk;
2018 sock_hold(match->sk);
2019 }
2020
2021 mgmt_pending_free(cmd);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002022}
Johan Hedberg5add6af2010-12-16 10:00:37 +02002023
Johan Hedberg744cf192011-11-08 20:40:14 +02002024int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg5add6af2010-12-16 10:00:37 +02002025{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002026 struct mgmt_mode ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002027 struct cmd_lookup match = { powered, NULL };
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002028 int ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002029
Johan Hedberg744cf192011-11-08 20:40:14 +02002030 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, mode_rsp, &match);
Johan Hedberg5add6af2010-12-16 10:00:37 +02002031
Johan Hedbergb24752f2011-11-03 14:40:33 +02002032 if (!powered) {
2033 u8 status = ENETDOWN;
Johan Hedberg744cf192011-11-08 20:40:14 +02002034 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002035 }
2036
Johan Hedberg72a734e2010-12-30 00:38:22 +02002037 ev.val = powered;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002038
Johan Hedberg744cf192011-11-08 20:40:14 +02002039 ret = mgmt_event(MGMT_EV_POWERED, hdev, &ev, sizeof(ev), match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002040
2041 if (match.sk)
2042 sock_put(match.sk);
2043
2044 return ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002045}
Johan Hedberg73f22f62010-12-29 16:00:25 +02002046
Johan Hedberg744cf192011-11-08 20:40:14 +02002047int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg73f22f62010-12-29 16:00:25 +02002048{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002049 struct mgmt_mode ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002050 struct cmd_lookup match = { discoverable, NULL };
2051 int ret;
2052
Johan Hedberg744cf192011-11-08 20:40:14 +02002053 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, mode_rsp, &match);
Johan Hedberg72a734e2010-12-30 00:38:22 +02002054
Johan Hedberg72a734e2010-12-30 00:38:22 +02002055 ev.val = discoverable;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002056
Johan Hedberg744cf192011-11-08 20:40:14 +02002057 ret = mgmt_event(MGMT_EV_DISCOVERABLE, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01002058 match.sk);
Johan Hedberg73f22f62010-12-29 16:00:25 +02002059
2060 if (match.sk)
2061 sock_put(match.sk);
2062
2063 return ret;
2064}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002065
Johan Hedberg744cf192011-11-08 20:40:14 +02002066int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002067{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002068 struct mgmt_mode ev;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002069 struct cmd_lookup match = { connectable, NULL };
2070 int ret;
2071
Johan Hedberg744cf192011-11-08 20:40:14 +02002072 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev, mode_rsp, &match);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002073
Johan Hedberg72a734e2010-12-30 00:38:22 +02002074 ev.val = connectable;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002075
Johan Hedberg744cf192011-11-08 20:40:14 +02002076 ret = mgmt_event(MGMT_EV_CONNECTABLE, hdev, &ev, sizeof(ev), match.sk);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002077
2078 if (match.sk)
2079 sock_put(match.sk);
2080
2081 return ret;
2082}
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002083
Johan Hedberg744cf192011-11-08 20:40:14 +02002084int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002085{
2086 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02002087 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002088 cmd_status_rsp, &status);
2089
2090 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02002091 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002092 cmd_status_rsp, &status);
2093
2094 return 0;
2095}
2096
Johan Hedberg744cf192011-11-08 20:40:14 +02002097int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
2098 u8 persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002099{
Johan Hedberg86742e12011-11-07 23:13:38 +02002100 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002101
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002102 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002103
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002104 ev.store_hint = persistent;
2105 bacpy(&ev.key.bdaddr, &key->bdaddr);
2106 ev.key.type = key->type;
2107 memcpy(ev.key.val, key->val, 16);
2108 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002109
Johan Hedberg744cf192011-11-08 20:40:14 +02002110 return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002111}
Johan Hedbergf7520542011-01-20 12:34:39 +02002112
Johan Hedberg48264f02011-11-09 13:58:58 +02002113int mgmt_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
2114 u8 addr_type)
Johan Hedbergf7520542011-01-20 12:34:39 +02002115{
Johan Hedberg4c659c32011-11-07 23:13:39 +02002116 struct mgmt_addr_info ev;
Johan Hedbergf7520542011-01-20 12:34:39 +02002117
Johan Hedbergf7520542011-01-20 12:34:39 +02002118 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02002119 ev.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02002120
Johan Hedberg744cf192011-11-08 20:40:14 +02002121 return mgmt_event(MGMT_EV_CONNECTED, hdev, &ev, sizeof(ev), NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02002122}
2123
Johan Hedberg8962ee72011-01-20 12:40:27 +02002124static void disconnect_rsp(struct pending_cmd *cmd, void *data)
2125{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01002126 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002127 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02002128 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002129
Johan Hedberga38528f2011-01-22 06:46:43 +02002130 bacpy(&rp.bdaddr, &cp->bdaddr);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002131
Szymon Janc4e51eae2011-02-25 19:05:48 +01002132 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002133
2134 *sk = cmd->sk;
2135 sock_hold(*sk);
2136
Johan Hedberga664b5b2011-02-19 12:06:02 -03002137 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002138}
2139
Johan Hedberga8a1d192011-11-10 15:54:38 +02002140static void remove_keys_rsp(struct pending_cmd *cmd, void *data)
2141{
2142 u8 *status = data;
2143 struct mgmt_cp_remove_keys *cp = cmd->param;
2144 struct mgmt_rp_remove_keys rp;
2145
2146 memset(&rp, 0, sizeof(rp));
2147 bacpy(&rp.bdaddr, &cp->bdaddr);
2148 if (status != NULL)
2149 rp.status = *status;
2150
2151 cmd_complete(cmd->sk, cmd->index, MGMT_OP_REMOVE_KEYS, &rp,
2152 sizeof(rp));
2153
2154 mgmt_pending_remove(cmd);
2155}
2156
Johan Hedberg48264f02011-11-09 13:58:58 +02002157int mgmt_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
2158 u8 addr_type)
Johan Hedbergf7520542011-01-20 12:34:39 +02002159{
Johan Hedberg4c659c32011-11-07 23:13:39 +02002160 struct mgmt_addr_info ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002161 struct sock *sk = NULL;
2162 int err;
2163
Johan Hedberg744cf192011-11-08 20:40:14 +02002164 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02002165
Johan Hedbergf7520542011-01-20 12:34:39 +02002166 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02002167 ev.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02002168
Johan Hedberg744cf192011-11-08 20:40:14 +02002169 err = mgmt_event(MGMT_EV_DISCONNECTED, hdev, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002170
2171 if (sk)
2172 sock_put(sk);
2173
Johan Hedberga8a1d192011-11-10 15:54:38 +02002174 mgmt_pending_foreach(MGMT_OP_REMOVE_KEYS, hdev, remove_keys_rsp, NULL);
2175
Johan Hedberg8962ee72011-01-20 12:40:27 +02002176 return err;
2177}
2178
Johan Hedberg744cf192011-11-08 20:40:14 +02002179int mgmt_disconnect_failed(struct hci_dev *hdev)
Johan Hedberg8962ee72011-01-20 12:40:27 +02002180{
2181 struct pending_cmd *cmd;
2182 int err;
2183
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002184 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002185 if (!cmd)
2186 return -ENOENT;
2187
Johan Hedberg744cf192011-11-08 20:40:14 +02002188 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_DISCONNECT, EIO);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002189
Johan Hedberga664b5b2011-02-19 12:06:02 -03002190 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002191
2192 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02002193}
Johan Hedberg17d5c042011-01-22 06:09:08 +02002194
Johan Hedberg48264f02011-11-09 13:58:58 +02002195int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
2196 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02002197{
2198 struct mgmt_ev_connect_failed ev;
2199
Johan Hedberg4c659c32011-11-07 23:13:39 +02002200 bacpy(&ev.addr.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02002201 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedberg17d5c042011-01-22 06:09:08 +02002202 ev.status = status;
2203
Johan Hedberg744cf192011-11-08 20:40:14 +02002204 return mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02002205}
Johan Hedberg980e1a52011-01-22 06:10:07 +02002206
Johan Hedberg744cf192011-11-08 20:40:14 +02002207int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002208{
2209 struct mgmt_ev_pin_code_request ev;
2210
Johan Hedberg980e1a52011-01-22 06:10:07 +02002211 bacpy(&ev.bdaddr, bdaddr);
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02002212 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002213
Johan Hedberg744cf192011-11-08 20:40:14 +02002214 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01002215 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002216}
2217
Johan Hedberg744cf192011-11-08 20:40:14 +02002218int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
2219 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002220{
2221 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002222 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002223 int err;
2224
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002225 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002226 if (!cmd)
2227 return -ENOENT;
2228
Johan Hedbergac56fb12011-02-19 12:05:59 -03002229 bacpy(&rp.bdaddr, bdaddr);
2230 rp.status = status;
2231
Johan Hedberg744cf192011-11-08 20:40:14 +02002232 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY, &rp,
Szymon Janc4e51eae2011-02-25 19:05:48 +01002233 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002234
Johan Hedberga664b5b2011-02-19 12:06:02 -03002235 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002236
2237 return err;
2238}
2239
Johan Hedberg744cf192011-11-08 20:40:14 +02002240int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
2241 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002242{
2243 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002244 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002245 int err;
2246
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002247 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002248 if (!cmd)
2249 return -ENOENT;
2250
Johan Hedbergac56fb12011-02-19 12:05:59 -03002251 bacpy(&rp.bdaddr, bdaddr);
2252 rp.status = status;
2253
Johan Hedberg744cf192011-11-08 20:40:14 +02002254 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY, &rp,
Szymon Janc4e51eae2011-02-25 19:05:48 +01002255 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002256
Johan Hedberga664b5b2011-02-19 12:06:02 -03002257 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002258
2259 return err;
2260}
Johan Hedberga5c29682011-02-19 12:05:57 -03002261
Johan Hedberg744cf192011-11-08 20:40:14 +02002262int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
2263 __le32 value, u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03002264{
2265 struct mgmt_ev_user_confirm_request ev;
2266
Johan Hedberg744cf192011-11-08 20:40:14 +02002267 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03002268
Johan Hedberga5c29682011-02-19 12:05:57 -03002269 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07002270 ev.confirm_hint = confirm_hint;
Johan Hedberga5c29682011-02-19 12:05:57 -03002271 put_unaligned_le32(value, &ev.value);
2272
Johan Hedberg744cf192011-11-08 20:40:14 +02002273 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01002274 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03002275}
2276
Johan Hedberg744cf192011-11-08 20:40:14 +02002277static int confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
2278 u8 status, u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03002279{
2280 struct pending_cmd *cmd;
2281 struct mgmt_rp_user_confirm_reply rp;
2282 int err;
2283
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002284 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002285 if (!cmd)
2286 return -ENOENT;
2287
Johan Hedberga5c29682011-02-19 12:05:57 -03002288 bacpy(&rp.bdaddr, bdaddr);
2289 rp.status = status;
Johan Hedberg744cf192011-11-08 20:40:14 +02002290 err = cmd_complete(cmd->sk, hdev->id, opcode, &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03002291
Johan Hedberga664b5b2011-02-19 12:06:02 -03002292 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002293
2294 return err;
2295}
2296
Johan Hedberg744cf192011-11-08 20:40:14 +02002297int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
2298 u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03002299{
Johan Hedberg744cf192011-11-08 20:40:14 +02002300 return confirm_reply_complete(hdev, bdaddr, status,
Johan Hedberga5c29682011-02-19 12:05:57 -03002301 MGMT_OP_USER_CONFIRM_REPLY);
2302}
2303
Johan Hedberg744cf192011-11-08 20:40:14 +02002304int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev,
2305 bdaddr_t *bdaddr, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03002306{
Johan Hedberg744cf192011-11-08 20:40:14 +02002307 return confirm_reply_complete(hdev, bdaddr, status,
Johan Hedberga5c29682011-02-19 12:05:57 -03002308 MGMT_OP_USER_CONFIRM_NEG_REPLY);
2309}
Johan Hedberg2a611692011-02-19 12:06:00 -03002310
Johan Hedberg744cf192011-11-08 20:40:14 +02002311int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03002312{
2313 struct mgmt_ev_auth_failed ev;
2314
Johan Hedberg2a611692011-02-19 12:06:00 -03002315 bacpy(&ev.bdaddr, bdaddr);
2316 ev.status = status;
2317
Johan Hedberg744cf192011-11-08 20:40:14 +02002318 return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03002319}
Johan Hedbergb312b1612011-03-16 14:29:37 +02002320
Johan Hedberg744cf192011-11-08 20:40:14 +02002321int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02002322{
2323 struct pending_cmd *cmd;
2324 struct mgmt_cp_set_local_name ev;
2325 int err;
2326
2327 memset(&ev, 0, sizeof(ev));
2328 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
2329
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002330 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002331 if (!cmd)
2332 goto send_event;
2333
2334 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02002335 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
2336 EIO);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002337 goto failed;
2338 }
2339
Johan Hedberg744cf192011-11-08 20:40:14 +02002340 update_eir(hdev);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002341
Johan Hedberg744cf192011-11-08 20:40:14 +02002342 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, &ev,
Johan Hedbergb312b1612011-03-16 14:29:37 +02002343 sizeof(ev));
2344 if (err < 0)
2345 goto failed;
2346
2347send_event:
Johan Hedberg744cf192011-11-08 20:40:14 +02002348 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
Johan Hedbergb312b1612011-03-16 14:29:37 +02002349 cmd ? cmd->sk : NULL);
2350
2351failed:
2352 if (cmd)
2353 mgmt_pending_remove(cmd);
2354 return err;
2355}
Szymon Jancc35938b2011-03-22 13:12:21 +01002356
Johan Hedberg744cf192011-11-08 20:40:14 +02002357int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
2358 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01002359{
2360 struct pending_cmd *cmd;
2361 int err;
2362
Johan Hedberg744cf192011-11-08 20:40:14 +02002363 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01002364
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002365 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002366 if (!cmd)
2367 return -ENOENT;
2368
2369 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02002370 err = cmd_status(cmd->sk, hdev->id,
2371 MGMT_OP_READ_LOCAL_OOB_DATA, EIO);
Szymon Jancc35938b2011-03-22 13:12:21 +01002372 } else {
2373 struct mgmt_rp_read_local_oob_data rp;
2374
2375 memcpy(rp.hash, hash, sizeof(rp.hash));
2376 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
2377
Johan Hedberg744cf192011-11-08 20:40:14 +02002378 err = cmd_complete(cmd->sk, hdev->id,
2379 MGMT_OP_READ_LOCAL_OOB_DATA,
2380 &rp, sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01002381 }
2382
2383 mgmt_pending_remove(cmd);
2384
2385 return err;
2386}
Johan Hedberge17acd42011-03-30 23:57:16 +03002387
Johan Hedberg48264f02011-11-09 13:58:58 +02002388int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
2389 u8 addr_type, u8 *dev_class, s8 rssi, u8 *eir)
Johan Hedberge17acd42011-03-30 23:57:16 +03002390{
2391 struct mgmt_ev_device_found ev;
2392
2393 memset(&ev, 0, sizeof(ev));
2394
Johan Hedberg4c659c32011-11-07 23:13:39 +02002395 bacpy(&ev.addr.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02002396 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedberge17acd42011-03-30 23:57:16 +03002397 ev.rssi = rssi;
2398
2399 if (eir)
2400 memcpy(ev.eir, eir, sizeof(ev.eir));
2401
Andre Guedesf8523592011-09-09 18:56:26 -03002402 if (dev_class)
2403 memcpy(ev.dev_class, dev_class, sizeof(ev.dev_class));
2404
Johan Hedberg744cf192011-11-08 20:40:14 +02002405 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, &ev, sizeof(ev), NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03002406}
Johan Hedberga88a9652011-03-30 13:18:12 +03002407
Johan Hedberg744cf192011-11-08 20:40:14 +02002408int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *name)
Johan Hedberga88a9652011-03-30 13:18:12 +03002409{
2410 struct mgmt_ev_remote_name ev;
2411
2412 memset(&ev, 0, sizeof(ev));
2413
2414 bacpy(&ev.bdaddr, bdaddr);
2415 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
2416
Johan Hedberg744cf192011-11-08 20:40:14 +02002417 return mgmt_event(MGMT_EV_REMOTE_NAME, hdev, &ev, sizeof(ev), NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03002418}
Johan Hedberg314b2382011-04-27 10:29:57 -04002419
Johan Hedberg744cf192011-11-08 20:40:14 +02002420int mgmt_inquiry_failed(struct hci_dev *hdev, u8 status)
Johan Hedberg164a6e72011-11-01 17:06:44 +02002421{
2422 struct pending_cmd *cmd;
2423 int err;
2424
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002425 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02002426 if (!cmd)
2427 return -ENOENT;
2428
Johan Hedberg744cf192011-11-08 20:40:14 +02002429 err = cmd_status(cmd->sk, hdev->id, cmd->opcode, status);
Johan Hedberg164a6e72011-11-01 17:06:44 +02002430 mgmt_pending_remove(cmd);
2431
2432 return err;
2433}
2434
Johan Hedberg744cf192011-11-08 20:40:14 +02002435int mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04002436{
Johan Hedberg164a6e72011-11-01 17:06:44 +02002437 struct pending_cmd *cmd;
2438
2439 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002440 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02002441 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002442 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02002443
2444 if (cmd != NULL) {
Johan Hedberg744cf192011-11-08 20:40:14 +02002445 cmd_complete(cmd->sk, hdev->id, cmd->opcode, NULL, 0);
Johan Hedberg164a6e72011-11-01 17:06:44 +02002446 mgmt_pending_remove(cmd);
2447 }
2448
Johan Hedberg744cf192011-11-08 20:40:14 +02002449 return mgmt_event(MGMT_EV_DISCOVERING, hdev, &discovering,
Johan Hedberg314b2382011-04-27 10:29:57 -04002450 sizeof(discovering), NULL);
2451}
Antti Julku5e762442011-08-25 16:48:02 +03002452
Johan Hedberg744cf192011-11-08 20:40:14 +02002453int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr)
Antti Julku5e762442011-08-25 16:48:02 +03002454{
2455 struct pending_cmd *cmd;
2456 struct mgmt_ev_device_blocked ev;
2457
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002458 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002459
2460 bacpy(&ev.bdaddr, bdaddr);
2461
Johan Hedberg744cf192011-11-08 20:40:14 +02002462 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
2463 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03002464}
2465
Johan Hedberg744cf192011-11-08 20:40:14 +02002466int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr)
Antti Julku5e762442011-08-25 16:48:02 +03002467{
2468 struct pending_cmd *cmd;
2469 struct mgmt_ev_device_unblocked ev;
2470
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002471 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002472
2473 bacpy(&ev.bdaddr, bdaddr);
2474
Johan Hedberg744cf192011-11-08 20:40:14 +02002475 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
2476 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03002477}