blob: 6c924f24b3d9c7cf529e5e66ef50f8ccb4a007d0 [file] [log] [blame]
Johan Hedberg03811012010-12-08 00:21:06 +02001/*
2 BlueZ - Bluetooth protocol stack for Linux
3 Copyright (C) 2010 Nokia Corporation
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License version 2 as
7 published by the Free Software Foundation;
8
9 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
10 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
11 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
12 IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
13 CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
14 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17
18 ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
19 COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
20 SOFTWARE IS DISCLAIMED.
21*/
22
23/* Bluetooth HCI Management interface */
24
Szymon Janc72359752011-02-17 14:16:32 +010025#include <linux/uaccess.h>
Johan Hedberg03811012010-12-08 00:21:06 +020026#include <asm/unaligned.h>
27
28#include <net/bluetooth/bluetooth.h>
29#include <net/bluetooth/hci_core.h>
30#include <net/bluetooth/mgmt.h>
31
Johan Hedberg02d98122010-12-13 21:07:04 +020032#define MGMT_VERSION 0
33#define MGMT_REVISION 1
34
Andre Guedes2519a1f2011-11-07 11:45:24 -030035#define INQUIRY_LEN_BREDR 0x08 /* TGAP(100) */
36
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020037struct pending_cmd {
38 struct list_head list;
Johan Hedbergfc2f4b12011-11-09 13:58:56 +020039 u16 opcode;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020040 int index;
Szymon Jancc68fb7f2011-03-22 13:12:19 +010041 void *param;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020042 struct sock *sk;
Johan Hedberge9a416b2011-02-19 12:05:56 -030043 void *user_data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020044};
45
Szymon Janc4e51eae2011-02-25 19:05:48 +010046static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
Johan Hedbergf7b64e62010-12-13 21:07:06 +020047{
48 struct sk_buff *skb;
49 struct mgmt_hdr *hdr;
50 struct mgmt_ev_cmd_status *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -030051 int err;
Johan Hedbergf7b64e62010-12-13 21:07:06 +020052
Szymon Janc34eb5252011-02-28 14:10:08 +010053 BT_DBG("sock %p, index %u, cmd %u, status %u", sk, index, cmd, status);
Johan Hedbergf7b64e62010-12-13 21:07:06 +020054
55 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_ATOMIC);
56 if (!skb)
57 return -ENOMEM;
58
59 hdr = (void *) skb_put(skb, sizeof(*hdr));
60
61 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_STATUS);
Szymon Janc4e51eae2011-02-25 19:05:48 +010062 hdr->index = cpu_to_le16(index);
Johan Hedbergf7b64e62010-12-13 21:07:06 +020063 hdr->len = cpu_to_le16(sizeof(*ev));
64
65 ev = (void *) skb_put(skb, sizeof(*ev));
66 ev->status = status;
67 put_unaligned_le16(cmd, &ev->opcode);
68
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -030069 err = sock_queue_rcv_skb(sk, skb);
70 if (err < 0)
Johan Hedbergf7b64e62010-12-13 21:07:06 +020071 kfree_skb(skb);
72
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -030073 return err;
Johan Hedbergf7b64e62010-12-13 21:07:06 +020074}
75
Szymon Janc4e51eae2011-02-25 19:05:48 +010076static int cmd_complete(struct sock *sk, u16 index, u16 cmd, void *rp,
77 size_t rp_len)
Johan Hedberg02d98122010-12-13 21:07:04 +020078{
79 struct sk_buff *skb;
80 struct mgmt_hdr *hdr;
81 struct mgmt_ev_cmd_complete *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -030082 int err;
Johan Hedberg02d98122010-12-13 21:07:04 +020083
84 BT_DBG("sock %p", sk);
85
Johan Hedberga38528f2011-01-22 06:46:43 +020086 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + rp_len, GFP_ATOMIC);
Johan Hedberg02d98122010-12-13 21:07:04 +020087 if (!skb)
88 return -ENOMEM;
89
90 hdr = (void *) skb_put(skb, sizeof(*hdr));
Johan Hedberga38528f2011-01-22 06:46:43 +020091
Johan Hedberg02d98122010-12-13 21:07:04 +020092 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE);
Szymon Janc4e51eae2011-02-25 19:05:48 +010093 hdr->index = cpu_to_le16(index);
Johan Hedberga38528f2011-01-22 06:46:43 +020094 hdr->len = cpu_to_le16(sizeof(*ev) + rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +020095
Johan Hedberga38528f2011-01-22 06:46:43 +020096 ev = (void *) skb_put(skb, sizeof(*ev) + rp_len);
97 put_unaligned_le16(cmd, &ev->opcode);
Szymon Janc8020c162011-02-28 14:09:50 +010098
99 if (rp)
100 memcpy(ev->data, rp, rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200101
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300102 err = sock_queue_rcv_skb(sk, skb);
103 if (err < 0)
Johan Hedberg02d98122010-12-13 21:07:04 +0200104 kfree_skb(skb);
105
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300106 return err;;
Johan Hedberg02d98122010-12-13 21:07:04 +0200107}
108
Johan Hedberga38528f2011-01-22 06:46:43 +0200109static int read_version(struct sock *sk)
110{
111 struct mgmt_rp_read_version rp;
112
113 BT_DBG("sock %p", sk);
114
115 rp.version = MGMT_VERSION;
116 put_unaligned_le16(MGMT_REVISION, &rp.revision);
117
Szymon Janc4e51eae2011-02-25 19:05:48 +0100118 return cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, &rp,
119 sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200120}
121
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200122static int read_index_list(struct sock *sk)
123{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200124 struct mgmt_rp_read_index_list *rp;
125 struct list_head *p;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200126 struct hci_dev *d;
Johan Hedberga38528f2011-01-22 06:46:43 +0200127 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200128 u16 count;
Johan Hedberga38528f2011-01-22 06:46:43 +0200129 int i, err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200130
131 BT_DBG("sock %p", sk);
132
133 read_lock(&hci_dev_list_lock);
134
135 count = 0;
136 list_for_each(p, &hci_dev_list) {
137 count++;
138 }
139
Johan Hedberga38528f2011-01-22 06:46:43 +0200140 rp_len = sizeof(*rp) + (2 * count);
141 rp = kmalloc(rp_len, GFP_ATOMIC);
142 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100143 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200144 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100145 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200146
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200147 put_unaligned_le16(count, &rp->num_controllers);
148
149 i = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200150 list_for_each_entry(d, &hci_dev_list, list) {
Johan Hedberg32435532011-11-07 22:16:04 +0200151 if (test_and_clear_bit(HCI_AUTO_OFF, &d->flags))
Johan Hedberge0f93092011-11-09 01:44:22 +0200152 cancel_delayed_work(&d->power_off);
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200153
154 if (test_bit(HCI_SETUP, &d->flags))
155 continue;
156
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200157 put_unaligned_le16(d->id, &rp->index[i++]);
158 BT_DBG("Added hci%u", d->id);
159 }
160
161 read_unlock(&hci_dev_list_lock);
162
Szymon Janc4e51eae2011-02-25 19:05:48 +0100163 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST, rp,
164 rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200165
Johan Hedberga38528f2011-01-22 06:46:43 +0200166 kfree(rp);
167
168 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200169}
170
Szymon Janc4e51eae2011-02-25 19:05:48 +0100171static int read_controller_info(struct sock *sk, u16 index)
Johan Hedberg03811012010-12-08 00:21:06 +0200172{
Johan Hedberga38528f2011-01-22 06:46:43 +0200173 struct mgmt_rp_read_info rp;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200174 struct hci_dev *hdev;
Johan Hedberg03811012010-12-08 00:21:06 +0200175
Szymon Janc4e51eae2011-02-25 19:05:48 +0100176 BT_DBG("sock %p hci%u", sk, index);
Johan Hedberg03811012010-12-08 00:21:06 +0200177
Szymon Janc4e51eae2011-02-25 19:05:48 +0100178 hdev = hci_dev_get(index);
Johan Hedberga38528f2011-01-22 06:46:43 +0200179 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100180 return cmd_status(sk, index, MGMT_OP_READ_INFO, ENODEV);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200181
Johan Hedberg32435532011-11-07 22:16:04 +0200182 if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->flags))
183 cancel_delayed_work_sync(&hdev->power_off);
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200184
Andre Guedes8c156c32011-07-07 10:30:36 -0300185 hci_dev_lock_bh(hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200186
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200187 set_bit(HCI_MGMT, &hdev->flags);
188
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200189 memset(&rp, 0, sizeof(rp));
190
Johan Hedberga38528f2011-01-22 06:46:43 +0200191 rp.type = hdev->dev_type;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200192
Johan Hedberga38528f2011-01-22 06:46:43 +0200193 rp.powered = test_bit(HCI_UP, &hdev->flags);
194 rp.connectable = test_bit(HCI_PSCAN, &hdev->flags);
195 rp.discoverable = test_bit(HCI_ISCAN, &hdev->flags);
196 rp.pairable = test_bit(HCI_PSCAN, &hdev->flags);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200197
198 if (test_bit(HCI_AUTH, &hdev->flags))
Johan Hedberga38528f2011-01-22 06:46:43 +0200199 rp.sec_mode = 3;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200200 else if (hdev->ssp_mode > 0)
Johan Hedberga38528f2011-01-22 06:46:43 +0200201 rp.sec_mode = 4;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200202 else
Johan Hedberga38528f2011-01-22 06:46:43 +0200203 rp.sec_mode = 2;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200204
Johan Hedberga38528f2011-01-22 06:46:43 +0200205 bacpy(&rp.bdaddr, &hdev->bdaddr);
206 memcpy(rp.features, hdev->features, 8);
207 memcpy(rp.dev_class, hdev->dev_class, 3);
208 put_unaligned_le16(hdev->manufacturer, &rp.manufacturer);
209 rp.hci_ver = hdev->hci_ver;
210 put_unaligned_le16(hdev->hci_rev, &rp.hci_rev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200211
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200212 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
213
Andre Guedes8c156c32011-07-07 10:30:36 -0300214 hci_dev_unlock_bh(hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200215 hci_dev_put(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200216
Szymon Janc4e51eae2011-02-25 19:05:48 +0100217 return cmd_complete(sk, index, MGMT_OP_READ_INFO, &rp, sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +0200218}
219
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200220static void mgmt_pending_free(struct pending_cmd *cmd)
221{
222 sock_put(cmd->sk);
Szymon Jancc68fb7f2011-03-22 13:12:19 +0100223 kfree(cmd->param);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200224 kfree(cmd);
225}
226
Johan Hedberg366a0332011-02-19 12:05:55 -0300227static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
Johan Hedberg2e58ef32011-11-08 20:40:15 +0200228 struct hci_dev *hdev,
229 void *data, u16 len)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200230{
231 struct pending_cmd *cmd;
232
233 cmd = kmalloc(sizeof(*cmd), GFP_ATOMIC);
234 if (!cmd)
Johan Hedberg366a0332011-02-19 12:05:55 -0300235 return NULL;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200236
237 cmd->opcode = opcode;
Johan Hedberg2e58ef32011-11-08 20:40:15 +0200238 cmd->index = hdev->id;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200239
Szymon Jancc68fb7f2011-03-22 13:12:19 +0100240 cmd->param = kmalloc(len, GFP_ATOMIC);
241 if (!cmd->param) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200242 kfree(cmd);
Johan Hedberg366a0332011-02-19 12:05:55 -0300243 return NULL;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200244 }
245
Szymon Janc8fce6352011-03-22 13:12:20 +0100246 if (data)
247 memcpy(cmd->param, data, len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200248
249 cmd->sk = sk;
250 sock_hold(sk);
251
Johan Hedberg2e58ef32011-11-08 20:40:15 +0200252 list_add(&cmd->list, &hdev->mgmt_pending);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200253
Johan Hedberg366a0332011-02-19 12:05:55 -0300254 return cmd;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200255}
256
Johan Hedberg744cf192011-11-08 20:40:14 +0200257static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200258 void (*cb)(struct pending_cmd *cmd, void *data),
259 void *data)
260{
261 struct list_head *p, *n;
262
Johan Hedberg2e58ef32011-11-08 20:40:15 +0200263 list_for_each_safe(p, n, &hdev->mgmt_pending) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200264 struct pending_cmd *cmd;
265
266 cmd = list_entry(p, struct pending_cmd, list);
267
Johan Hedbergb24752f2011-11-03 14:40:33 +0200268 if (opcode > 0 && cmd->opcode != opcode)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200269 continue;
270
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200271 cb(cmd, data);
272 }
273}
274
Johan Hedberg2e58ef32011-11-08 20:40:15 +0200275static struct pending_cmd *mgmt_pending_find(u16 opcode, struct hci_dev *hdev)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200276{
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200277 struct pending_cmd *cmd;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200278
Johan Hedberg2e58ef32011-11-08 20:40:15 +0200279 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberg2aeabcb2011-11-09 13:58:57 +0200280 if (cmd->opcode == opcode)
281 return cmd;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200282 }
283
284 return NULL;
285}
286
Johan Hedberga664b5b2011-02-19 12:06:02 -0300287static void mgmt_pending_remove(struct pending_cmd *cmd)
Johan Hedberg73f22f62010-12-29 16:00:25 +0200288{
Johan Hedberg73f22f62010-12-29 16:00:25 +0200289 list_del(&cmd->list);
290 mgmt_pending_free(cmd);
291}
292
Szymon Janc4e51eae2011-02-25 19:05:48 +0100293static int set_powered(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200294{
Johan Hedberg72a734e2010-12-30 00:38:22 +0200295 struct mgmt_mode *cp;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200296 struct hci_dev *hdev;
Johan Hedberg366a0332011-02-19 12:05:55 -0300297 struct pending_cmd *cmd;
Johan Hedberg366a0332011-02-19 12:05:55 -0300298 int err, up;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200299
300 cp = (void *) data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200301
Szymon Janc4e51eae2011-02-25 19:05:48 +0100302 BT_DBG("request for hci%u", index);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200303
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100304 if (len != sizeof(*cp))
305 return cmd_status(sk, index, MGMT_OP_SET_POWERED, EINVAL);
306
Szymon Janc4e51eae2011-02-25 19:05:48 +0100307 hdev = hci_dev_get(index);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200308 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100309 return cmd_status(sk, index, MGMT_OP_SET_POWERED, ENODEV);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200310
Andre Guedes8c156c32011-07-07 10:30:36 -0300311 hci_dev_lock_bh(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200312
313 up = test_bit(HCI_UP, &hdev->flags);
Johan Hedberg72a734e2010-12-30 00:38:22 +0200314 if ((cp->val && up) || (!cp->val && !up)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100315 err = cmd_status(sk, index, MGMT_OP_SET_POWERED, EALREADY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200316 goto failed;
317 }
318
Johan Hedberg2e58ef32011-11-08 20:40:15 +0200319 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100320 err = cmd_status(sk, index, MGMT_OP_SET_POWERED, EBUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200321 goto failed;
322 }
323
Johan Hedberg2e58ef32011-11-08 20:40:15 +0200324 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -0300325 if (!cmd) {
326 err = -ENOMEM;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200327 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -0300328 }
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200329
Johan Hedberg72a734e2010-12-30 00:38:22 +0200330 if (cp->val)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200331 queue_work(hdev->workqueue, &hdev->power_on);
332 else
Johan Hedberg32435532011-11-07 22:16:04 +0200333 queue_work(hdev->workqueue, &hdev->power_off.work);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200334
Johan Hedberg366a0332011-02-19 12:05:55 -0300335 err = 0;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200336
337failed:
Andre Guedes8c156c32011-07-07 10:30:36 -0300338 hci_dev_unlock_bh(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200339 hci_dev_put(hdev);
Johan Hedberg366a0332011-02-19 12:05:55 -0300340 return err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200341}
342
Szymon Janc4e51eae2011-02-25 19:05:48 +0100343static int set_discoverable(struct sock *sk, u16 index, unsigned char *data,
344 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +0200345{
Johan Hedberg16ab91a2011-11-07 22:16:02 +0200346 struct mgmt_cp_set_discoverable *cp;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200347 struct hci_dev *hdev;
Johan Hedberg366a0332011-02-19 12:05:55 -0300348 struct pending_cmd *cmd;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200349 u8 scan;
350 int err;
351
352 cp = (void *) data;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200353
Szymon Janc4e51eae2011-02-25 19:05:48 +0100354 BT_DBG("request for hci%u", index);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200355
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100356 if (len != sizeof(*cp))
357 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, EINVAL);
358
Szymon Janc4e51eae2011-02-25 19:05:48 +0100359 hdev = hci_dev_get(index);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200360 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100361 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, ENODEV);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200362
Andre Guedes8c156c32011-07-07 10:30:36 -0300363 hci_dev_lock_bh(hdev);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200364
365 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100366 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, ENETDOWN);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200367 goto failed;
368 }
369
Johan Hedberg2e58ef32011-11-08 20:40:15 +0200370 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
371 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100372 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, EBUSY);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200373 goto failed;
374 }
375
Johan Hedberg72a734e2010-12-30 00:38:22 +0200376 if (cp->val == test_bit(HCI_ISCAN, &hdev->flags) &&
Johan Hedberg73f22f62010-12-29 16:00:25 +0200377 test_bit(HCI_PSCAN, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100378 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, EALREADY);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200379 goto failed;
380 }
381
Johan Hedberg2e58ef32011-11-08 20:40:15 +0200382 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -0300383 if (!cmd) {
384 err = -ENOMEM;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200385 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -0300386 }
Johan Hedberg73f22f62010-12-29 16:00:25 +0200387
388 scan = SCAN_PAGE;
389
Johan Hedberg72a734e2010-12-30 00:38:22 +0200390 if (cp->val)
Johan Hedberg73f22f62010-12-29 16:00:25 +0200391 scan |= SCAN_INQUIRY;
Johan Hedberg16ab91a2011-11-07 22:16:02 +0200392 else
Johan Hedberge0f93092011-11-09 01:44:22 +0200393 cancel_delayed_work(&hdev->discov_off);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200394
395 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
396 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -0300397 mgmt_pending_remove(cmd);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200398
Johan Hedberg16ab91a2011-11-07 22:16:02 +0200399 if (cp->val)
400 hdev->discov_timeout = get_unaligned_le16(&cp->timeout);
401
Johan Hedberg73f22f62010-12-29 16:00:25 +0200402failed:
Andre Guedes8c156c32011-07-07 10:30:36 -0300403 hci_dev_unlock_bh(hdev);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200404 hci_dev_put(hdev);
405
406 return err;
407}
408
Szymon Janc4e51eae2011-02-25 19:05:48 +0100409static int set_connectable(struct sock *sk, u16 index, unsigned char *data,
410 u16 len)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200411{
Johan Hedberg72a734e2010-12-30 00:38:22 +0200412 struct mgmt_mode *cp;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200413 struct hci_dev *hdev;
Johan Hedberg366a0332011-02-19 12:05:55 -0300414 struct pending_cmd *cmd;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200415 u8 scan;
416 int err;
417
418 cp = (void *) data;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200419
Szymon Janc4e51eae2011-02-25 19:05:48 +0100420 BT_DBG("request for hci%u", index);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200421
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100422 if (len != sizeof(*cp))
423 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, EINVAL);
424
Szymon Janc4e51eae2011-02-25 19:05:48 +0100425 hdev = hci_dev_get(index);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200426 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100427 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, ENODEV);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200428
Andre Guedes8c156c32011-07-07 10:30:36 -0300429 hci_dev_lock_bh(hdev);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200430
431 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100432 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, ENETDOWN);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200433 goto failed;
434 }
435
Johan Hedberg2e58ef32011-11-08 20:40:15 +0200436 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
437 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100438 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, EBUSY);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200439 goto failed;
440 }
441
Johan Hedberg72a734e2010-12-30 00:38:22 +0200442 if (cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100443 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, EALREADY);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200444 goto failed;
445 }
446
Johan Hedberg2e58ef32011-11-08 20:40:15 +0200447 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -0300448 if (!cmd) {
449 err = -ENOMEM;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200450 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -0300451 }
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200452
Johan Hedberg72a734e2010-12-30 00:38:22 +0200453 if (cp->val)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200454 scan = SCAN_PAGE;
455 else
456 scan = 0;
457
458 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
459 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -0300460 mgmt_pending_remove(cmd);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200461
462failed:
Andre Guedes8c156c32011-07-07 10:30:36 -0300463 hci_dev_unlock_bh(hdev);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200464 hci_dev_put(hdev);
465
466 return err;
467}
468
Johan Hedberg744cf192011-11-08 20:40:14 +0200469static int mgmt_event(u16 event, struct hci_dev *hdev, void *data,
470 u16 data_len, struct sock *skip_sk)
Johan Hedbergc542a062011-01-26 13:11:03 +0200471{
472 struct sk_buff *skb;
473 struct mgmt_hdr *hdr;
474
475 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_ATOMIC);
476 if (!skb)
477 return -ENOMEM;
478
479 bt_cb(skb)->channel = HCI_CHANNEL_CONTROL;
480
481 hdr = (void *) skb_put(skb, sizeof(*hdr));
482 hdr->opcode = cpu_to_le16(event);
Johan Hedberg744cf192011-11-08 20:40:14 +0200483 if (hdev)
484 hdr->index = cpu_to_le16(hdev->id);
485 else
486 hdr->index = cpu_to_le16(MGMT_INDEX_NONE);
Johan Hedbergc542a062011-01-26 13:11:03 +0200487 hdr->len = cpu_to_le16(data_len);
488
Szymon Janc4e51eae2011-02-25 19:05:48 +0100489 if (data)
490 memcpy(skb_put(skb, data_len), data, data_len);
Johan Hedbergc542a062011-01-26 13:11:03 +0200491
492 hci_send_to_sock(NULL, skb, skip_sk);
493 kfree_skb(skb);
494
495 return 0;
496}
497
Johan Hedberg053f0212011-01-26 13:07:10 +0200498static int send_mode_rsp(struct sock *sk, u16 opcode, u16 index, u8 val)
499{
Johan Hedberga38528f2011-01-22 06:46:43 +0200500 struct mgmt_mode rp;
Johan Hedberg053f0212011-01-26 13:07:10 +0200501
Johan Hedberga38528f2011-01-22 06:46:43 +0200502 rp.val = val;
Johan Hedberg053f0212011-01-26 13:07:10 +0200503
Szymon Janc4e51eae2011-02-25 19:05:48 +0100504 return cmd_complete(sk, index, opcode, &rp, sizeof(rp));
Johan Hedberg053f0212011-01-26 13:07:10 +0200505}
506
Szymon Janc4e51eae2011-02-25 19:05:48 +0100507static int set_pairable(struct sock *sk, u16 index, unsigned char *data,
508 u16 len)
Johan Hedbergc542a062011-01-26 13:11:03 +0200509{
510 struct mgmt_mode *cp, ev;
511 struct hci_dev *hdev;
Johan Hedbergc542a062011-01-26 13:11:03 +0200512 int err;
513
514 cp = (void *) data;
Johan Hedbergc542a062011-01-26 13:11:03 +0200515
Szymon Janc4e51eae2011-02-25 19:05:48 +0100516 BT_DBG("request for hci%u", index);
Johan Hedbergc542a062011-01-26 13:11:03 +0200517
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100518 if (len != sizeof(*cp))
519 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE, EINVAL);
520
Szymon Janc4e51eae2011-02-25 19:05:48 +0100521 hdev = hci_dev_get(index);
Johan Hedbergc542a062011-01-26 13:11:03 +0200522 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100523 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE, ENODEV);
Johan Hedbergc542a062011-01-26 13:11:03 +0200524
Andre Guedes8c156c32011-07-07 10:30:36 -0300525 hci_dev_lock_bh(hdev);
Johan Hedbergc542a062011-01-26 13:11:03 +0200526
527 if (cp->val)
528 set_bit(HCI_PAIRABLE, &hdev->flags);
529 else
530 clear_bit(HCI_PAIRABLE, &hdev->flags);
531
Szymon Janc4e51eae2011-02-25 19:05:48 +0100532 err = send_mode_rsp(sk, MGMT_OP_SET_PAIRABLE, index, cp->val);
Johan Hedbergc542a062011-01-26 13:11:03 +0200533 if (err < 0)
534 goto failed;
535
Johan Hedbergc542a062011-01-26 13:11:03 +0200536 ev.val = cp->val;
537
Johan Hedberg744cf192011-11-08 20:40:14 +0200538 err = mgmt_event(MGMT_EV_PAIRABLE, hdev, &ev, sizeof(ev), sk);
Johan Hedbergc542a062011-01-26 13:11:03 +0200539
540failed:
Andre Guedes8c156c32011-07-07 10:30:36 -0300541 hci_dev_unlock_bh(hdev);
Johan Hedbergc542a062011-01-26 13:11:03 +0200542 hci_dev_put(hdev);
543
544 return err;
545}
546
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300547#define EIR_FLAGS 0x01 /* flags */
548#define EIR_UUID16_SOME 0x02 /* 16-bit UUID, more available */
549#define EIR_UUID16_ALL 0x03 /* 16-bit UUID, all listed */
550#define EIR_UUID32_SOME 0x04 /* 32-bit UUID, more available */
551#define EIR_UUID32_ALL 0x05 /* 32-bit UUID, all listed */
552#define EIR_UUID128_SOME 0x06 /* 128-bit UUID, more available */
553#define EIR_UUID128_ALL 0x07 /* 128-bit UUID, all listed */
554#define EIR_NAME_SHORT 0x08 /* shortened local name */
555#define EIR_NAME_COMPLETE 0x09 /* complete local name */
556#define EIR_TX_POWER 0x0A /* transmit power level */
557#define EIR_DEVICE_ID 0x10 /* device ID */
558
559#define PNP_INFO_SVCLASS_ID 0x1200
560
561static u8 bluetooth_base_uuid[] = {
562 0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80,
563 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
564};
565
566static u16 get_uuid16(u8 *uuid128)
567{
568 u32 val;
569 int i;
570
571 for (i = 0; i < 12; i++) {
572 if (bluetooth_base_uuid[i] != uuid128[i])
573 return 0;
574 }
575
576 memcpy(&val, &uuid128[12], 4);
577
578 val = le32_to_cpu(val);
579 if (val > 0xffff)
580 return 0;
581
582 return (u16) val;
583}
584
585static void create_eir(struct hci_dev *hdev, u8 *data)
586{
587 u8 *ptr = data;
588 u16 eir_len = 0;
589 u16 uuid16_list[HCI_MAX_EIR_LENGTH / sizeof(u16)];
590 int i, truncated = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200591 struct bt_uuid *uuid;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300592 size_t name_len;
593
594 name_len = strlen(hdev->dev_name);
595
596 if (name_len > 0) {
597 /* EIR Data type */
598 if (name_len > 48) {
599 name_len = 48;
600 ptr[1] = EIR_NAME_SHORT;
601 } else
602 ptr[1] = EIR_NAME_COMPLETE;
603
604 /* EIR Data length */
605 ptr[0] = name_len + 1;
606
607 memcpy(ptr + 2, hdev->dev_name, name_len);
608
609 eir_len += (name_len + 2);
610 ptr += (name_len + 2);
611 }
612
613 memset(uuid16_list, 0, sizeof(uuid16_list));
614
615 /* Group all UUID16 types */
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200616 list_for_each_entry(uuid, &hdev->uuids, list) {
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300617 u16 uuid16;
618
619 uuid16 = get_uuid16(uuid->uuid);
620 if (uuid16 == 0)
621 return;
622
623 if (uuid16 < 0x1100)
624 continue;
625
626 if (uuid16 == PNP_INFO_SVCLASS_ID)
627 continue;
628
629 /* Stop if not enough space to put next UUID */
630 if (eir_len + 2 + sizeof(u16) > HCI_MAX_EIR_LENGTH) {
631 truncated = 1;
632 break;
633 }
634
635 /* Check for duplicates */
636 for (i = 0; uuid16_list[i] != 0; i++)
637 if (uuid16_list[i] == uuid16)
638 break;
639
640 if (uuid16_list[i] == 0) {
641 uuid16_list[i] = uuid16;
642 eir_len += sizeof(u16);
643 }
644 }
645
646 if (uuid16_list[0] != 0) {
647 u8 *length = ptr;
648
649 /* EIR Data type */
650 ptr[1] = truncated ? EIR_UUID16_SOME : EIR_UUID16_ALL;
651
652 ptr += 2;
653 eir_len += 2;
654
655 for (i = 0; uuid16_list[i] != 0; i++) {
656 *ptr++ = (uuid16_list[i] & 0x00ff);
657 *ptr++ = (uuid16_list[i] & 0xff00) >> 8;
658 }
659
660 /* EIR Data length */
661 *length = (i * sizeof(u16)) + 1;
662 }
663}
664
665static int update_eir(struct hci_dev *hdev)
666{
667 struct hci_cp_write_eir cp;
668
669 if (!(hdev->features[6] & LMP_EXT_INQ))
670 return 0;
671
672 if (hdev->ssp_mode == 0)
673 return 0;
674
675 if (test_bit(HCI_SERVICE_CACHE, &hdev->flags))
676 return 0;
677
678 memset(&cp, 0, sizeof(cp));
679
680 create_eir(hdev, cp.data);
681
682 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
683 return 0;
684
685 memcpy(hdev->eir, cp.data, sizeof(cp.data));
686
687 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
688}
689
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200690static u8 get_service_classes(struct hci_dev *hdev)
691{
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300692 struct bt_uuid *uuid;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200693 u8 val = 0;
694
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300695 list_for_each_entry(uuid, &hdev->uuids, list)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200696 val |= uuid->svc_hint;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200697
698 return val;
699}
700
701static int update_class(struct hci_dev *hdev)
702{
703 u8 cod[3];
704
705 BT_DBG("%s", hdev->name);
706
707 if (test_bit(HCI_SERVICE_CACHE, &hdev->flags))
708 return 0;
709
710 cod[0] = hdev->minor_class;
711 cod[1] = hdev->major_class;
712 cod[2] = get_service_classes(hdev);
713
714 if (memcmp(cod, hdev->dev_class, 3) == 0)
715 return 0;
716
717 return hci_send_cmd(hdev, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
718}
719
Szymon Janc4e51eae2011-02-25 19:05:48 +0100720static int add_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200721{
722 struct mgmt_cp_add_uuid *cp;
723 struct hci_dev *hdev;
724 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200725 int err;
726
727 cp = (void *) data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200728
Szymon Janc4e51eae2011-02-25 19:05:48 +0100729 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200730
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100731 if (len != sizeof(*cp))
732 return cmd_status(sk, index, MGMT_OP_ADD_UUID, EINVAL);
733
Szymon Janc4e51eae2011-02-25 19:05:48 +0100734 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200735 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100736 return cmd_status(sk, index, MGMT_OP_ADD_UUID, ENODEV);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200737
Andre Guedes8c156c32011-07-07 10:30:36 -0300738 hci_dev_lock_bh(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200739
740 uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC);
741 if (!uuid) {
742 err = -ENOMEM;
743 goto failed;
744 }
745
746 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200747 uuid->svc_hint = cp->svc_hint;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200748
749 list_add(&uuid->list, &hdev->uuids);
750
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200751 err = update_class(hdev);
752 if (err < 0)
753 goto failed;
754
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300755 err = update_eir(hdev);
756 if (err < 0)
757 goto failed;
758
Szymon Janc4e51eae2011-02-25 19:05:48 +0100759 err = cmd_complete(sk, index, MGMT_OP_ADD_UUID, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200760
761failed:
Andre Guedes8c156c32011-07-07 10:30:36 -0300762 hci_dev_unlock_bh(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200763 hci_dev_put(hdev);
764
765 return err;
766}
767
Szymon Janc4e51eae2011-02-25 19:05:48 +0100768static int remove_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200769{
770 struct list_head *p, *n;
Szymon Janc779cb852011-02-25 19:05:47 +0100771 struct mgmt_cp_remove_uuid *cp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200772 struct hci_dev *hdev;
773 u8 bt_uuid_any[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200774 int err, found;
775
776 cp = (void *) data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200777
Szymon Janc4e51eae2011-02-25 19:05:48 +0100778 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200779
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100780 if (len != sizeof(*cp))
781 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID, EINVAL);
782
Szymon Janc4e51eae2011-02-25 19:05:48 +0100783 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200784 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100785 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID, ENODEV);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200786
Andre Guedes8c156c32011-07-07 10:30:36 -0300787 hci_dev_lock_bh(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200788
789 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
790 err = hci_uuids_clear(hdev);
791 goto unlock;
792 }
793
794 found = 0;
795
796 list_for_each_safe(p, n, &hdev->uuids) {
797 struct bt_uuid *match = list_entry(p, struct bt_uuid, list);
798
799 if (memcmp(match->uuid, cp->uuid, 16) != 0)
800 continue;
801
802 list_del(&match->list);
803 found++;
804 }
805
806 if (found == 0) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100807 err = cmd_status(sk, index, MGMT_OP_REMOVE_UUID, ENOENT);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200808 goto unlock;
809 }
810
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200811 err = update_class(hdev);
812 if (err < 0)
813 goto unlock;
814
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300815 err = update_eir(hdev);
816 if (err < 0)
817 goto unlock;
818
Szymon Janc4e51eae2011-02-25 19:05:48 +0100819 err = cmd_complete(sk, index, MGMT_OP_REMOVE_UUID, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200820
821unlock:
Andre Guedes8c156c32011-07-07 10:30:36 -0300822 hci_dev_unlock_bh(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200823 hci_dev_put(hdev);
824
825 return err;
826}
827
Szymon Janc4e51eae2011-02-25 19:05:48 +0100828static int set_dev_class(struct sock *sk, u16 index, unsigned char *data,
829 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200830{
831 struct hci_dev *hdev;
832 struct mgmt_cp_set_dev_class *cp;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200833 int err;
834
835 cp = (void *) data;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200836
Szymon Janc4e51eae2011-02-25 19:05:48 +0100837 BT_DBG("request for hci%u", index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200838
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100839 if (len != sizeof(*cp))
840 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS, EINVAL);
841
Szymon Janc4e51eae2011-02-25 19:05:48 +0100842 hdev = hci_dev_get(index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200843 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100844 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS, ENODEV);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200845
Andre Guedes8c156c32011-07-07 10:30:36 -0300846 hci_dev_lock_bh(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200847
848 hdev->major_class = cp->major;
849 hdev->minor_class = cp->minor;
850
851 err = update_class(hdev);
852
853 if (err == 0)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100854 err = cmd_complete(sk, index, MGMT_OP_SET_DEV_CLASS, NULL, 0);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200855
Andre Guedes8c156c32011-07-07 10:30:36 -0300856 hci_dev_unlock_bh(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200857 hci_dev_put(hdev);
858
859 return err;
860}
861
Szymon Janc4e51eae2011-02-25 19:05:48 +0100862static int set_service_cache(struct sock *sk, u16 index, unsigned char *data,
863 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200864{
865 struct hci_dev *hdev;
866 struct mgmt_cp_set_service_cache *cp;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200867 int err;
868
869 cp = (void *) data;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200870
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100871 if (len != sizeof(*cp))
Szymon Jancb8534e02011-03-01 16:55:34 +0100872 return cmd_status(sk, index, MGMT_OP_SET_SERVICE_CACHE, EINVAL);
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100873
Szymon Janc4e51eae2011-02-25 19:05:48 +0100874 hdev = hci_dev_get(index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200875 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100876 return cmd_status(sk, index, MGMT_OP_SET_SERVICE_CACHE, ENODEV);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200877
Andre Guedes8c156c32011-07-07 10:30:36 -0300878 hci_dev_lock_bh(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200879
Szymon Janc4e51eae2011-02-25 19:05:48 +0100880 BT_DBG("hci%u enable %d", index, cp->enable);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200881
882 if (cp->enable) {
883 set_bit(HCI_SERVICE_CACHE, &hdev->flags);
884 err = 0;
885 } else {
886 clear_bit(HCI_SERVICE_CACHE, &hdev->flags);
887 err = update_class(hdev);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300888 if (err == 0)
889 err = update_eir(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200890 }
891
892 if (err == 0)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100893 err = cmd_complete(sk, index, MGMT_OP_SET_SERVICE_CACHE, NULL,
894 0);
Gustavo F. Padovane5b82e52011-10-15 18:03:15 -0300895 else
896 cmd_status(sk, index, MGMT_OP_SET_SERVICE_CACHE, -err);
897
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200898
Andre Guedes8c156c32011-07-07 10:30:36 -0300899 hci_dev_unlock_bh(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200900 hci_dev_put(hdev);
901
902 return err;
903}
904
Johan Hedberg86742e12011-11-07 23:13:38 +0200905static int load_link_keys(struct sock *sk, u16 index, unsigned char *data,
906 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200907{
908 struct hci_dev *hdev;
Johan Hedberg86742e12011-11-07 23:13:38 +0200909 struct mgmt_cp_load_link_keys *cp;
Szymon Janc4e51eae2011-02-25 19:05:48 +0100910 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -0300911 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200912
913 cp = (void *) data;
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100914
915 if (len < sizeof(*cp))
Johan Hedberg86742e12011-11-07 23:13:38 +0200916 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS, EINVAL);
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100917
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200918 key_count = get_unaligned_le16(&cp->key_count);
919
Johan Hedberg86742e12011-11-07 23:13:38 +0200920 expected_len = sizeof(*cp) + key_count *
921 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -0300922 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +0200923 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -0300924 len, expected_len);
Johan Hedberg86742e12011-11-07 23:13:38 +0200925 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS, EINVAL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200926 }
927
Szymon Janc4e51eae2011-02-25 19:05:48 +0100928 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200929 if (!hdev)
Johan Hedberg86742e12011-11-07 23:13:38 +0200930 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS, ENODEV);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200931
Szymon Janc4e51eae2011-02-25 19:05:48 +0100932 BT_DBG("hci%u debug_keys %u key_count %u", index, cp->debug_keys,
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200933 key_count);
934
Andre Guedes8c156c32011-07-07 10:30:36 -0300935 hci_dev_lock_bh(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200936
937 hci_link_keys_clear(hdev);
938
939 set_bit(HCI_LINK_KEYS, &hdev->flags);
940
941 if (cp->debug_keys)
942 set_bit(HCI_DEBUG_KEYS, &hdev->flags);
943 else
944 clear_bit(HCI_DEBUG_KEYS, &hdev->flags);
945
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -0300946 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +0200947 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200948
Johan Hedbergd25e28a2011-04-28 11:28:59 -0700949 hci_add_link_key(hdev, NULL, 0, &key->bdaddr, key->val, key->type,
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200950 key->pin_len);
951 }
952
Andre Guedes8c156c32011-07-07 10:30:36 -0300953 hci_dev_unlock_bh(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200954 hci_dev_put(hdev);
955
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -0300956 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200957}
958
Johan Hedberg86742e12011-11-07 23:13:38 +0200959static int remove_keys(struct sock *sk, u16 index, unsigned char *data,
960 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200961{
962 struct hci_dev *hdev;
Johan Hedberg86742e12011-11-07 23:13:38 +0200963 struct mgmt_cp_remove_keys *cp;
Johan Hedberga8a1d192011-11-10 15:54:38 +0200964 struct mgmt_rp_remove_keys rp;
965 struct hci_cp_disconnect dc;
966 struct pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200967 struct hci_conn *conn;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200968 int err;
969
970 cp = (void *) data;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200971
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100972 if (len != sizeof(*cp))
Johan Hedberg86742e12011-11-07 23:13:38 +0200973 return cmd_status(sk, index, MGMT_OP_REMOVE_KEYS, EINVAL);
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100974
Szymon Janc4e51eae2011-02-25 19:05:48 +0100975 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200976 if (!hdev)
Johan Hedberg86742e12011-11-07 23:13:38 +0200977 return cmd_status(sk, index, MGMT_OP_REMOVE_KEYS, ENODEV);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200978
Andre Guedes8c156c32011-07-07 10:30:36 -0300979 hci_dev_lock_bh(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200980
Johan Hedberga8a1d192011-11-10 15:54:38 +0200981 memset(&rp, 0, sizeof(rp));
982 bacpy(&rp.bdaddr, &cp->bdaddr);
983
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200984 err = hci_remove_link_key(hdev, &cp->bdaddr);
Johan Hedberga8a1d192011-11-10 15:54:38 +0200985 if (err < 0)
986 goto unlock;
987
988 if (!test_bit(HCI_UP, &hdev->flags) || !cp->disconnect) {
989 err = cmd_complete(sk, index, MGMT_OP_REMOVE_KEYS, &rp,
990 sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200991 goto unlock;
992 }
993
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200994 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
Johan Hedberga8a1d192011-11-10 15:54:38 +0200995 if (!conn) {
996 err = cmd_complete(sk, index, MGMT_OP_REMOVE_KEYS, &rp,
997 sizeof(rp));
998 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200999 }
1000
Johan Hedberga8a1d192011-11-10 15:54:38 +02001001 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_KEYS, hdev, cp, sizeof(*cp));
1002 if (!cmd) {
1003 err = -ENOMEM;
1004 goto unlock;
1005 }
1006
1007 put_unaligned_le16(conn->handle, &dc.handle);
1008 dc.reason = 0x13; /* Remote User Terminated Connection */
1009 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1010 if (err < 0)
1011 mgmt_pending_remove(cmd);
1012
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001013unlock:
Johan Hedberga8a1d192011-11-10 15:54:38 +02001014 if (err < 0) {
1015 rp.status = -err;
1016 err = cmd_complete(sk, index, MGMT_OP_REMOVE_KEYS, &rp,
1017 sizeof(rp));
1018 }
Andre Guedes8c156c32011-07-07 10:30:36 -03001019 hci_dev_unlock_bh(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001020 hci_dev_put(hdev);
1021
1022 return err;
1023}
1024
Szymon Janc4e51eae2011-02-25 19:05:48 +01001025static int disconnect(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02001026{
1027 struct hci_dev *hdev;
1028 struct mgmt_cp_disconnect *cp;
1029 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03001030 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001031 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001032 int err;
1033
1034 BT_DBG("");
1035
1036 cp = (void *) data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001037
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001038 if (len != sizeof(*cp))
1039 return cmd_status(sk, index, MGMT_OP_DISCONNECT, EINVAL);
1040
Szymon Janc4e51eae2011-02-25 19:05:48 +01001041 hdev = hci_dev_get(index);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001042 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001043 return cmd_status(sk, index, MGMT_OP_DISCONNECT, ENODEV);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001044
Andre Guedes8c156c32011-07-07 10:30:36 -03001045 hci_dev_lock_bh(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001046
1047 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001048 err = cmd_status(sk, index, MGMT_OP_DISCONNECT, ENETDOWN);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001049 goto failed;
1050 }
1051
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001052 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001053 err = cmd_status(sk, index, MGMT_OP_DISCONNECT, EBUSY);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001054 goto failed;
1055 }
1056
1057 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03001058 if (!conn)
1059 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->bdaddr);
1060
Johan Hedberg8962ee72011-01-20 12:40:27 +02001061 if (!conn) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001062 err = cmd_status(sk, index, MGMT_OP_DISCONNECT, ENOTCONN);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001063 goto failed;
1064 }
1065
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001066 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001067 if (!cmd) {
1068 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001069 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001070 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001071
1072 put_unaligned_le16(conn->handle, &dc.handle);
1073 dc.reason = 0x13; /* Remote User Terminated Connection */
1074
1075 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1076 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001077 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001078
1079failed:
Andre Guedes8c156c32011-07-07 10:30:36 -03001080 hci_dev_unlock_bh(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001081 hci_dev_put(hdev);
1082
1083 return err;
1084}
1085
Johan Hedberg48264f02011-11-09 13:58:58 +02001086static u8 link_to_mgmt(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02001087{
1088 switch (link_type) {
1089 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02001090 switch (addr_type) {
1091 case ADDR_LE_DEV_PUBLIC:
1092 return MGMT_ADDR_LE_PUBLIC;
1093 case ADDR_LE_DEV_RANDOM:
1094 return MGMT_ADDR_LE_RANDOM;
1095 default:
1096 return MGMT_ADDR_INVALID;
1097 }
Johan Hedberg4c659c32011-11-07 23:13:39 +02001098 case ACL_LINK:
1099 return MGMT_ADDR_BREDR;
1100 default:
1101 return MGMT_ADDR_INVALID;
1102 }
1103}
1104
Szymon Janc8ce62842011-03-01 16:55:32 +01001105static int get_connections(struct sock *sk, u16 index)
Johan Hedberg2784eb42011-01-21 13:56:35 +02001106{
Johan Hedberg2784eb42011-01-21 13:56:35 +02001107 struct mgmt_rp_get_connections *rp;
1108 struct hci_dev *hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001109 struct hci_conn *c;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001110 struct list_head *p;
Johan Hedberga38528f2011-01-22 06:46:43 +02001111 size_t rp_len;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001112 u16 count;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001113 int i, err;
1114
1115 BT_DBG("");
1116
Szymon Janc4e51eae2011-02-25 19:05:48 +01001117 hdev = hci_dev_get(index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001118 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001119 return cmd_status(sk, index, MGMT_OP_GET_CONNECTIONS, ENODEV);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001120
Andre Guedes8c156c32011-07-07 10:30:36 -03001121 hci_dev_lock_bh(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001122
1123 count = 0;
1124 list_for_each(p, &hdev->conn_hash.list) {
1125 count++;
1126 }
1127
Johan Hedberg4c659c32011-11-07 23:13:39 +02001128 rp_len = sizeof(*rp) + (count * sizeof(struct mgmt_addr_info));
Johan Hedberga38528f2011-01-22 06:46:43 +02001129 rp = kmalloc(rp_len, GFP_ATOMIC);
1130 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02001131 err = -ENOMEM;
1132 goto unlock;
1133 }
1134
Johan Hedberg2784eb42011-01-21 13:56:35 +02001135 put_unaligned_le16(count, &rp->conn_count);
1136
Johan Hedberg2784eb42011-01-21 13:56:35 +02001137 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001138 list_for_each_entry(c, &hdev->conn_hash.list, list) {
1139 bacpy(&rp->addr[i].bdaddr, &c->dst);
Johan Hedberg48264f02011-11-09 13:58:58 +02001140 rp->addr[i].type = link_to_mgmt(c->type, c->dst_type);
Johan Hedberg4c659c32011-11-07 23:13:39 +02001141 if (rp->addr[i].type == MGMT_ADDR_INVALID)
1142 continue;
1143 i++;
1144 }
1145
1146 /* Recalculate length in case of filtered SCO connections, etc */
1147 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02001148
Szymon Janc4e51eae2011-02-25 19:05:48 +01001149 err = cmd_complete(sk, index, MGMT_OP_GET_CONNECTIONS, rp, rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001150
1151unlock:
Johan Hedberga38528f2011-01-22 06:46:43 +02001152 kfree(rp);
Andre Guedes8c156c32011-07-07 10:30:36 -03001153 hci_dev_unlock_bh(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001154 hci_dev_put(hdev);
1155 return err;
1156}
1157
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001158static int send_pin_code_neg_reply(struct sock *sk, u16 index,
1159 struct hci_dev *hdev, struct mgmt_cp_pin_code_neg_reply *cp)
1160{
1161 struct pending_cmd *cmd;
1162 int err;
1163
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001164 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001165 sizeof(*cp));
1166 if (!cmd)
1167 return -ENOMEM;
1168
1169 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY, sizeof(cp->bdaddr),
1170 &cp->bdaddr);
1171 if (err < 0)
1172 mgmt_pending_remove(cmd);
1173
1174 return err;
1175}
1176
Szymon Janc4e51eae2011-02-25 19:05:48 +01001177static int pin_code_reply(struct sock *sk, u16 index, unsigned char *data,
1178 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001179{
1180 struct hci_dev *hdev;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001181 struct hci_conn *conn;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001182 struct mgmt_cp_pin_code_reply *cp;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001183 struct mgmt_cp_pin_code_neg_reply ncp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001184 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03001185 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001186 int err;
1187
1188 BT_DBG("");
1189
1190 cp = (void *) data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001191
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001192 if (len != sizeof(*cp))
1193 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, EINVAL);
1194
Szymon Janc4e51eae2011-02-25 19:05:48 +01001195 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001196 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001197 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENODEV);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001198
Andre Guedes8c156c32011-07-07 10:30:36 -03001199 hci_dev_lock_bh(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001200
1201 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001202 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENETDOWN);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001203 goto failed;
1204 }
1205
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001206 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
1207 if (!conn) {
1208 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENOTCONN);
1209 goto failed;
1210 }
1211
1212 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
1213 bacpy(&ncp.bdaddr, &cp->bdaddr);
1214
1215 BT_ERR("PIN code is not 16 bytes long");
1216
1217 err = send_pin_code_neg_reply(sk, index, hdev, &ncp);
1218 if (err >= 0)
1219 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1220 EINVAL);
1221
1222 goto failed;
1223 }
1224
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001225 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001226 if (!cmd) {
1227 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001228 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001229 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02001230
1231 bacpy(&reply.bdaddr, &cp->bdaddr);
1232 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02001233 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02001234
1235 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
1236 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001237 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001238
1239failed:
Andre Guedes8c156c32011-07-07 10:30:36 -03001240 hci_dev_unlock_bh(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001241 hci_dev_put(hdev);
1242
1243 return err;
1244}
1245
Szymon Janc4e51eae2011-02-25 19:05:48 +01001246static int pin_code_neg_reply(struct sock *sk, u16 index, unsigned char *data,
1247 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001248{
1249 struct hci_dev *hdev;
1250 struct mgmt_cp_pin_code_neg_reply *cp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001251 int err;
1252
1253 BT_DBG("");
1254
1255 cp = (void *) data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001256
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001257 if (len != sizeof(*cp))
1258 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1259 EINVAL);
1260
Szymon Janc4e51eae2011-02-25 19:05:48 +01001261 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001262 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001263 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1264 ENODEV);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001265
Andre Guedes8c156c32011-07-07 10:30:36 -03001266 hci_dev_lock_bh(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001267
1268 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001269 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1270 ENETDOWN);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001271 goto failed;
1272 }
1273
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001274 err = send_pin_code_neg_reply(sk, index, hdev, cp);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001275
1276failed:
Andre Guedes8c156c32011-07-07 10:30:36 -03001277 hci_dev_unlock_bh(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001278 hci_dev_put(hdev);
1279
1280 return err;
1281}
1282
Szymon Janc4e51eae2011-02-25 19:05:48 +01001283static int set_io_capability(struct sock *sk, u16 index, unsigned char *data,
1284 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001285{
1286 struct hci_dev *hdev;
1287 struct mgmt_cp_set_io_capability *cp;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001288
1289 BT_DBG("");
1290
1291 cp = (void *) data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001292
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001293 if (len != sizeof(*cp))
Szymon Jancb8534e02011-03-01 16:55:34 +01001294 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY, EINVAL);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001295
Szymon Janc4e51eae2011-02-25 19:05:48 +01001296 hdev = hci_dev_get(index);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001297 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001298 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY, ENODEV);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001299
Andre Guedes8c156c32011-07-07 10:30:36 -03001300 hci_dev_lock_bh(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001301
1302 hdev->io_capability = cp->io_capability;
1303
1304 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Szymon Jancb8534e02011-03-01 16:55:34 +01001305 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001306
Andre Guedes8c156c32011-07-07 10:30:36 -03001307 hci_dev_unlock_bh(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001308 hci_dev_put(hdev);
1309
Szymon Janc4e51eae2011-02-25 19:05:48 +01001310 return cmd_complete(sk, index, MGMT_OP_SET_IO_CAPABILITY, NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001311}
1312
Johan Hedberge9a416b2011-02-19 12:05:56 -03001313static inline struct pending_cmd *find_pairing(struct hci_conn *conn)
1314{
1315 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001316 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001317
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001318 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03001319 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
1320 continue;
1321
Johan Hedberge9a416b2011-02-19 12:05:56 -03001322 if (cmd->user_data != conn)
1323 continue;
1324
1325 return cmd;
1326 }
1327
1328 return NULL;
1329}
1330
1331static void pairing_complete(struct pending_cmd *cmd, u8 status)
1332{
1333 struct mgmt_rp_pair_device rp;
1334 struct hci_conn *conn = cmd->user_data;
1335
Johan 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;
1369 struct pending_cmd *cmd;
1370 u8 sec_level, auth_type;
1371 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001372 int err;
1373
1374 BT_DBG("");
1375
1376 cp = (void *) data;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001377
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001378 if (len != sizeof(*cp))
1379 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, EINVAL);
1380
Szymon Janc4e51eae2011-02-25 19:05:48 +01001381 hdev = hci_dev_get(index);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001382 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001383 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, ENODEV);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001384
Andre Guedes8c156c32011-07-07 10:30:36 -03001385 hci_dev_lock_bh(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001386
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001387 sec_level = BT_SECURITY_MEDIUM;
1388 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001389 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001390 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03001391 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001392
Johan Hedbergba4e5642011-11-11 00:07:34 +02001393 if (cp->addr.type == MGMT_ADDR_BREDR)
1394 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr, sec_level,
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001395 auth_type);
1396 else
Johan Hedbergba4e5642011-11-11 00:07:34 +02001397 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr, sec_level,
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001398 auth_type);
1399
Ville Tervo30e76272011-02-22 16:10:53 -03001400 if (IS_ERR(conn)) {
1401 err = PTR_ERR(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001402 goto unlock;
1403 }
1404
1405 if (conn->connect_cfm_cb) {
1406 hci_conn_put(conn);
Szymon Janc4e51eae2011-02-25 19:05:48 +01001407 err = cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, EBUSY);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001408 goto unlock;
1409 }
1410
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001411 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001412 if (!cmd) {
1413 err = -ENOMEM;
1414 hci_conn_put(conn);
1415 goto unlock;
1416 }
1417
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001418 /* For LE, just connecting isn't a proof that the pairing finished */
Johan Hedbergba4e5642011-11-11 00:07:34 +02001419 if (cp->addr.type == MGMT_ADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001420 conn->connect_cfm_cb = pairing_complete_cb;
1421
Johan Hedberge9a416b2011-02-19 12:05:56 -03001422 conn->security_cfm_cb = pairing_complete_cb;
1423 conn->disconn_cfm_cb = pairing_complete_cb;
1424 conn->io_capability = cp->io_cap;
1425 cmd->user_data = conn;
1426
1427 if (conn->state == BT_CONNECTED &&
1428 hci_conn_security(conn, sec_level, auth_type))
1429 pairing_complete(cmd, 0);
1430
1431 err = 0;
1432
1433unlock:
Andre Guedes8c156c32011-07-07 10:30:36 -03001434 hci_dev_unlock_bh(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001435 hci_dev_put(hdev);
1436
1437 return err;
1438}
1439
Szymon Janc4e51eae2011-02-25 19:05:48 +01001440static int user_confirm_reply(struct sock *sk, u16 index, unsigned char *data,
1441 u16 len, int success)
Johan Hedberga5c29682011-02-19 12:05:57 -03001442{
1443 struct mgmt_cp_user_confirm_reply *cp = (void *) data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001444 u16 mgmt_op, hci_op;
Johan Hedberga5c29682011-02-19 12:05:57 -03001445 struct pending_cmd *cmd;
1446 struct hci_dev *hdev;
1447 int err;
1448
1449 BT_DBG("");
1450
Johan Hedberga5c29682011-02-19 12:05:57 -03001451 if (success) {
1452 mgmt_op = MGMT_OP_USER_CONFIRM_REPLY;
1453 hci_op = HCI_OP_USER_CONFIRM_REPLY;
1454 } else {
1455 mgmt_op = MGMT_OP_USER_CONFIRM_NEG_REPLY;
1456 hci_op = HCI_OP_USER_CONFIRM_NEG_REPLY;
1457 }
1458
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001459 if (len != sizeof(*cp))
1460 return cmd_status(sk, index, mgmt_op, EINVAL);
1461
Szymon Janc4e51eae2011-02-25 19:05:48 +01001462 hdev = hci_dev_get(index);
Johan Hedberga5c29682011-02-19 12:05:57 -03001463 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001464 return cmd_status(sk, index, mgmt_op, ENODEV);
Johan Hedberga5c29682011-02-19 12:05:57 -03001465
Andre Guedes8c156c32011-07-07 10:30:36 -03001466 hci_dev_lock_bh(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02001467
Johan Hedberga5c29682011-02-19 12:05:57 -03001468 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001469 err = cmd_status(sk, index, mgmt_op, ENETDOWN);
Johan Hedberga5c29682011-02-19 12:05:57 -03001470 goto failed;
1471 }
1472
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001473 cmd = mgmt_pending_add(sk, mgmt_op, hdev, data, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03001474 if (!cmd) {
1475 err = -ENOMEM;
1476 goto failed;
1477 }
1478
1479 err = hci_send_cmd(hdev, hci_op, sizeof(cp->bdaddr), &cp->bdaddr);
Johan Hedberga664b5b2011-02-19 12:06:02 -03001480 if (err < 0)
1481 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03001482
1483failed:
Andre Guedes8c156c32011-07-07 10:30:36 -03001484 hci_dev_unlock_bh(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03001485 hci_dev_put(hdev);
1486
1487 return err;
1488}
1489
Johan Hedbergb312b1612011-03-16 14:29:37 +02001490static int set_local_name(struct sock *sk, u16 index, unsigned char *data,
1491 u16 len)
1492{
1493 struct mgmt_cp_set_local_name *mgmt_cp = (void *) data;
1494 struct hci_cp_write_local_name hci_cp;
1495 struct hci_dev *hdev;
1496 struct pending_cmd *cmd;
1497 int err;
1498
1499 BT_DBG("");
1500
1501 if (len != sizeof(*mgmt_cp))
1502 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, EINVAL);
1503
1504 hdev = hci_dev_get(index);
1505 if (!hdev)
1506 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, ENODEV);
1507
Andre Guedes8c156c32011-07-07 10:30:36 -03001508 hci_dev_lock_bh(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001509
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001510 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001511 if (!cmd) {
1512 err = -ENOMEM;
1513 goto failed;
1514 }
1515
1516 memcpy(hci_cp.name, mgmt_cp->name, sizeof(hci_cp.name));
1517 err = hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(hci_cp),
1518 &hci_cp);
1519 if (err < 0)
1520 mgmt_pending_remove(cmd);
1521
1522failed:
Andre Guedes8c156c32011-07-07 10:30:36 -03001523 hci_dev_unlock_bh(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001524 hci_dev_put(hdev);
1525
1526 return err;
1527}
1528
Szymon Jancc35938b2011-03-22 13:12:21 +01001529static int read_local_oob_data(struct sock *sk, u16 index)
1530{
1531 struct hci_dev *hdev;
1532 struct pending_cmd *cmd;
1533 int err;
1534
1535 BT_DBG("hci%u", index);
1536
1537 hdev = hci_dev_get(index);
1538 if (!hdev)
1539 return cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
1540 ENODEV);
1541
Andre Guedes8c156c32011-07-07 10:30:36 -03001542 hci_dev_lock_bh(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01001543
1544 if (!test_bit(HCI_UP, &hdev->flags)) {
1545 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
1546 ENETDOWN);
1547 goto unlock;
1548 }
1549
1550 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
1551 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
1552 EOPNOTSUPP);
1553 goto unlock;
1554 }
1555
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001556 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Szymon Jancc35938b2011-03-22 13:12:21 +01001557 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA, EBUSY);
1558 goto unlock;
1559 }
1560
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001561 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01001562 if (!cmd) {
1563 err = -ENOMEM;
1564 goto unlock;
1565 }
1566
1567 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
1568 if (err < 0)
1569 mgmt_pending_remove(cmd);
1570
1571unlock:
Andre Guedes8c156c32011-07-07 10:30:36 -03001572 hci_dev_unlock_bh(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01001573 hci_dev_put(hdev);
1574
1575 return err;
1576}
1577
Szymon Janc2763eda2011-03-22 13:12:22 +01001578static int add_remote_oob_data(struct sock *sk, u16 index, unsigned char *data,
1579 u16 len)
1580{
1581 struct hci_dev *hdev;
1582 struct mgmt_cp_add_remote_oob_data *cp = (void *) data;
1583 int err;
1584
1585 BT_DBG("hci%u ", index);
1586
1587 if (len != sizeof(*cp))
1588 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
1589 EINVAL);
1590
1591 hdev = hci_dev_get(index);
1592 if (!hdev)
1593 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
1594 ENODEV);
1595
Andre Guedes8c156c32011-07-07 10:30:36 -03001596 hci_dev_lock_bh(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001597
1598 err = hci_add_remote_oob_data(hdev, &cp->bdaddr, cp->hash,
1599 cp->randomizer);
1600 if (err < 0)
1601 err = cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, -err);
1602 else
1603 err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, NULL,
1604 0);
1605
Andre Guedes8c156c32011-07-07 10:30:36 -03001606 hci_dev_unlock_bh(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001607 hci_dev_put(hdev);
1608
1609 return err;
1610}
1611
1612static int remove_remote_oob_data(struct sock *sk, u16 index,
1613 unsigned char *data, u16 len)
1614{
1615 struct hci_dev *hdev;
1616 struct mgmt_cp_remove_remote_oob_data *cp = (void *) data;
1617 int err;
1618
1619 BT_DBG("hci%u ", index);
1620
1621 if (len != sizeof(*cp))
1622 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
1623 EINVAL);
1624
1625 hdev = hci_dev_get(index);
1626 if (!hdev)
1627 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
1628 ENODEV);
1629
Andre Guedes8c156c32011-07-07 10:30:36 -03001630 hci_dev_lock_bh(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001631
1632 err = hci_remove_remote_oob_data(hdev, &cp->bdaddr);
1633 if (err < 0)
1634 err = cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
1635 -err);
1636 else
1637 err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
1638 NULL, 0);
1639
Andre Guedes8c156c32011-07-07 10:30:36 -03001640 hci_dev_unlock_bh(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001641 hci_dev_put(hdev);
1642
1643 return err;
1644}
1645
Johan Hedberg14a53662011-04-27 10:29:56 -04001646static int start_discovery(struct sock *sk, u16 index)
1647{
Johan Hedberg14a53662011-04-27 10:29:56 -04001648 struct pending_cmd *cmd;
1649 struct hci_dev *hdev;
1650 int err;
1651
1652 BT_DBG("hci%u", index);
1653
1654 hdev = hci_dev_get(index);
1655 if (!hdev)
1656 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY, ENODEV);
1657
1658 hci_dev_lock_bh(hdev);
1659
Johan Hedbergbd2d1332011-11-07 23:13:37 +02001660 if (!test_bit(HCI_UP, &hdev->flags)) {
1661 err = cmd_status(sk, index, MGMT_OP_START_DISCOVERY, ENETDOWN);
1662 goto failed;
1663 }
1664
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001665 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04001666 if (!cmd) {
1667 err = -ENOMEM;
1668 goto failed;
1669 }
1670
Andre Guedes2519a1f2011-11-07 11:45:24 -03001671 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
Johan Hedberg14a53662011-04-27 10:29:56 -04001672 if (err < 0)
1673 mgmt_pending_remove(cmd);
1674
1675failed:
1676 hci_dev_unlock_bh(hdev);
1677 hci_dev_put(hdev);
1678
1679 return err;
1680}
1681
1682static int stop_discovery(struct sock *sk, u16 index)
1683{
1684 struct hci_dev *hdev;
1685 struct pending_cmd *cmd;
1686 int err;
1687
1688 BT_DBG("hci%u", index);
1689
1690 hdev = hci_dev_get(index);
1691 if (!hdev)
1692 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY, ENODEV);
1693
1694 hci_dev_lock_bh(hdev);
1695
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001696 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04001697 if (!cmd) {
1698 err = -ENOMEM;
1699 goto failed;
1700 }
1701
Andre Guedes023d50492011-11-04 14:16:52 -03001702 err = hci_cancel_inquiry(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04001703 if (err < 0)
1704 mgmt_pending_remove(cmd);
1705
1706failed:
1707 hci_dev_unlock_bh(hdev);
1708 hci_dev_put(hdev);
1709
1710 return err;
1711}
1712
Antti Julku7fbec222011-06-15 12:01:15 +03001713static int block_device(struct sock *sk, u16 index, unsigned char *data,
1714 u16 len)
1715{
1716 struct hci_dev *hdev;
Antti Julku5e762442011-08-25 16:48:02 +03001717 struct mgmt_cp_block_device *cp = (void *) data;
Antti Julku7fbec222011-06-15 12:01:15 +03001718 int err;
1719
1720 BT_DBG("hci%u", index);
1721
Antti Julku7fbec222011-06-15 12:01:15 +03001722 if (len != sizeof(*cp))
1723 return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
1724 EINVAL);
1725
1726 hdev = hci_dev_get(index);
1727 if (!hdev)
1728 return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
1729 ENODEV);
1730
Antti Julku5e762442011-08-25 16:48:02 +03001731 hci_dev_lock_bh(hdev);
1732
Antti Julku7fbec222011-06-15 12:01:15 +03001733 err = hci_blacklist_add(hdev, &cp->bdaddr);
Antti Julku7fbec222011-06-15 12:01:15 +03001734 if (err < 0)
1735 err = cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE, -err);
1736 else
1737 err = cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE,
1738 NULL, 0);
Antti Julku5e762442011-08-25 16:48:02 +03001739
Antti Julku5e762442011-08-25 16:48:02 +03001740 hci_dev_unlock_bh(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03001741 hci_dev_put(hdev);
1742
1743 return err;
1744}
1745
1746static int unblock_device(struct sock *sk, u16 index, unsigned char *data,
1747 u16 len)
1748{
1749 struct hci_dev *hdev;
Antti Julku5e762442011-08-25 16:48:02 +03001750 struct mgmt_cp_unblock_device *cp = (void *) data;
Antti Julku7fbec222011-06-15 12:01:15 +03001751 int err;
1752
1753 BT_DBG("hci%u", index);
1754
Antti Julku7fbec222011-06-15 12:01:15 +03001755 if (len != sizeof(*cp))
1756 return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
1757 EINVAL);
1758
1759 hdev = hci_dev_get(index);
1760 if (!hdev)
1761 return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
1762 ENODEV);
1763
Antti Julku5e762442011-08-25 16:48:02 +03001764 hci_dev_lock_bh(hdev);
1765
Antti Julku7fbec222011-06-15 12:01:15 +03001766 err = hci_blacklist_del(hdev, &cp->bdaddr);
1767
1768 if (err < 0)
1769 err = cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE, -err);
1770 else
1771 err = cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE,
1772 NULL, 0);
Antti Julku5e762442011-08-25 16:48:02 +03001773
Antti Julku5e762442011-08-25 16:48:02 +03001774 hci_dev_unlock_bh(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03001775 hci_dev_put(hdev);
1776
1777 return err;
1778}
1779
Antti Julkuf6422ec2011-06-22 13:11:56 +03001780static int set_fast_connectable(struct sock *sk, u16 index,
1781 unsigned char *data, u16 len)
1782{
1783 struct hci_dev *hdev;
1784 struct mgmt_cp_set_fast_connectable *cp = (void *) data;
1785 struct hci_cp_write_page_scan_activity acp;
1786 u8 type;
1787 int err;
1788
1789 BT_DBG("hci%u", index);
1790
1791 if (len != sizeof(*cp))
1792 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
1793 EINVAL);
1794
1795 hdev = hci_dev_get(index);
1796 if (!hdev)
1797 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
1798 ENODEV);
1799
1800 hci_dev_lock(hdev);
1801
1802 if (cp->enable) {
1803 type = PAGE_SCAN_TYPE_INTERLACED;
1804 acp.interval = 0x0024; /* 22.5 msec page scan interval */
1805 } else {
1806 type = PAGE_SCAN_TYPE_STANDARD; /* default */
1807 acp.interval = 0x0800; /* default 1.28 sec page scan */
1808 }
1809
1810 acp.window = 0x0012; /* default 11.25 msec page scan window */
1811
1812 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
1813 sizeof(acp), &acp);
1814 if (err < 0) {
1815 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
1816 -err);
1817 goto done;
1818 }
1819
1820 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
1821 if (err < 0) {
1822 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
1823 -err);
1824 goto done;
1825 }
1826
1827 err = cmd_complete(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
1828 NULL, 0);
1829done:
1830 hci_dev_unlock(hdev);
1831 hci_dev_put(hdev);
1832
1833 return err;
1834}
1835
Johan Hedberg03811012010-12-08 00:21:06 +02001836int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
1837{
1838 unsigned char *buf;
1839 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001840 u16 opcode, index, len;
Johan Hedberg03811012010-12-08 00:21:06 +02001841 int err;
1842
1843 BT_DBG("got %zu bytes", msglen);
1844
1845 if (msglen < sizeof(*hdr))
1846 return -EINVAL;
1847
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03001848 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02001849 if (!buf)
1850 return -ENOMEM;
1851
1852 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
1853 err = -EFAULT;
1854 goto done;
1855 }
1856
1857 hdr = (struct mgmt_hdr *) buf;
1858 opcode = get_unaligned_le16(&hdr->opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01001859 index = get_unaligned_le16(&hdr->index);
Johan Hedberg03811012010-12-08 00:21:06 +02001860 len = get_unaligned_le16(&hdr->len);
1861
1862 if (len != msglen - sizeof(*hdr)) {
1863 err = -EINVAL;
1864 goto done;
1865 }
1866
1867 switch (opcode) {
Johan Hedberg02d98122010-12-13 21:07:04 +02001868 case MGMT_OP_READ_VERSION:
1869 err = read_version(sk);
1870 break;
Johan Hedbergfaba42e2010-12-13 21:07:05 +02001871 case MGMT_OP_READ_INDEX_LIST:
1872 err = read_index_list(sk);
1873 break;
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001874 case MGMT_OP_READ_INFO:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001875 err = read_controller_info(sk, index);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001876 break;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001877 case MGMT_OP_SET_POWERED:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001878 err = set_powered(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001879 break;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001880 case MGMT_OP_SET_DISCOVERABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001881 err = set_discoverable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001882 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001883 case MGMT_OP_SET_CONNECTABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001884 err = set_connectable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001885 break;
Johan Hedbergc542a062011-01-26 13:11:03 +02001886 case MGMT_OP_SET_PAIRABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001887 err = set_pairable(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergc542a062011-01-26 13:11:03 +02001888 break;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001889 case MGMT_OP_ADD_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001890 err = add_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001891 break;
1892 case MGMT_OP_REMOVE_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001893 err = remove_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001894 break;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001895 case MGMT_OP_SET_DEV_CLASS:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001896 err = set_dev_class(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001897 break;
1898 case MGMT_OP_SET_SERVICE_CACHE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001899 err = set_service_cache(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001900 break;
Johan Hedberg86742e12011-11-07 23:13:38 +02001901 case MGMT_OP_LOAD_LINK_KEYS:
1902 err = load_link_keys(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001903 break;
Johan Hedberg86742e12011-11-07 23:13:38 +02001904 case MGMT_OP_REMOVE_KEYS:
1905 err = remove_keys(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001906 break;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001907 case MGMT_OP_DISCONNECT:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001908 err = disconnect(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001909 break;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001910 case MGMT_OP_GET_CONNECTIONS:
Szymon Janc8ce62842011-03-01 16:55:32 +01001911 err = get_connections(sk, index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001912 break;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001913 case MGMT_OP_PIN_CODE_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001914 err = pin_code_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001915 break;
1916 case MGMT_OP_PIN_CODE_NEG_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001917 err = pin_code_neg_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001918 break;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001919 case MGMT_OP_SET_IO_CAPABILITY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001920 err = set_io_capability(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001921 break;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001922 case MGMT_OP_PAIR_DEVICE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001923 err = pair_device(sk, index, buf + sizeof(*hdr), len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001924 break;
Johan Hedberga5c29682011-02-19 12:05:57 -03001925 case MGMT_OP_USER_CONFIRM_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001926 err = user_confirm_reply(sk, index, buf + sizeof(*hdr), len, 1);
Johan Hedberga5c29682011-02-19 12:05:57 -03001927 break;
1928 case MGMT_OP_USER_CONFIRM_NEG_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001929 err = user_confirm_reply(sk, index, buf + sizeof(*hdr), len, 0);
Johan Hedberga5c29682011-02-19 12:05:57 -03001930 break;
Johan Hedbergb312b1612011-03-16 14:29:37 +02001931 case MGMT_OP_SET_LOCAL_NAME:
1932 err = set_local_name(sk, index, buf + sizeof(*hdr), len);
1933 break;
Szymon Jancc35938b2011-03-22 13:12:21 +01001934 case MGMT_OP_READ_LOCAL_OOB_DATA:
1935 err = read_local_oob_data(sk, index);
1936 break;
Szymon Janc2763eda2011-03-22 13:12:22 +01001937 case MGMT_OP_ADD_REMOTE_OOB_DATA:
1938 err = add_remote_oob_data(sk, index, buf + sizeof(*hdr), len);
1939 break;
1940 case MGMT_OP_REMOVE_REMOTE_OOB_DATA:
1941 err = remove_remote_oob_data(sk, index, buf + sizeof(*hdr),
1942 len);
1943 break;
Johan Hedberg14a53662011-04-27 10:29:56 -04001944 case MGMT_OP_START_DISCOVERY:
1945 err = start_discovery(sk, index);
1946 break;
1947 case MGMT_OP_STOP_DISCOVERY:
1948 err = stop_discovery(sk, index);
1949 break;
Antti Julku7fbec222011-06-15 12:01:15 +03001950 case MGMT_OP_BLOCK_DEVICE:
1951 err = block_device(sk, index, buf + sizeof(*hdr), len);
1952 break;
1953 case MGMT_OP_UNBLOCK_DEVICE:
1954 err = unblock_device(sk, index, buf + sizeof(*hdr), len);
1955 break;
Antti Julkuf6422ec2011-06-22 13:11:56 +03001956 case MGMT_OP_SET_FAST_CONNECTABLE:
1957 err = set_fast_connectable(sk, index, buf + sizeof(*hdr),
1958 len);
1959 break;
Johan Hedberg03811012010-12-08 00:21:06 +02001960 default:
1961 BT_DBG("Unknown op %u", opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01001962 err = cmd_status(sk, index, opcode, 0x01);
Johan Hedberg03811012010-12-08 00:21:06 +02001963 break;
1964 }
1965
Johan Hedberge41d8b42010-12-13 21:07:03 +02001966 if (err < 0)
1967 goto done;
1968
Johan Hedberg03811012010-12-08 00:21:06 +02001969 err = msglen;
1970
1971done:
1972 kfree(buf);
1973 return err;
1974}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001975
Johan Hedbergb24752f2011-11-03 14:40:33 +02001976static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
1977{
1978 u8 *status = data;
1979
1980 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
1981 mgmt_pending_remove(cmd);
1982}
1983
Johan Hedberg744cf192011-11-08 20:40:14 +02001984int mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001985{
Johan Hedberg744cf192011-11-08 20:40:14 +02001986 return mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001987}
1988
Johan Hedberg744cf192011-11-08 20:40:14 +02001989int mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001990{
Johan Hedbergb24752f2011-11-03 14:40:33 +02001991 u8 status = ENODEV;
1992
Johan Hedberg744cf192011-11-08 20:40:14 +02001993 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02001994
Johan Hedberg744cf192011-11-08 20:40:14 +02001995 return mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001996}
1997
Johan Hedberg73f22f62010-12-29 16:00:25 +02001998struct cmd_lookup {
Johan Hedberg72a734e2010-12-30 00:38:22 +02001999 u8 val;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002000 struct sock *sk;
2001};
2002
Johan Hedberg72a734e2010-12-30 00:38:22 +02002003static void mode_rsp(struct pending_cmd *cmd, void *data)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002004{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01002005 struct mgmt_mode *cp = cmd->param;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002006 struct cmd_lookup *match = data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002007
Johan Hedberg72a734e2010-12-30 00:38:22 +02002008 if (cp->val != match->val)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002009 return;
2010
Johan Hedberg053f0212011-01-26 13:07:10 +02002011 send_mode_rsp(cmd->sk, cmd->opcode, cmd->index, cp->val);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002012
2013 list_del(&cmd->list);
2014
2015 if (match->sk == NULL) {
2016 match->sk = cmd->sk;
2017 sock_hold(match->sk);
2018 }
2019
2020 mgmt_pending_free(cmd);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002021}
Johan Hedberg5add6af2010-12-16 10:00:37 +02002022
Johan Hedberg744cf192011-11-08 20:40:14 +02002023int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg5add6af2010-12-16 10:00:37 +02002024{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002025 struct mgmt_mode ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002026 struct cmd_lookup match = { powered, NULL };
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002027 int ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002028
Johan Hedberg744cf192011-11-08 20:40:14 +02002029 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, mode_rsp, &match);
Johan Hedberg5add6af2010-12-16 10:00:37 +02002030
Johan Hedbergb24752f2011-11-03 14:40:33 +02002031 if (!powered) {
2032 u8 status = ENETDOWN;
Johan Hedberg744cf192011-11-08 20:40:14 +02002033 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002034 }
2035
Johan Hedberg72a734e2010-12-30 00:38:22 +02002036 ev.val = powered;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002037
Johan Hedberg744cf192011-11-08 20:40:14 +02002038 ret = mgmt_event(MGMT_EV_POWERED, hdev, &ev, sizeof(ev), match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002039
2040 if (match.sk)
2041 sock_put(match.sk);
2042
2043 return ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002044}
Johan Hedberg73f22f62010-12-29 16:00:25 +02002045
Johan Hedberg744cf192011-11-08 20:40:14 +02002046int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg73f22f62010-12-29 16:00:25 +02002047{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002048 struct mgmt_mode ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002049 struct cmd_lookup match = { discoverable, NULL };
2050 int ret;
2051
Johan Hedberg744cf192011-11-08 20:40:14 +02002052 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, mode_rsp, &match);
Johan Hedberg72a734e2010-12-30 00:38:22 +02002053
Johan Hedberg72a734e2010-12-30 00:38:22 +02002054 ev.val = discoverable;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002055
Johan Hedberg744cf192011-11-08 20:40:14 +02002056 ret = mgmt_event(MGMT_EV_DISCOVERABLE, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01002057 match.sk);
Johan Hedberg73f22f62010-12-29 16:00:25 +02002058
2059 if (match.sk)
2060 sock_put(match.sk);
2061
2062 return ret;
2063}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002064
Johan Hedberg744cf192011-11-08 20:40:14 +02002065int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002066{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002067 struct mgmt_mode ev;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002068 struct cmd_lookup match = { connectable, NULL };
2069 int ret;
2070
Johan Hedberg744cf192011-11-08 20:40:14 +02002071 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev, mode_rsp, &match);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002072
Johan Hedberg72a734e2010-12-30 00:38:22 +02002073 ev.val = connectable;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002074
Johan Hedberg744cf192011-11-08 20:40:14 +02002075 ret = mgmt_event(MGMT_EV_CONNECTABLE, hdev, &ev, sizeof(ev), match.sk);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002076
2077 if (match.sk)
2078 sock_put(match.sk);
2079
2080 return ret;
2081}
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002082
Johan Hedberg744cf192011-11-08 20:40:14 +02002083int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002084{
2085 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02002086 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002087 cmd_status_rsp, &status);
2088
2089 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02002090 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002091 cmd_status_rsp, &status);
2092
2093 return 0;
2094}
2095
Johan Hedberg744cf192011-11-08 20:40:14 +02002096int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
2097 u8 persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002098{
Johan Hedberg86742e12011-11-07 23:13:38 +02002099 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002100
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002101 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002102
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002103 ev.store_hint = persistent;
2104 bacpy(&ev.key.bdaddr, &key->bdaddr);
2105 ev.key.type = key->type;
2106 memcpy(ev.key.val, key->val, 16);
2107 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002108
Johan Hedberg744cf192011-11-08 20:40:14 +02002109 return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002110}
Johan Hedbergf7520542011-01-20 12:34:39 +02002111
Johan Hedberg48264f02011-11-09 13:58:58 +02002112int mgmt_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
2113 u8 addr_type)
Johan Hedbergf7520542011-01-20 12:34:39 +02002114{
Johan Hedberg4c659c32011-11-07 23:13:39 +02002115 struct mgmt_addr_info ev;
Johan Hedbergf7520542011-01-20 12:34:39 +02002116
Johan Hedbergf7520542011-01-20 12:34:39 +02002117 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02002118 ev.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02002119
Johan Hedberg744cf192011-11-08 20:40:14 +02002120 return mgmt_event(MGMT_EV_CONNECTED, hdev, &ev, sizeof(ev), NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02002121}
2122
Johan Hedberg8962ee72011-01-20 12:40:27 +02002123static void disconnect_rsp(struct pending_cmd *cmd, void *data)
2124{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01002125 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002126 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02002127 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002128
Johan Hedberga38528f2011-01-22 06:46:43 +02002129 bacpy(&rp.bdaddr, &cp->bdaddr);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02002130 rp.status = 0;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002131
Szymon Janc4e51eae2011-02-25 19:05:48 +01002132 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002133
2134 *sk = cmd->sk;
2135 sock_hold(*sk);
2136
Johan Hedberga664b5b2011-02-19 12:06:02 -03002137 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002138}
2139
Johan Hedberga8a1d192011-11-10 15:54:38 +02002140static void remove_keys_rsp(struct pending_cmd *cmd, void *data)
2141{
2142 u8 *status = data;
2143 struct mgmt_cp_remove_keys *cp = cmd->param;
2144 struct mgmt_rp_remove_keys rp;
2145
2146 memset(&rp, 0, sizeof(rp));
2147 bacpy(&rp.bdaddr, &cp->bdaddr);
2148 if (status != NULL)
2149 rp.status = *status;
2150
2151 cmd_complete(cmd->sk, cmd->index, MGMT_OP_REMOVE_KEYS, &rp,
2152 sizeof(rp));
2153
2154 mgmt_pending_remove(cmd);
2155}
2156
Johan Hedberg48264f02011-11-09 13:58:58 +02002157int mgmt_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
2158 u8 addr_type)
Johan Hedbergf7520542011-01-20 12:34:39 +02002159{
Johan Hedberg4c659c32011-11-07 23:13:39 +02002160 struct mgmt_addr_info ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002161 struct sock *sk = NULL;
2162 int err;
2163
Johan Hedberg744cf192011-11-08 20:40:14 +02002164 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02002165
Johan Hedbergf7520542011-01-20 12:34:39 +02002166 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02002167 ev.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02002168
Johan Hedberg744cf192011-11-08 20:40:14 +02002169 err = mgmt_event(MGMT_EV_DISCONNECTED, hdev, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002170
2171 if (sk)
2172 sock_put(sk);
2173
Johan Hedberga8a1d192011-11-10 15:54:38 +02002174 mgmt_pending_foreach(MGMT_OP_REMOVE_KEYS, hdev, remove_keys_rsp, NULL);
2175
Johan Hedberg8962ee72011-01-20 12:40:27 +02002176 return err;
2177}
2178
Johan Hedberg37d9ef72011-11-10 15:54:39 +02002179int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02002180{
2181 struct pending_cmd *cmd;
2182 int err;
2183
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002184 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002185 if (!cmd)
2186 return -ENOENT;
2187
Johan Hedberg37d9ef72011-11-10 15:54:39 +02002188 if (bdaddr) {
2189 struct mgmt_rp_disconnect rp;
2190
2191 bacpy(&rp.bdaddr, bdaddr);
2192 rp.status = status;
2193
2194 err = cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
2195 &rp, sizeof(rp));
2196 } else
2197 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_DISCONNECT,
2198 status);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002199
Johan Hedberga664b5b2011-02-19 12:06:02 -03002200 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002201
2202 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02002203}
Johan Hedberg17d5c042011-01-22 06:09:08 +02002204
Johan Hedberg48264f02011-11-09 13:58:58 +02002205int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
2206 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02002207{
2208 struct mgmt_ev_connect_failed ev;
2209
Johan Hedberg4c659c32011-11-07 23:13:39 +02002210 bacpy(&ev.addr.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02002211 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedberg17d5c042011-01-22 06:09:08 +02002212 ev.status = status;
2213
Johan Hedberg744cf192011-11-08 20:40:14 +02002214 return mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02002215}
Johan Hedberg980e1a52011-01-22 06:10:07 +02002216
Johan Hedberg744cf192011-11-08 20:40:14 +02002217int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002218{
2219 struct mgmt_ev_pin_code_request ev;
2220
Johan Hedberg980e1a52011-01-22 06:10:07 +02002221 bacpy(&ev.bdaddr, bdaddr);
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02002222 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002223
Johan Hedberg744cf192011-11-08 20:40:14 +02002224 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01002225 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002226}
2227
Johan Hedberg744cf192011-11-08 20:40:14 +02002228int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
2229 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002230{
2231 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002232 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002233 int err;
2234
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002235 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002236 if (!cmd)
2237 return -ENOENT;
2238
Johan Hedbergac56fb12011-02-19 12:05:59 -03002239 bacpy(&rp.bdaddr, bdaddr);
2240 rp.status = status;
2241
Johan Hedberg744cf192011-11-08 20:40:14 +02002242 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY, &rp,
Szymon Janc4e51eae2011-02-25 19:05:48 +01002243 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002244
Johan Hedberga664b5b2011-02-19 12:06:02 -03002245 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002246
2247 return err;
2248}
2249
Johan Hedberg744cf192011-11-08 20:40:14 +02002250int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
2251 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002252{
2253 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002254 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002255 int err;
2256
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002257 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002258 if (!cmd)
2259 return -ENOENT;
2260
Johan Hedbergac56fb12011-02-19 12:05:59 -03002261 bacpy(&rp.bdaddr, bdaddr);
2262 rp.status = status;
2263
Johan Hedberg744cf192011-11-08 20:40:14 +02002264 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY, &rp,
Szymon Janc4e51eae2011-02-25 19:05:48 +01002265 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002266
Johan Hedberga664b5b2011-02-19 12:06:02 -03002267 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002268
2269 return err;
2270}
Johan Hedberga5c29682011-02-19 12:05:57 -03002271
Johan Hedberg744cf192011-11-08 20:40:14 +02002272int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
2273 __le32 value, u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03002274{
2275 struct mgmt_ev_user_confirm_request ev;
2276
Johan Hedberg744cf192011-11-08 20:40:14 +02002277 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03002278
Johan Hedberga5c29682011-02-19 12:05:57 -03002279 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07002280 ev.confirm_hint = confirm_hint;
Johan Hedberga5c29682011-02-19 12:05:57 -03002281 put_unaligned_le32(value, &ev.value);
2282
Johan Hedberg744cf192011-11-08 20:40:14 +02002283 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01002284 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03002285}
2286
Johan Hedberg744cf192011-11-08 20:40:14 +02002287static int confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
2288 u8 status, u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03002289{
2290 struct pending_cmd *cmd;
2291 struct mgmt_rp_user_confirm_reply rp;
2292 int err;
2293
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002294 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002295 if (!cmd)
2296 return -ENOENT;
2297
Johan Hedberga5c29682011-02-19 12:05:57 -03002298 bacpy(&rp.bdaddr, bdaddr);
2299 rp.status = status;
Johan Hedberg744cf192011-11-08 20:40:14 +02002300 err = cmd_complete(cmd->sk, hdev->id, opcode, &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03002301
Johan Hedberga664b5b2011-02-19 12:06:02 -03002302 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002303
2304 return err;
2305}
2306
Johan Hedberg744cf192011-11-08 20:40:14 +02002307int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
2308 u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03002309{
Johan Hedberg744cf192011-11-08 20:40:14 +02002310 return confirm_reply_complete(hdev, bdaddr, status,
Johan Hedberga5c29682011-02-19 12:05:57 -03002311 MGMT_OP_USER_CONFIRM_REPLY);
2312}
2313
Johan Hedberg744cf192011-11-08 20:40:14 +02002314int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev,
2315 bdaddr_t *bdaddr, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03002316{
Johan Hedberg744cf192011-11-08 20:40:14 +02002317 return confirm_reply_complete(hdev, bdaddr, status,
Johan Hedberga5c29682011-02-19 12:05:57 -03002318 MGMT_OP_USER_CONFIRM_NEG_REPLY);
2319}
Johan Hedberg2a611692011-02-19 12:06:00 -03002320
Johan Hedberg744cf192011-11-08 20:40:14 +02002321int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03002322{
2323 struct mgmt_ev_auth_failed ev;
2324
Johan Hedberg2a611692011-02-19 12:06:00 -03002325 bacpy(&ev.bdaddr, bdaddr);
2326 ev.status = status;
2327
Johan Hedberg744cf192011-11-08 20:40:14 +02002328 return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03002329}
Johan Hedbergb312b1612011-03-16 14:29:37 +02002330
Johan Hedberg744cf192011-11-08 20:40:14 +02002331int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02002332{
2333 struct pending_cmd *cmd;
2334 struct mgmt_cp_set_local_name ev;
2335 int err;
2336
2337 memset(&ev, 0, sizeof(ev));
2338 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
2339
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002340 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002341 if (!cmd)
2342 goto send_event;
2343
2344 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02002345 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
2346 EIO);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002347 goto failed;
2348 }
2349
Johan Hedberg744cf192011-11-08 20:40:14 +02002350 update_eir(hdev);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002351
Johan Hedberg744cf192011-11-08 20:40:14 +02002352 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, &ev,
Johan Hedbergb312b1612011-03-16 14:29:37 +02002353 sizeof(ev));
2354 if (err < 0)
2355 goto failed;
2356
2357send_event:
Johan Hedberg744cf192011-11-08 20:40:14 +02002358 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
Johan Hedbergb312b1612011-03-16 14:29:37 +02002359 cmd ? cmd->sk : NULL);
2360
2361failed:
2362 if (cmd)
2363 mgmt_pending_remove(cmd);
2364 return err;
2365}
Szymon Jancc35938b2011-03-22 13:12:21 +01002366
Johan Hedberg744cf192011-11-08 20:40:14 +02002367int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
2368 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01002369{
2370 struct pending_cmd *cmd;
2371 int err;
2372
Johan Hedberg744cf192011-11-08 20:40:14 +02002373 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01002374
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002375 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002376 if (!cmd)
2377 return -ENOENT;
2378
2379 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02002380 err = cmd_status(cmd->sk, hdev->id,
2381 MGMT_OP_READ_LOCAL_OOB_DATA, EIO);
Szymon Jancc35938b2011-03-22 13:12:21 +01002382 } else {
2383 struct mgmt_rp_read_local_oob_data rp;
2384
2385 memcpy(rp.hash, hash, sizeof(rp.hash));
2386 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
2387
Johan Hedberg744cf192011-11-08 20:40:14 +02002388 err = cmd_complete(cmd->sk, hdev->id,
2389 MGMT_OP_READ_LOCAL_OOB_DATA,
2390 &rp, sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01002391 }
2392
2393 mgmt_pending_remove(cmd);
2394
2395 return err;
2396}
Johan Hedberge17acd42011-03-30 23:57:16 +03002397
Johan Hedberg48264f02011-11-09 13:58:58 +02002398int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
2399 u8 addr_type, u8 *dev_class, s8 rssi, u8 *eir)
Johan Hedberge17acd42011-03-30 23:57:16 +03002400{
2401 struct mgmt_ev_device_found ev;
2402
2403 memset(&ev, 0, sizeof(ev));
2404
Johan Hedberg4c659c32011-11-07 23:13:39 +02002405 bacpy(&ev.addr.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02002406 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedberge17acd42011-03-30 23:57:16 +03002407 ev.rssi = rssi;
2408
2409 if (eir)
2410 memcpy(ev.eir, eir, sizeof(ev.eir));
2411
Andre Guedesf8523592011-09-09 18:56:26 -03002412 if (dev_class)
2413 memcpy(ev.dev_class, dev_class, sizeof(ev.dev_class));
2414
Johan Hedberg744cf192011-11-08 20:40:14 +02002415 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, &ev, sizeof(ev), NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03002416}
Johan Hedberga88a9652011-03-30 13:18:12 +03002417
Johan Hedberg744cf192011-11-08 20:40:14 +02002418int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *name)
Johan Hedberga88a9652011-03-30 13:18:12 +03002419{
2420 struct mgmt_ev_remote_name ev;
2421
2422 memset(&ev, 0, sizeof(ev));
2423
2424 bacpy(&ev.bdaddr, bdaddr);
2425 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
2426
Johan Hedberg744cf192011-11-08 20:40:14 +02002427 return mgmt_event(MGMT_EV_REMOTE_NAME, hdev, &ev, sizeof(ev), NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03002428}
Johan Hedberg314b2382011-04-27 10:29:57 -04002429
Andre Guedes7a135102011-11-09 17:14:25 -03002430int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
Johan Hedberg164a6e72011-11-01 17:06:44 +02002431{
2432 struct pending_cmd *cmd;
2433 int err;
2434
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002435 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02002436 if (!cmd)
2437 return -ENOENT;
2438
Johan Hedberg744cf192011-11-08 20:40:14 +02002439 err = cmd_status(cmd->sk, hdev->id, cmd->opcode, status);
Johan Hedberg164a6e72011-11-01 17:06:44 +02002440 mgmt_pending_remove(cmd);
2441
2442 return err;
2443}
2444
Andre Guedese6d465c2011-11-09 17:14:26 -03002445int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
2446{
2447 struct pending_cmd *cmd;
2448 int err;
2449
2450 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
2451 if (!cmd)
2452 return -ENOENT;
2453
2454 err = cmd_status(cmd->sk, hdev->id, cmd->opcode, status);
2455 mgmt_pending_remove(cmd);
2456
2457 return err;
2458}
2459
Johan Hedberg744cf192011-11-08 20:40:14 +02002460int mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04002461{
Johan Hedberg164a6e72011-11-01 17:06:44 +02002462 struct pending_cmd *cmd;
2463
2464 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002465 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02002466 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002467 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02002468
2469 if (cmd != NULL) {
Johan Hedberg744cf192011-11-08 20:40:14 +02002470 cmd_complete(cmd->sk, hdev->id, cmd->opcode, NULL, 0);
Johan Hedberg164a6e72011-11-01 17:06:44 +02002471 mgmt_pending_remove(cmd);
2472 }
2473
Johan Hedberg744cf192011-11-08 20:40:14 +02002474 return mgmt_event(MGMT_EV_DISCOVERING, hdev, &discovering,
Johan Hedberg314b2382011-04-27 10:29:57 -04002475 sizeof(discovering), NULL);
2476}
Antti Julku5e762442011-08-25 16:48:02 +03002477
Johan Hedberg744cf192011-11-08 20:40:14 +02002478int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr)
Antti Julku5e762442011-08-25 16:48:02 +03002479{
2480 struct pending_cmd *cmd;
2481 struct mgmt_ev_device_blocked ev;
2482
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002483 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002484
2485 bacpy(&ev.bdaddr, bdaddr);
2486
Johan Hedberg744cf192011-11-08 20:40:14 +02002487 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
2488 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03002489}
2490
Johan Hedberg744cf192011-11-08 20:40:14 +02002491int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr)
Antti Julku5e762442011-08-25 16:48:02 +03002492{
2493 struct pending_cmd *cmd;
2494 struct mgmt_ev_device_unblocked ev;
2495
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002496 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002497
2498 bacpy(&ev.bdaddr, bdaddr);
2499
Johan Hedberg744cf192011-11-08 20:40:14 +02002500 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
2501 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03002502}