blob: 3958cbdd258f744cf099686bab5b5ad8fc820bb5 [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 Hedberg55ed8ca2011-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 Hedberg55ed8ca2011-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 Hedberg55ed8ca2011-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 Hedberg55ed8ca2011-01-17 14:41:05 +0200926 }
927
Szymon Janc4e51eae2011-02-25 19:05:48 +0100928 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca2011-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 Hedberg55ed8ca2011-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 Hedberg55ed8ca2011-01-17 14:41:05 +0200933 key_count);
934
Andre Guedes8c156c32011-07-07 10:30:36 -0300935 hci_dev_lock_bh(hdev);
Johan Hedberg55ed8ca2011-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 Hedberg55ed8ca2011-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 Hedberg55ed8ca2011-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 Hedberg55ed8ca2011-01-17 14:41:05 +0200954 hci_dev_put(hdev);
955
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -0300956 return 0;
Johan Hedberg55ed8ca2011-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 Hedberg55ed8ca2011-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 Hedberg55ed8ca2011-01-17 14:41:05 +0200967 struct hci_conn *conn;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +0200968 int err;
969
970 cp = (void *) data;
Johan Hedberg55ed8ca2011-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 Hedberg55ed8ca2011-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 Hedberg55ed8ca2011-01-17 14:41:05 +0200978
Andre Guedes8c156c32011-07-07 10:30:36 -0300979 hci_dev_lock_bh(hdev);
Johan Hedberg55ed8ca2011-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 Hedberg55ed8ca2011-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 Hedberg55ed8ca2011-01-17 14:41:05 +0200991 goto unlock;
992 }
993
Johan Hedberg55ed8ca2011-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 Hedberg55ed8ca2011-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 Hedberg55ed8ca2011-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 Hedberg55ed8ca2011-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 Hedbergba4e5642011-11-11 00:07:34 +02001336 bacpy(&rp.addr.bdaddr, &conn->dst);
1337 rp.addr.type = link_to_mgmt(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001338 rp.status = status;
1339
Szymon Janc4e51eae2011-02-25 19:05:48 +01001340 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001341
1342 /* So we don't get further callbacks for this connection */
1343 conn->connect_cfm_cb = NULL;
1344 conn->security_cfm_cb = NULL;
1345 conn->disconn_cfm_cb = NULL;
1346
1347 hci_conn_put(conn);
1348
Johan Hedberga664b5b2011-02-19 12:06:02 -03001349 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001350}
1351
1352static void pairing_complete_cb(struct hci_conn *conn, u8 status)
1353{
1354 struct pending_cmd *cmd;
1355
1356 BT_DBG("status %u", status);
1357
Johan Hedberg56e5cb82011-11-08 20:40:16 +02001358 cmd = find_pairing(conn);
1359 if (!cmd)
1360 BT_DBG("Unable to find a pending command");
1361 else
1362 pairing_complete(cmd, status);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001363}
1364
Szymon Janc4e51eae2011-02-25 19:05:48 +01001365static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001366{
1367 struct hci_dev *hdev;
1368 struct mgmt_cp_pair_device *cp;
Johan Hedberg1425acb2011-11-11 00:07:35 +02001369 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001370 struct pending_cmd *cmd;
1371 u8 sec_level, auth_type;
1372 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001373 int err;
1374
1375 BT_DBG("");
1376
1377 cp = (void *) data;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001378
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001379 if (len != sizeof(*cp))
1380 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, EINVAL);
1381
Szymon Janc4e51eae2011-02-25 19:05:48 +01001382 hdev = hci_dev_get(index);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001383 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001384 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, ENODEV);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001385
Andre Guedes8c156c32011-07-07 10:30:36 -03001386 hci_dev_lock_bh(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001387
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001388 sec_level = BT_SECURITY_MEDIUM;
1389 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001390 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001391 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03001392 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001393
Johan Hedbergba4e5642011-11-11 00:07:34 +02001394 if (cp->addr.type == MGMT_ADDR_BREDR)
1395 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr, sec_level,
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001396 auth_type);
1397 else
Johan Hedbergba4e5642011-11-11 00:07:34 +02001398 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr, sec_level,
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001399 auth_type);
1400
Johan Hedberg1425acb2011-11-11 00:07:35 +02001401 memset(&rp, 0, sizeof(rp));
1402 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1403 rp.addr.type = cp->addr.type;
1404
Ville Tervo30e76272011-02-22 16:10:53 -03001405 if (IS_ERR(conn)) {
Johan Hedberg1425acb2011-11-11 00:07:35 +02001406 rp.status = -PTR_ERR(conn);
1407 err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE,
1408 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001409 goto unlock;
1410 }
1411
1412 if (conn->connect_cfm_cb) {
1413 hci_conn_put(conn);
Johan Hedberg1425acb2011-11-11 00:07:35 +02001414 rp.status = EBUSY;
1415 err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE,
1416 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001417 goto unlock;
1418 }
1419
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001420 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001421 if (!cmd) {
1422 err = -ENOMEM;
1423 hci_conn_put(conn);
1424 goto unlock;
1425 }
1426
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001427 /* For LE, just connecting isn't a proof that the pairing finished */
Johan Hedbergba4e5642011-11-11 00:07:34 +02001428 if (cp->addr.type == MGMT_ADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001429 conn->connect_cfm_cb = pairing_complete_cb;
1430
Johan Hedberge9a416b2011-02-19 12:05:56 -03001431 conn->security_cfm_cb = pairing_complete_cb;
1432 conn->disconn_cfm_cb = pairing_complete_cb;
1433 conn->io_capability = cp->io_cap;
1434 cmd->user_data = conn;
1435
1436 if (conn->state == BT_CONNECTED &&
1437 hci_conn_security(conn, sec_level, auth_type))
1438 pairing_complete(cmd, 0);
1439
1440 err = 0;
1441
1442unlock:
Andre Guedes8c156c32011-07-07 10:30:36 -03001443 hci_dev_unlock_bh(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001444 hci_dev_put(hdev);
1445
1446 return err;
1447}
1448
Szymon Janc4e51eae2011-02-25 19:05:48 +01001449static int user_confirm_reply(struct sock *sk, u16 index, unsigned char *data,
1450 u16 len, int success)
Johan Hedberga5c29682011-02-19 12:05:57 -03001451{
1452 struct mgmt_cp_user_confirm_reply *cp = (void *) data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001453 u16 mgmt_op, hci_op;
Johan Hedberga5c29682011-02-19 12:05:57 -03001454 struct pending_cmd *cmd;
1455 struct hci_dev *hdev;
1456 int err;
1457
1458 BT_DBG("");
1459
Johan Hedberga5c29682011-02-19 12:05:57 -03001460 if (success) {
1461 mgmt_op = MGMT_OP_USER_CONFIRM_REPLY;
1462 hci_op = HCI_OP_USER_CONFIRM_REPLY;
1463 } else {
1464 mgmt_op = MGMT_OP_USER_CONFIRM_NEG_REPLY;
1465 hci_op = HCI_OP_USER_CONFIRM_NEG_REPLY;
1466 }
1467
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001468 if (len != sizeof(*cp))
1469 return cmd_status(sk, index, mgmt_op, EINVAL);
1470
Szymon Janc4e51eae2011-02-25 19:05:48 +01001471 hdev = hci_dev_get(index);
Johan Hedberga5c29682011-02-19 12:05:57 -03001472 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001473 return cmd_status(sk, index, mgmt_op, ENODEV);
Johan Hedberga5c29682011-02-19 12:05:57 -03001474
Andre Guedes8c156c32011-07-07 10:30:36 -03001475 hci_dev_lock_bh(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02001476
Johan Hedberga5c29682011-02-19 12:05:57 -03001477 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001478 err = cmd_status(sk, index, mgmt_op, ENETDOWN);
Johan Hedberga5c29682011-02-19 12:05:57 -03001479 goto failed;
1480 }
1481
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001482 cmd = mgmt_pending_add(sk, mgmt_op, hdev, data, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03001483 if (!cmd) {
1484 err = -ENOMEM;
1485 goto failed;
1486 }
1487
1488 err = hci_send_cmd(hdev, hci_op, sizeof(cp->bdaddr), &cp->bdaddr);
Johan Hedberga664b5b2011-02-19 12:06:02 -03001489 if (err < 0)
1490 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03001491
1492failed:
Andre Guedes8c156c32011-07-07 10:30:36 -03001493 hci_dev_unlock_bh(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03001494 hci_dev_put(hdev);
1495
1496 return err;
1497}
1498
Johan Hedbergb312b1612011-03-16 14:29:37 +02001499static int set_local_name(struct sock *sk, u16 index, unsigned char *data,
1500 u16 len)
1501{
1502 struct mgmt_cp_set_local_name *mgmt_cp = (void *) data;
1503 struct hci_cp_write_local_name hci_cp;
1504 struct hci_dev *hdev;
1505 struct pending_cmd *cmd;
1506 int err;
1507
1508 BT_DBG("");
1509
1510 if (len != sizeof(*mgmt_cp))
1511 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, EINVAL);
1512
1513 hdev = hci_dev_get(index);
1514 if (!hdev)
1515 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, ENODEV);
1516
Andre Guedes8c156c32011-07-07 10:30:36 -03001517 hci_dev_lock_bh(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001518
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001519 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001520 if (!cmd) {
1521 err = -ENOMEM;
1522 goto failed;
1523 }
1524
1525 memcpy(hci_cp.name, mgmt_cp->name, sizeof(hci_cp.name));
1526 err = hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(hci_cp),
1527 &hci_cp);
1528 if (err < 0)
1529 mgmt_pending_remove(cmd);
1530
1531failed:
Andre Guedes8c156c32011-07-07 10:30:36 -03001532 hci_dev_unlock_bh(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001533 hci_dev_put(hdev);
1534
1535 return err;
1536}
1537
Szymon Jancc35938b2011-03-22 13:12:21 +01001538static int read_local_oob_data(struct sock *sk, u16 index)
1539{
1540 struct hci_dev *hdev;
1541 struct pending_cmd *cmd;
1542 int err;
1543
1544 BT_DBG("hci%u", index);
1545
1546 hdev = hci_dev_get(index);
1547 if (!hdev)
1548 return cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
1549 ENODEV);
1550
Andre Guedes8c156c32011-07-07 10:30:36 -03001551 hci_dev_lock_bh(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01001552
1553 if (!test_bit(HCI_UP, &hdev->flags)) {
1554 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
1555 ENETDOWN);
1556 goto unlock;
1557 }
1558
1559 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
1560 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
1561 EOPNOTSUPP);
1562 goto unlock;
1563 }
1564
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001565 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Szymon Jancc35938b2011-03-22 13:12:21 +01001566 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA, EBUSY);
1567 goto unlock;
1568 }
1569
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001570 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01001571 if (!cmd) {
1572 err = -ENOMEM;
1573 goto unlock;
1574 }
1575
1576 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
1577 if (err < 0)
1578 mgmt_pending_remove(cmd);
1579
1580unlock:
Andre Guedes8c156c32011-07-07 10:30:36 -03001581 hci_dev_unlock_bh(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01001582 hci_dev_put(hdev);
1583
1584 return err;
1585}
1586
Szymon Janc2763eda2011-03-22 13:12:22 +01001587static int add_remote_oob_data(struct sock *sk, u16 index, unsigned char *data,
1588 u16 len)
1589{
1590 struct hci_dev *hdev;
1591 struct mgmt_cp_add_remote_oob_data *cp = (void *) data;
1592 int err;
1593
1594 BT_DBG("hci%u ", index);
1595
1596 if (len != sizeof(*cp))
1597 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
1598 EINVAL);
1599
1600 hdev = hci_dev_get(index);
1601 if (!hdev)
1602 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
1603 ENODEV);
1604
Andre Guedes8c156c32011-07-07 10:30:36 -03001605 hci_dev_lock_bh(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001606
1607 err = hci_add_remote_oob_data(hdev, &cp->bdaddr, cp->hash,
1608 cp->randomizer);
1609 if (err < 0)
1610 err = cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, -err);
1611 else
1612 err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, NULL,
1613 0);
1614
Andre Guedes8c156c32011-07-07 10:30:36 -03001615 hci_dev_unlock_bh(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001616 hci_dev_put(hdev);
1617
1618 return err;
1619}
1620
1621static int remove_remote_oob_data(struct sock *sk, u16 index,
1622 unsigned char *data, u16 len)
1623{
1624 struct hci_dev *hdev;
1625 struct mgmt_cp_remove_remote_oob_data *cp = (void *) data;
1626 int err;
1627
1628 BT_DBG("hci%u ", index);
1629
1630 if (len != sizeof(*cp))
1631 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
1632 EINVAL);
1633
1634 hdev = hci_dev_get(index);
1635 if (!hdev)
1636 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
1637 ENODEV);
1638
Andre Guedes8c156c32011-07-07 10:30:36 -03001639 hci_dev_lock_bh(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001640
1641 err = hci_remove_remote_oob_data(hdev, &cp->bdaddr);
1642 if (err < 0)
1643 err = cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
1644 -err);
1645 else
1646 err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
1647 NULL, 0);
1648
Andre Guedes8c156c32011-07-07 10:30:36 -03001649 hci_dev_unlock_bh(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001650 hci_dev_put(hdev);
1651
1652 return err;
1653}
1654
Johan Hedberg14a53662011-04-27 10:29:56 -04001655static int start_discovery(struct sock *sk, u16 index)
1656{
Johan Hedberg14a53662011-04-27 10:29:56 -04001657 struct pending_cmd *cmd;
1658 struct hci_dev *hdev;
1659 int err;
1660
1661 BT_DBG("hci%u", index);
1662
1663 hdev = hci_dev_get(index);
1664 if (!hdev)
1665 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY, ENODEV);
1666
1667 hci_dev_lock_bh(hdev);
1668
Johan Hedbergbd2d1332011-11-07 23:13:37 +02001669 if (!test_bit(HCI_UP, &hdev->flags)) {
1670 err = cmd_status(sk, index, MGMT_OP_START_DISCOVERY, ENETDOWN);
1671 goto failed;
1672 }
1673
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001674 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04001675 if (!cmd) {
1676 err = -ENOMEM;
1677 goto failed;
1678 }
1679
Andre Guedes2519a1f2011-11-07 11:45:24 -03001680 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
Johan Hedberg14a53662011-04-27 10:29:56 -04001681 if (err < 0)
1682 mgmt_pending_remove(cmd);
1683
1684failed:
1685 hci_dev_unlock_bh(hdev);
1686 hci_dev_put(hdev);
1687
1688 return err;
1689}
1690
1691static int stop_discovery(struct sock *sk, u16 index)
1692{
1693 struct hci_dev *hdev;
1694 struct pending_cmd *cmd;
1695 int err;
1696
1697 BT_DBG("hci%u", index);
1698
1699 hdev = hci_dev_get(index);
1700 if (!hdev)
1701 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY, ENODEV);
1702
1703 hci_dev_lock_bh(hdev);
1704
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001705 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04001706 if (!cmd) {
1707 err = -ENOMEM;
1708 goto failed;
1709 }
1710
Andre Guedes023d5042011-11-04 14:16:52 -03001711 err = hci_cancel_inquiry(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04001712 if (err < 0)
1713 mgmt_pending_remove(cmd);
1714
1715failed:
1716 hci_dev_unlock_bh(hdev);
1717 hci_dev_put(hdev);
1718
1719 return err;
1720}
1721
Antti Julku7fbec222011-06-15 12:01:15 +03001722static int block_device(struct sock *sk, u16 index, unsigned char *data,
1723 u16 len)
1724{
1725 struct hci_dev *hdev;
Antti Julku5e762442011-08-25 16:48:02 +03001726 struct mgmt_cp_block_device *cp = (void *) data;
Antti Julku7fbec222011-06-15 12:01:15 +03001727 int err;
1728
1729 BT_DBG("hci%u", index);
1730
Antti Julku7fbec222011-06-15 12:01:15 +03001731 if (len != sizeof(*cp))
1732 return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
1733 EINVAL);
1734
1735 hdev = hci_dev_get(index);
1736 if (!hdev)
1737 return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
1738 ENODEV);
1739
Antti Julku5e762442011-08-25 16:48:02 +03001740 hci_dev_lock_bh(hdev);
1741
Antti Julku7fbec222011-06-15 12:01:15 +03001742 err = hci_blacklist_add(hdev, &cp->bdaddr);
Antti Julku7fbec222011-06-15 12:01:15 +03001743 if (err < 0)
1744 err = cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE, -err);
1745 else
1746 err = cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE,
1747 NULL, 0);
Antti Julku5e762442011-08-25 16:48:02 +03001748
Antti Julku5e762442011-08-25 16:48:02 +03001749 hci_dev_unlock_bh(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03001750 hci_dev_put(hdev);
1751
1752 return err;
1753}
1754
1755static int unblock_device(struct sock *sk, u16 index, unsigned char *data,
1756 u16 len)
1757{
1758 struct hci_dev *hdev;
Antti Julku5e762442011-08-25 16:48:02 +03001759 struct mgmt_cp_unblock_device *cp = (void *) data;
Antti Julku7fbec222011-06-15 12:01:15 +03001760 int err;
1761
1762 BT_DBG("hci%u", index);
1763
Antti Julku7fbec222011-06-15 12:01:15 +03001764 if (len != sizeof(*cp))
1765 return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
1766 EINVAL);
1767
1768 hdev = hci_dev_get(index);
1769 if (!hdev)
1770 return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
1771 ENODEV);
1772
Antti Julku5e762442011-08-25 16:48:02 +03001773 hci_dev_lock_bh(hdev);
1774
Antti Julku7fbec222011-06-15 12:01:15 +03001775 err = hci_blacklist_del(hdev, &cp->bdaddr);
1776
1777 if (err < 0)
1778 err = cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE, -err);
1779 else
1780 err = cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE,
1781 NULL, 0);
Antti Julku5e762442011-08-25 16:48:02 +03001782
Antti Julku5e762442011-08-25 16:48:02 +03001783 hci_dev_unlock_bh(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03001784 hci_dev_put(hdev);
1785
1786 return err;
1787}
1788
Antti Julkuf6422ec2011-06-22 13:11:56 +03001789static int set_fast_connectable(struct sock *sk, u16 index,
1790 unsigned char *data, u16 len)
1791{
1792 struct hci_dev *hdev;
1793 struct mgmt_cp_set_fast_connectable *cp = (void *) data;
1794 struct hci_cp_write_page_scan_activity acp;
1795 u8 type;
1796 int err;
1797
1798 BT_DBG("hci%u", index);
1799
1800 if (len != sizeof(*cp))
1801 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
1802 EINVAL);
1803
1804 hdev = hci_dev_get(index);
1805 if (!hdev)
1806 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
1807 ENODEV);
1808
1809 hci_dev_lock(hdev);
1810
1811 if (cp->enable) {
1812 type = PAGE_SCAN_TYPE_INTERLACED;
1813 acp.interval = 0x0024; /* 22.5 msec page scan interval */
1814 } else {
1815 type = PAGE_SCAN_TYPE_STANDARD; /* default */
1816 acp.interval = 0x0800; /* default 1.28 sec page scan */
1817 }
1818
1819 acp.window = 0x0012; /* default 11.25 msec page scan window */
1820
1821 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
1822 sizeof(acp), &acp);
1823 if (err < 0) {
1824 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
1825 -err);
1826 goto done;
1827 }
1828
1829 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
1830 if (err < 0) {
1831 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
1832 -err);
1833 goto done;
1834 }
1835
1836 err = cmd_complete(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
1837 NULL, 0);
1838done:
1839 hci_dev_unlock(hdev);
1840 hci_dev_put(hdev);
1841
1842 return err;
1843}
1844
Johan Hedberg03811012010-12-08 00:21:06 +02001845int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
1846{
1847 unsigned char *buf;
1848 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001849 u16 opcode, index, len;
Johan Hedberg03811012010-12-08 00:21:06 +02001850 int err;
1851
1852 BT_DBG("got %zu bytes", msglen);
1853
1854 if (msglen < sizeof(*hdr))
1855 return -EINVAL;
1856
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03001857 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02001858 if (!buf)
1859 return -ENOMEM;
1860
1861 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
1862 err = -EFAULT;
1863 goto done;
1864 }
1865
1866 hdr = (struct mgmt_hdr *) buf;
1867 opcode = get_unaligned_le16(&hdr->opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01001868 index = get_unaligned_le16(&hdr->index);
Johan Hedberg03811012010-12-08 00:21:06 +02001869 len = get_unaligned_le16(&hdr->len);
1870
1871 if (len != msglen - sizeof(*hdr)) {
1872 err = -EINVAL;
1873 goto done;
1874 }
1875
1876 switch (opcode) {
Johan Hedberg02d98122010-12-13 21:07:04 +02001877 case MGMT_OP_READ_VERSION:
1878 err = read_version(sk);
1879 break;
Johan Hedbergfaba42e2010-12-13 21:07:05 +02001880 case MGMT_OP_READ_INDEX_LIST:
1881 err = read_index_list(sk);
1882 break;
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001883 case MGMT_OP_READ_INFO:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001884 err = read_controller_info(sk, index);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001885 break;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001886 case MGMT_OP_SET_POWERED:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001887 err = set_powered(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001888 break;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001889 case MGMT_OP_SET_DISCOVERABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001890 err = set_discoverable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001891 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001892 case MGMT_OP_SET_CONNECTABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001893 err = set_connectable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001894 break;
Johan Hedbergc542a062011-01-26 13:11:03 +02001895 case MGMT_OP_SET_PAIRABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001896 err = set_pairable(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergc542a062011-01-26 13:11:03 +02001897 break;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001898 case MGMT_OP_ADD_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001899 err = add_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001900 break;
1901 case MGMT_OP_REMOVE_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001902 err = remove_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001903 break;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001904 case MGMT_OP_SET_DEV_CLASS:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001905 err = set_dev_class(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001906 break;
1907 case MGMT_OP_SET_SERVICE_CACHE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001908 err = set_service_cache(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001909 break;
Johan Hedberg86742e12011-11-07 23:13:38 +02001910 case MGMT_OP_LOAD_LINK_KEYS:
1911 err = load_link_keys(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001912 break;
Johan Hedberg86742e12011-11-07 23:13:38 +02001913 case MGMT_OP_REMOVE_KEYS:
1914 err = remove_keys(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001915 break;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001916 case MGMT_OP_DISCONNECT:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001917 err = disconnect(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001918 break;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001919 case MGMT_OP_GET_CONNECTIONS:
Szymon Janc8ce62842011-03-01 16:55:32 +01001920 err = get_connections(sk, index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001921 break;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001922 case MGMT_OP_PIN_CODE_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001923 err = pin_code_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001924 break;
1925 case MGMT_OP_PIN_CODE_NEG_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001926 err = pin_code_neg_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001927 break;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001928 case MGMT_OP_SET_IO_CAPABILITY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001929 err = set_io_capability(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001930 break;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001931 case MGMT_OP_PAIR_DEVICE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001932 err = pair_device(sk, index, buf + sizeof(*hdr), len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001933 break;
Johan Hedberga5c29682011-02-19 12:05:57 -03001934 case MGMT_OP_USER_CONFIRM_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001935 err = user_confirm_reply(sk, index, buf + sizeof(*hdr), len, 1);
Johan Hedberga5c29682011-02-19 12:05:57 -03001936 break;
1937 case MGMT_OP_USER_CONFIRM_NEG_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001938 err = user_confirm_reply(sk, index, buf + sizeof(*hdr), len, 0);
Johan Hedberga5c29682011-02-19 12:05:57 -03001939 break;
Johan Hedbergb312b1612011-03-16 14:29:37 +02001940 case MGMT_OP_SET_LOCAL_NAME:
1941 err = set_local_name(sk, index, buf + sizeof(*hdr), len);
1942 break;
Szymon Jancc35938b2011-03-22 13:12:21 +01001943 case MGMT_OP_READ_LOCAL_OOB_DATA:
1944 err = read_local_oob_data(sk, index);
1945 break;
Szymon Janc2763eda2011-03-22 13:12:22 +01001946 case MGMT_OP_ADD_REMOTE_OOB_DATA:
1947 err = add_remote_oob_data(sk, index, buf + sizeof(*hdr), len);
1948 break;
1949 case MGMT_OP_REMOVE_REMOTE_OOB_DATA:
1950 err = remove_remote_oob_data(sk, index, buf + sizeof(*hdr),
1951 len);
1952 break;
Johan Hedberg14a53662011-04-27 10:29:56 -04001953 case MGMT_OP_START_DISCOVERY:
1954 err = start_discovery(sk, index);
1955 break;
1956 case MGMT_OP_STOP_DISCOVERY:
1957 err = stop_discovery(sk, index);
1958 break;
Antti Julku7fbec222011-06-15 12:01:15 +03001959 case MGMT_OP_BLOCK_DEVICE:
1960 err = block_device(sk, index, buf + sizeof(*hdr), len);
1961 break;
1962 case MGMT_OP_UNBLOCK_DEVICE:
1963 err = unblock_device(sk, index, buf + sizeof(*hdr), len);
1964 break;
Antti Julkuf6422ec2011-06-22 13:11:56 +03001965 case MGMT_OP_SET_FAST_CONNECTABLE:
1966 err = set_fast_connectable(sk, index, buf + sizeof(*hdr),
1967 len);
1968 break;
Johan Hedberg03811012010-12-08 00:21:06 +02001969 default:
1970 BT_DBG("Unknown op %u", opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01001971 err = cmd_status(sk, index, opcode, 0x01);
Johan Hedberg03811012010-12-08 00:21:06 +02001972 break;
1973 }
1974
Johan Hedberge41d8b42010-12-13 21:07:03 +02001975 if (err < 0)
1976 goto done;
1977
Johan Hedberg03811012010-12-08 00:21:06 +02001978 err = msglen;
1979
1980done:
1981 kfree(buf);
1982 return err;
1983}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001984
Johan Hedbergb24752f2011-11-03 14:40:33 +02001985static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
1986{
1987 u8 *status = data;
1988
1989 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
1990 mgmt_pending_remove(cmd);
1991}
1992
Johan Hedberg744cf192011-11-08 20:40:14 +02001993int mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001994{
Johan Hedberg744cf192011-11-08 20:40:14 +02001995 return mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001996}
1997
Johan Hedberg744cf192011-11-08 20:40:14 +02001998int mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001999{
Johan Hedbergb24752f2011-11-03 14:40:33 +02002000 u8 status = ENODEV;
2001
Johan Hedberg744cf192011-11-08 20:40:14 +02002002 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002003
Johan Hedberg744cf192011-11-08 20:40:14 +02002004 return mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002005}
2006
Johan Hedberg73f22f62010-12-29 16:00:25 +02002007struct cmd_lookup {
Johan Hedberg72a734e2010-12-30 00:38:22 +02002008 u8 val;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002009 struct sock *sk;
2010};
2011
Johan Hedberg72a734e2010-12-30 00:38:22 +02002012static void mode_rsp(struct pending_cmd *cmd, void *data)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002013{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01002014 struct mgmt_mode *cp = cmd->param;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002015 struct cmd_lookup *match = data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002016
Johan Hedberg72a734e2010-12-30 00:38:22 +02002017 if (cp->val != match->val)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002018 return;
2019
Johan Hedberg053f0212011-01-26 13:07:10 +02002020 send_mode_rsp(cmd->sk, cmd->opcode, cmd->index, cp->val);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002021
2022 list_del(&cmd->list);
2023
2024 if (match->sk == NULL) {
2025 match->sk = cmd->sk;
2026 sock_hold(match->sk);
2027 }
2028
2029 mgmt_pending_free(cmd);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002030}
Johan Hedberg5add6af2010-12-16 10:00:37 +02002031
Johan Hedberg744cf192011-11-08 20:40:14 +02002032int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg5add6af2010-12-16 10:00:37 +02002033{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002034 struct mgmt_mode ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002035 struct cmd_lookup match = { powered, NULL };
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002036 int ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002037
Johan Hedberg744cf192011-11-08 20:40:14 +02002038 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, mode_rsp, &match);
Johan Hedberg5add6af2010-12-16 10:00:37 +02002039
Johan Hedbergb24752f2011-11-03 14:40:33 +02002040 if (!powered) {
2041 u8 status = ENETDOWN;
Johan Hedberg744cf192011-11-08 20:40:14 +02002042 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002043 }
2044
Johan Hedberg72a734e2010-12-30 00:38:22 +02002045 ev.val = powered;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002046
Johan Hedberg744cf192011-11-08 20:40:14 +02002047 ret = mgmt_event(MGMT_EV_POWERED, hdev, &ev, sizeof(ev), match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002048
2049 if (match.sk)
2050 sock_put(match.sk);
2051
2052 return ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002053}
Johan Hedberg73f22f62010-12-29 16:00:25 +02002054
Johan Hedberg744cf192011-11-08 20:40:14 +02002055int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg73f22f62010-12-29 16:00:25 +02002056{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002057 struct mgmt_mode ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002058 struct cmd_lookup match = { discoverable, NULL };
2059 int ret;
2060
Johan Hedberg744cf192011-11-08 20:40:14 +02002061 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, mode_rsp, &match);
Johan Hedberg72a734e2010-12-30 00:38:22 +02002062
Johan Hedberg72a734e2010-12-30 00:38:22 +02002063 ev.val = discoverable;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002064
Johan Hedberg744cf192011-11-08 20:40:14 +02002065 ret = mgmt_event(MGMT_EV_DISCOVERABLE, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01002066 match.sk);
Johan Hedberg73f22f62010-12-29 16:00:25 +02002067
2068 if (match.sk)
2069 sock_put(match.sk);
2070
2071 return ret;
2072}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002073
Johan Hedberg744cf192011-11-08 20:40:14 +02002074int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002075{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002076 struct mgmt_mode ev;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002077 struct cmd_lookup match = { connectable, NULL };
2078 int ret;
2079
Johan Hedberg744cf192011-11-08 20:40:14 +02002080 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev, mode_rsp, &match);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002081
Johan Hedberg72a734e2010-12-30 00:38:22 +02002082 ev.val = connectable;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002083
Johan Hedberg744cf192011-11-08 20:40:14 +02002084 ret = mgmt_event(MGMT_EV_CONNECTABLE, hdev, &ev, sizeof(ev), match.sk);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002085
2086 if (match.sk)
2087 sock_put(match.sk);
2088
2089 return ret;
2090}
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002091
Johan Hedberg744cf192011-11-08 20:40:14 +02002092int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002093{
2094 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02002095 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002096 cmd_status_rsp, &status);
2097
2098 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02002099 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002100 cmd_status_rsp, &status);
2101
2102 return 0;
2103}
2104
Johan Hedberg744cf192011-11-08 20:40:14 +02002105int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
2106 u8 persistent)
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002107{
Johan Hedberg86742e12011-11-07 23:13:38 +02002108 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002109
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002110 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002111
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002112 ev.store_hint = persistent;
2113 bacpy(&ev.key.bdaddr, &key->bdaddr);
2114 ev.key.type = key->type;
2115 memcpy(ev.key.val, key->val, 16);
2116 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002117
Johan Hedberg744cf192011-11-08 20:40:14 +02002118 return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002119}
Johan Hedbergf7520542011-01-20 12:34:39 +02002120
Johan Hedberg48264f02011-11-09 13:58:58 +02002121int mgmt_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
2122 u8 addr_type)
Johan Hedbergf7520542011-01-20 12:34:39 +02002123{
Johan Hedberg4c659c32011-11-07 23:13:39 +02002124 struct mgmt_addr_info ev;
Johan Hedbergf7520542011-01-20 12:34:39 +02002125
Johan Hedbergf7520542011-01-20 12:34:39 +02002126 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02002127 ev.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02002128
Johan Hedberg744cf192011-11-08 20:40:14 +02002129 return mgmt_event(MGMT_EV_CONNECTED, hdev, &ev, sizeof(ev), NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02002130}
2131
Johan Hedberg8962ee72011-01-20 12:40:27 +02002132static void disconnect_rsp(struct pending_cmd *cmd, void *data)
2133{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01002134 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002135 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02002136 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002137
Johan Hedberga38528f2011-01-22 06:46:43 +02002138 bacpy(&rp.bdaddr, &cp->bdaddr);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02002139 rp.status = 0;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002140
Szymon Janc4e51eae2011-02-25 19:05:48 +01002141 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002142
2143 *sk = cmd->sk;
2144 sock_hold(*sk);
2145
Johan Hedberga664b5b2011-02-19 12:06:02 -03002146 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002147}
2148
Johan Hedberga8a1d192011-11-10 15:54:38 +02002149static void remove_keys_rsp(struct pending_cmd *cmd, void *data)
2150{
2151 u8 *status = data;
2152 struct mgmt_cp_remove_keys *cp = cmd->param;
2153 struct mgmt_rp_remove_keys rp;
2154
2155 memset(&rp, 0, sizeof(rp));
2156 bacpy(&rp.bdaddr, &cp->bdaddr);
2157 if (status != NULL)
2158 rp.status = *status;
2159
2160 cmd_complete(cmd->sk, cmd->index, MGMT_OP_REMOVE_KEYS, &rp,
2161 sizeof(rp));
2162
2163 mgmt_pending_remove(cmd);
2164}
2165
Johan Hedberg48264f02011-11-09 13:58:58 +02002166int mgmt_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
2167 u8 addr_type)
Johan Hedbergf7520542011-01-20 12:34:39 +02002168{
Johan Hedberg4c659c32011-11-07 23:13:39 +02002169 struct mgmt_addr_info ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002170 struct sock *sk = NULL;
2171 int err;
2172
Johan Hedberg744cf192011-11-08 20:40:14 +02002173 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02002174
Johan Hedbergf7520542011-01-20 12:34:39 +02002175 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02002176 ev.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02002177
Johan Hedberg744cf192011-11-08 20:40:14 +02002178 err = mgmt_event(MGMT_EV_DISCONNECTED, hdev, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002179
2180 if (sk)
2181 sock_put(sk);
2182
Johan Hedberga8a1d192011-11-10 15:54:38 +02002183 mgmt_pending_foreach(MGMT_OP_REMOVE_KEYS, hdev, remove_keys_rsp, NULL);
2184
Johan Hedberg8962ee72011-01-20 12:40:27 +02002185 return err;
2186}
2187
Johan Hedberg37d9ef72011-11-10 15:54:39 +02002188int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02002189{
2190 struct pending_cmd *cmd;
2191 int err;
2192
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002193 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002194 if (!cmd)
2195 return -ENOENT;
2196
Johan Hedberg37d9ef72011-11-10 15:54:39 +02002197 if (bdaddr) {
2198 struct mgmt_rp_disconnect rp;
2199
2200 bacpy(&rp.bdaddr, bdaddr);
2201 rp.status = status;
2202
2203 err = cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
2204 &rp, sizeof(rp));
2205 } else
2206 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_DISCONNECT,
2207 status);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002208
Johan Hedberga664b5b2011-02-19 12:06:02 -03002209 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002210
2211 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02002212}
Johan Hedberg17d5c042011-01-22 06:09:08 +02002213
Johan Hedberg48264f02011-11-09 13:58:58 +02002214int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
2215 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02002216{
2217 struct mgmt_ev_connect_failed ev;
2218
Johan Hedberg4c659c32011-11-07 23:13:39 +02002219 bacpy(&ev.addr.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02002220 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedberg17d5c042011-01-22 06:09:08 +02002221 ev.status = status;
2222
Johan Hedberg744cf192011-11-08 20:40:14 +02002223 return mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02002224}
Johan Hedberg980e1a52011-01-22 06:10:07 +02002225
Johan Hedberg744cf192011-11-08 20:40:14 +02002226int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002227{
2228 struct mgmt_ev_pin_code_request ev;
2229
Johan Hedberg980e1a52011-01-22 06:10:07 +02002230 bacpy(&ev.bdaddr, bdaddr);
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02002231 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002232
Johan Hedberg744cf192011-11-08 20:40:14 +02002233 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01002234 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002235}
2236
Johan Hedberg744cf192011-11-08 20:40:14 +02002237int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
2238 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002239{
2240 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002241 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002242 int err;
2243
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002244 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002245 if (!cmd)
2246 return -ENOENT;
2247
Johan Hedbergac56fb12011-02-19 12:05:59 -03002248 bacpy(&rp.bdaddr, bdaddr);
2249 rp.status = status;
2250
Johan Hedberg744cf192011-11-08 20:40:14 +02002251 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY, &rp,
Szymon Janc4e51eae2011-02-25 19:05:48 +01002252 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002253
Johan Hedberga664b5b2011-02-19 12:06:02 -03002254 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002255
2256 return err;
2257}
2258
Johan Hedberg744cf192011-11-08 20:40:14 +02002259int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
2260 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002261{
2262 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002263 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002264 int err;
2265
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002266 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002267 if (!cmd)
2268 return -ENOENT;
2269
Johan Hedbergac56fb12011-02-19 12:05:59 -03002270 bacpy(&rp.bdaddr, bdaddr);
2271 rp.status = status;
2272
Johan Hedberg744cf192011-11-08 20:40:14 +02002273 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY, &rp,
Szymon Janc4e51eae2011-02-25 19:05:48 +01002274 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002275
Johan Hedberga664b5b2011-02-19 12:06:02 -03002276 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002277
2278 return err;
2279}
Johan Hedberga5c29682011-02-19 12:05:57 -03002280
Johan Hedberg744cf192011-11-08 20:40:14 +02002281int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
2282 __le32 value, u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03002283{
2284 struct mgmt_ev_user_confirm_request ev;
2285
Johan Hedberg744cf192011-11-08 20:40:14 +02002286 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03002287
Johan Hedberga5c29682011-02-19 12:05:57 -03002288 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07002289 ev.confirm_hint = confirm_hint;
Johan Hedberga5c29682011-02-19 12:05:57 -03002290 put_unaligned_le32(value, &ev.value);
2291
Johan Hedberg744cf192011-11-08 20:40:14 +02002292 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01002293 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03002294}
2295
Johan Hedberg744cf192011-11-08 20:40:14 +02002296static int confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
2297 u8 status, u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03002298{
2299 struct pending_cmd *cmd;
2300 struct mgmt_rp_user_confirm_reply rp;
2301 int err;
2302
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002303 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002304 if (!cmd)
2305 return -ENOENT;
2306
Johan Hedberga5c29682011-02-19 12:05:57 -03002307 bacpy(&rp.bdaddr, bdaddr);
2308 rp.status = status;
Johan Hedberg744cf192011-11-08 20:40:14 +02002309 err = cmd_complete(cmd->sk, hdev->id, opcode, &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03002310
Johan Hedberga664b5b2011-02-19 12:06:02 -03002311 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002312
2313 return err;
2314}
2315
Johan Hedberg744cf192011-11-08 20:40:14 +02002316int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
2317 u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03002318{
Johan Hedberg744cf192011-11-08 20:40:14 +02002319 return confirm_reply_complete(hdev, bdaddr, status,
Johan Hedberga5c29682011-02-19 12:05:57 -03002320 MGMT_OP_USER_CONFIRM_REPLY);
2321}
2322
Johan Hedberg744cf192011-11-08 20:40:14 +02002323int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev,
2324 bdaddr_t *bdaddr, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03002325{
Johan Hedberg744cf192011-11-08 20:40:14 +02002326 return confirm_reply_complete(hdev, bdaddr, status,
Johan Hedberga5c29682011-02-19 12:05:57 -03002327 MGMT_OP_USER_CONFIRM_NEG_REPLY);
2328}
Johan Hedberg2a611692011-02-19 12:06:00 -03002329
Johan Hedberg744cf192011-11-08 20:40:14 +02002330int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03002331{
2332 struct mgmt_ev_auth_failed ev;
2333
Johan Hedberg2a611692011-02-19 12:06:00 -03002334 bacpy(&ev.bdaddr, bdaddr);
2335 ev.status = status;
2336
Johan Hedberg744cf192011-11-08 20:40:14 +02002337 return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03002338}
Johan Hedbergb312b1612011-03-16 14:29:37 +02002339
Johan Hedberg744cf192011-11-08 20:40:14 +02002340int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02002341{
2342 struct pending_cmd *cmd;
2343 struct mgmt_cp_set_local_name ev;
2344 int err;
2345
2346 memset(&ev, 0, sizeof(ev));
2347 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
2348
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002349 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002350 if (!cmd)
2351 goto send_event;
2352
2353 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02002354 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
2355 EIO);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002356 goto failed;
2357 }
2358
Johan Hedberg744cf192011-11-08 20:40:14 +02002359 update_eir(hdev);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002360
Johan Hedberg744cf192011-11-08 20:40:14 +02002361 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, &ev,
Johan Hedbergb312b1612011-03-16 14:29:37 +02002362 sizeof(ev));
2363 if (err < 0)
2364 goto failed;
2365
2366send_event:
Johan Hedberg744cf192011-11-08 20:40:14 +02002367 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
Johan Hedbergb312b1612011-03-16 14:29:37 +02002368 cmd ? cmd->sk : NULL);
2369
2370failed:
2371 if (cmd)
2372 mgmt_pending_remove(cmd);
2373 return err;
2374}
Szymon Jancc35938b2011-03-22 13:12:21 +01002375
Johan Hedberg744cf192011-11-08 20:40:14 +02002376int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
2377 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01002378{
2379 struct pending_cmd *cmd;
2380 int err;
2381
Johan Hedberg744cf192011-11-08 20:40:14 +02002382 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01002383
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002384 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002385 if (!cmd)
2386 return -ENOENT;
2387
2388 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02002389 err = cmd_status(cmd->sk, hdev->id,
2390 MGMT_OP_READ_LOCAL_OOB_DATA, EIO);
Szymon Jancc35938b2011-03-22 13:12:21 +01002391 } else {
2392 struct mgmt_rp_read_local_oob_data rp;
2393
2394 memcpy(rp.hash, hash, sizeof(rp.hash));
2395 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
2396
Johan Hedberg744cf192011-11-08 20:40:14 +02002397 err = cmd_complete(cmd->sk, hdev->id,
2398 MGMT_OP_READ_LOCAL_OOB_DATA,
2399 &rp, sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01002400 }
2401
2402 mgmt_pending_remove(cmd);
2403
2404 return err;
2405}
Johan Hedberge17acd42011-03-30 23:57:16 +03002406
Johan Hedberg48264f02011-11-09 13:58:58 +02002407int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
2408 u8 addr_type, u8 *dev_class, s8 rssi, u8 *eir)
Johan Hedberge17acd42011-03-30 23:57:16 +03002409{
2410 struct mgmt_ev_device_found ev;
2411
2412 memset(&ev, 0, sizeof(ev));
2413
Johan Hedberg4c659c32011-11-07 23:13:39 +02002414 bacpy(&ev.addr.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02002415 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedberge17acd42011-03-30 23:57:16 +03002416 ev.rssi = rssi;
2417
2418 if (eir)
2419 memcpy(ev.eir, eir, sizeof(ev.eir));
2420
Andre Guedesf8523592011-09-09 18:56:26 -03002421 if (dev_class)
2422 memcpy(ev.dev_class, dev_class, sizeof(ev.dev_class));
2423
Johan Hedberg744cf192011-11-08 20:40:14 +02002424 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, &ev, sizeof(ev), NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03002425}
Johan Hedberga88a9652011-03-30 13:18:12 +03002426
Johan Hedberg744cf192011-11-08 20:40:14 +02002427int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *name)
Johan Hedberga88a9652011-03-30 13:18:12 +03002428{
2429 struct mgmt_ev_remote_name ev;
2430
2431 memset(&ev, 0, sizeof(ev));
2432
2433 bacpy(&ev.bdaddr, bdaddr);
2434 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
2435
Johan Hedberg744cf192011-11-08 20:40:14 +02002436 return mgmt_event(MGMT_EV_REMOTE_NAME, hdev, &ev, sizeof(ev), NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03002437}
Johan Hedberg314b2382011-04-27 10:29:57 -04002438
Andre Guedes7a135102011-11-09 17:14:25 -03002439int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
Johan Hedberg164a6e72011-11-01 17:06:44 +02002440{
2441 struct pending_cmd *cmd;
2442 int err;
2443
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002444 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02002445 if (!cmd)
2446 return -ENOENT;
2447
Johan Hedberg744cf192011-11-08 20:40:14 +02002448 err = cmd_status(cmd->sk, hdev->id, cmd->opcode, status);
Johan Hedberg164a6e72011-11-01 17:06:44 +02002449 mgmt_pending_remove(cmd);
2450
2451 return err;
2452}
2453
Andre Guedese6d465c2011-11-09 17:14:26 -03002454int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
2455{
2456 struct pending_cmd *cmd;
2457 int err;
2458
2459 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
2460 if (!cmd)
2461 return -ENOENT;
2462
2463 err = cmd_status(cmd->sk, hdev->id, cmd->opcode, status);
2464 mgmt_pending_remove(cmd);
2465
2466 return err;
2467}
2468
Johan Hedberg744cf192011-11-08 20:40:14 +02002469int mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04002470{
Johan Hedberg164a6e72011-11-01 17:06:44 +02002471 struct pending_cmd *cmd;
2472
2473 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002474 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02002475 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002476 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02002477
2478 if (cmd != NULL) {
Johan Hedberg744cf192011-11-08 20:40:14 +02002479 cmd_complete(cmd->sk, hdev->id, cmd->opcode, NULL, 0);
Johan Hedberg164a6e72011-11-01 17:06:44 +02002480 mgmt_pending_remove(cmd);
2481 }
2482
Johan Hedberg744cf192011-11-08 20:40:14 +02002483 return mgmt_event(MGMT_EV_DISCOVERING, hdev, &discovering,
Johan Hedberg314b2382011-04-27 10:29:57 -04002484 sizeof(discovering), NULL);
2485}
Antti Julku5e762442011-08-25 16:48:02 +03002486
Johan Hedberg744cf192011-11-08 20:40:14 +02002487int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr)
Antti Julku5e762442011-08-25 16:48:02 +03002488{
2489 struct pending_cmd *cmd;
2490 struct mgmt_ev_device_blocked ev;
2491
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002492 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002493
2494 bacpy(&ev.bdaddr, bdaddr);
2495
Johan Hedberg744cf192011-11-08 20:40:14 +02002496 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
2497 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03002498}
2499
Johan Hedberg744cf192011-11-08 20:40:14 +02002500int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr)
Antti Julku5e762442011-08-25 16:48:02 +03002501{
2502 struct pending_cmd *cmd;
2503 struct mgmt_ev_device_unblocked ev;
2504
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002505 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002506
2507 bacpy(&ev.bdaddr, bdaddr);
2508
Johan Hedberg744cf192011-11-08 20:40:14 +02002509 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
2510 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03002511}