blob: d23a803d69dfa8edcd6f8d4877ad8016c7e47a64 [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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-12-13 21:07:06 +020071 kfree_skb(skb);
72
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -030073 return err;
Johan Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-12-13 21:07:06 +0200202 else
Johan Hedberga38528f2011-01-22 06:46:43 +0200203 rp.sec_mode = 2;
Johan Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedberg55ed8ca12011-01-17 14:41:05 +0200964 struct hci_conn *conn;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200965 int err;
966
967 cp = (void *) data;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200968
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100969 if (len != sizeof(*cp))
Johan Hedberg86742e12011-11-07 23:13:38 +0200970 return cmd_status(sk, index, MGMT_OP_REMOVE_KEYS, EINVAL);
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100971
Szymon Janc4e51eae2011-02-25 19:05:48 +0100972 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200973 if (!hdev)
Johan Hedberg86742e12011-11-07 23:13:38 +0200974 return cmd_status(sk, index, MGMT_OP_REMOVE_KEYS, ENODEV);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200975
Andre Guedes8c156c32011-07-07 10:30:36 -0300976 hci_dev_lock_bh(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200977
978 err = hci_remove_link_key(hdev, &cp->bdaddr);
979 if (err < 0) {
Johan Hedberg86742e12011-11-07 23:13:38 +0200980 err = cmd_status(sk, index, MGMT_OP_REMOVE_KEYS, -err);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200981 goto unlock;
982 }
983
984 err = 0;
985
986 if (!test_bit(HCI_UP, &hdev->flags) || !cp->disconnect)
987 goto unlock;
988
989 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
990 if (conn) {
991 struct hci_cp_disconnect dc;
992
993 put_unaligned_le16(conn->handle, &dc.handle);
994 dc.reason = 0x13; /* Remote User Terminated Connection */
Anderson Lizardo94ac0272011-06-13 15:42:03 -0400995 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200996 }
997
998unlock:
Andre Guedes8c156c32011-07-07 10:30:36 -0300999 hci_dev_unlock_bh(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001000 hci_dev_put(hdev);
1001
1002 return err;
1003}
1004
Szymon Janc4e51eae2011-02-25 19:05:48 +01001005static int disconnect(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02001006{
1007 struct hci_dev *hdev;
1008 struct mgmt_cp_disconnect *cp;
1009 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03001010 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001011 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001012 int err;
1013
1014 BT_DBG("");
1015
1016 cp = (void *) data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001017
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001018 if (len != sizeof(*cp))
1019 return cmd_status(sk, index, MGMT_OP_DISCONNECT, EINVAL);
1020
Szymon Janc4e51eae2011-02-25 19:05:48 +01001021 hdev = hci_dev_get(index);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001022 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001023 return cmd_status(sk, index, MGMT_OP_DISCONNECT, ENODEV);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001024
Andre Guedes8c156c32011-07-07 10:30:36 -03001025 hci_dev_lock_bh(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001026
1027 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001028 err = cmd_status(sk, index, MGMT_OP_DISCONNECT, ENETDOWN);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001029 goto failed;
1030 }
1031
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001032 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001033 err = cmd_status(sk, index, MGMT_OP_DISCONNECT, EBUSY);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001034 goto failed;
1035 }
1036
1037 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03001038 if (!conn)
1039 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->bdaddr);
1040
Johan Hedberg8962ee72011-01-20 12:40:27 +02001041 if (!conn) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001042 err = cmd_status(sk, index, MGMT_OP_DISCONNECT, ENOTCONN);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001043 goto failed;
1044 }
1045
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001046 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001047 if (!cmd) {
1048 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001049 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001050 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001051
1052 put_unaligned_le16(conn->handle, &dc.handle);
1053 dc.reason = 0x13; /* Remote User Terminated Connection */
1054
1055 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1056 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001057 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001058
1059failed:
Andre Guedes8c156c32011-07-07 10:30:36 -03001060 hci_dev_unlock_bh(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001061 hci_dev_put(hdev);
1062
1063 return err;
1064}
1065
Johan Hedberg48264f02011-11-09 13:58:58 +02001066static u8 link_to_mgmt(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02001067{
1068 switch (link_type) {
1069 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02001070 switch (addr_type) {
1071 case ADDR_LE_DEV_PUBLIC:
1072 return MGMT_ADDR_LE_PUBLIC;
1073 case ADDR_LE_DEV_RANDOM:
1074 return MGMT_ADDR_LE_RANDOM;
1075 default:
1076 return MGMT_ADDR_INVALID;
1077 }
Johan Hedberg4c659c32011-11-07 23:13:39 +02001078 case ACL_LINK:
1079 return MGMT_ADDR_BREDR;
1080 default:
1081 return MGMT_ADDR_INVALID;
1082 }
1083}
1084
Szymon Janc8ce62842011-03-01 16:55:32 +01001085static int get_connections(struct sock *sk, u16 index)
Johan Hedberg2784eb42011-01-21 13:56:35 +02001086{
Johan Hedberg2784eb42011-01-21 13:56:35 +02001087 struct mgmt_rp_get_connections *rp;
1088 struct hci_dev *hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001089 struct hci_conn *c;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001090 struct list_head *p;
Johan Hedberga38528f2011-01-22 06:46:43 +02001091 size_t rp_len;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001092 u16 count;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001093 int i, err;
1094
1095 BT_DBG("");
1096
Szymon Janc4e51eae2011-02-25 19:05:48 +01001097 hdev = hci_dev_get(index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001098 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001099 return cmd_status(sk, index, MGMT_OP_GET_CONNECTIONS, ENODEV);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001100
Andre Guedes8c156c32011-07-07 10:30:36 -03001101 hci_dev_lock_bh(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001102
1103 count = 0;
1104 list_for_each(p, &hdev->conn_hash.list) {
1105 count++;
1106 }
1107
Johan Hedberg4c659c32011-11-07 23:13:39 +02001108 rp_len = sizeof(*rp) + (count * sizeof(struct mgmt_addr_info));
Johan Hedberga38528f2011-01-22 06:46:43 +02001109 rp = kmalloc(rp_len, GFP_ATOMIC);
1110 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02001111 err = -ENOMEM;
1112 goto unlock;
1113 }
1114
Johan Hedberg2784eb42011-01-21 13:56:35 +02001115 put_unaligned_le16(count, &rp->conn_count);
1116
Johan Hedberg2784eb42011-01-21 13:56:35 +02001117 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001118 list_for_each_entry(c, &hdev->conn_hash.list, list) {
1119 bacpy(&rp->addr[i].bdaddr, &c->dst);
Johan Hedberg48264f02011-11-09 13:58:58 +02001120 rp->addr[i].type = link_to_mgmt(c->type, c->dst_type);
Johan Hedberg4c659c32011-11-07 23:13:39 +02001121 if (rp->addr[i].type == MGMT_ADDR_INVALID)
1122 continue;
1123 i++;
1124 }
1125
1126 /* Recalculate length in case of filtered SCO connections, etc */
1127 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02001128
Szymon Janc4e51eae2011-02-25 19:05:48 +01001129 err = cmd_complete(sk, index, MGMT_OP_GET_CONNECTIONS, rp, rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001130
1131unlock:
Johan Hedberga38528f2011-01-22 06:46:43 +02001132 kfree(rp);
Andre Guedes8c156c32011-07-07 10:30:36 -03001133 hci_dev_unlock_bh(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001134 hci_dev_put(hdev);
1135 return err;
1136}
1137
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001138static int send_pin_code_neg_reply(struct sock *sk, u16 index,
1139 struct hci_dev *hdev, struct mgmt_cp_pin_code_neg_reply *cp)
1140{
1141 struct pending_cmd *cmd;
1142 int err;
1143
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001144 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001145 sizeof(*cp));
1146 if (!cmd)
1147 return -ENOMEM;
1148
1149 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY, sizeof(cp->bdaddr),
1150 &cp->bdaddr);
1151 if (err < 0)
1152 mgmt_pending_remove(cmd);
1153
1154 return err;
1155}
1156
Szymon Janc4e51eae2011-02-25 19:05:48 +01001157static int pin_code_reply(struct sock *sk, u16 index, unsigned char *data,
1158 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001159{
1160 struct hci_dev *hdev;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001161 struct hci_conn *conn;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001162 struct mgmt_cp_pin_code_reply *cp;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001163 struct mgmt_cp_pin_code_neg_reply ncp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001164 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03001165 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001166 int err;
1167
1168 BT_DBG("");
1169
1170 cp = (void *) data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001171
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001172 if (len != sizeof(*cp))
1173 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, EINVAL);
1174
Szymon Janc4e51eae2011-02-25 19:05:48 +01001175 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001176 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001177 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENODEV);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001178
Andre Guedes8c156c32011-07-07 10:30:36 -03001179 hci_dev_lock_bh(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001180
1181 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001182 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENETDOWN);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001183 goto failed;
1184 }
1185
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001186 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
1187 if (!conn) {
1188 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENOTCONN);
1189 goto failed;
1190 }
1191
1192 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
1193 bacpy(&ncp.bdaddr, &cp->bdaddr);
1194
1195 BT_ERR("PIN code is not 16 bytes long");
1196
1197 err = send_pin_code_neg_reply(sk, index, hdev, &ncp);
1198 if (err >= 0)
1199 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1200 EINVAL);
1201
1202 goto failed;
1203 }
1204
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001205 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001206 if (!cmd) {
1207 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001208 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001209 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02001210
1211 bacpy(&reply.bdaddr, &cp->bdaddr);
1212 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02001213 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02001214
1215 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
1216 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001217 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001218
1219failed:
Andre Guedes8c156c32011-07-07 10:30:36 -03001220 hci_dev_unlock_bh(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001221 hci_dev_put(hdev);
1222
1223 return err;
1224}
1225
Szymon Janc4e51eae2011-02-25 19:05:48 +01001226static int pin_code_neg_reply(struct sock *sk, u16 index, unsigned char *data,
1227 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001228{
1229 struct hci_dev *hdev;
1230 struct mgmt_cp_pin_code_neg_reply *cp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001231 int err;
1232
1233 BT_DBG("");
1234
1235 cp = (void *) data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001236
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001237 if (len != sizeof(*cp))
1238 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1239 EINVAL);
1240
Szymon Janc4e51eae2011-02-25 19:05:48 +01001241 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001242 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001243 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1244 ENODEV);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001245
Andre Guedes8c156c32011-07-07 10:30:36 -03001246 hci_dev_lock_bh(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001247
1248 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001249 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1250 ENETDOWN);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001251 goto failed;
1252 }
1253
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001254 err = send_pin_code_neg_reply(sk, index, hdev, cp);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001255
1256failed:
Andre Guedes8c156c32011-07-07 10:30:36 -03001257 hci_dev_unlock_bh(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001258 hci_dev_put(hdev);
1259
1260 return err;
1261}
1262
Szymon Janc4e51eae2011-02-25 19:05:48 +01001263static int set_io_capability(struct sock *sk, u16 index, unsigned char *data,
1264 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001265{
1266 struct hci_dev *hdev;
1267 struct mgmt_cp_set_io_capability *cp;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001268
1269 BT_DBG("");
1270
1271 cp = (void *) data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001272
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001273 if (len != sizeof(*cp))
Szymon Jancb8534e02011-03-01 16:55:34 +01001274 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY, EINVAL);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001275
Szymon Janc4e51eae2011-02-25 19:05:48 +01001276 hdev = hci_dev_get(index);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001277 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001278 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY, ENODEV);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001279
Andre Guedes8c156c32011-07-07 10:30:36 -03001280 hci_dev_lock_bh(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001281
1282 hdev->io_capability = cp->io_capability;
1283
1284 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Szymon Jancb8534e02011-03-01 16:55:34 +01001285 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001286
Andre Guedes8c156c32011-07-07 10:30:36 -03001287 hci_dev_unlock_bh(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001288 hci_dev_put(hdev);
1289
Szymon Janc4e51eae2011-02-25 19:05:48 +01001290 return cmd_complete(sk, index, MGMT_OP_SET_IO_CAPABILITY, NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001291}
1292
Johan Hedberge9a416b2011-02-19 12:05:56 -03001293static inline struct pending_cmd *find_pairing(struct hci_conn *conn)
1294{
1295 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001296 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001297
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001298 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03001299 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
1300 continue;
1301
Johan Hedberge9a416b2011-02-19 12:05:56 -03001302 if (cmd->user_data != conn)
1303 continue;
1304
1305 return cmd;
1306 }
1307
1308 return NULL;
1309}
1310
1311static void pairing_complete(struct pending_cmd *cmd, u8 status)
1312{
1313 struct mgmt_rp_pair_device rp;
1314 struct hci_conn *conn = cmd->user_data;
1315
Johan Hedberge9a416b2011-02-19 12:05:56 -03001316 bacpy(&rp.bdaddr, &conn->dst);
1317 rp.status = status;
1318
Szymon Janc4e51eae2011-02-25 19:05:48 +01001319 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001320
1321 /* So we don't get further callbacks for this connection */
1322 conn->connect_cfm_cb = NULL;
1323 conn->security_cfm_cb = NULL;
1324 conn->disconn_cfm_cb = NULL;
1325
1326 hci_conn_put(conn);
1327
Johan Hedberga664b5b2011-02-19 12:06:02 -03001328 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001329}
1330
1331static void pairing_complete_cb(struct hci_conn *conn, u8 status)
1332{
1333 struct pending_cmd *cmd;
Johan Hedberg56e5cb82011-11-08 20:40:16 +02001334 struct hci_dev *hdev = conn->hdev;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001335
1336 BT_DBG("status %u", status);
1337
Johan Hedberg56e5cb82011-11-08 20:40:16 +02001338 hci_dev_lock_bh(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001339
Johan Hedberg56e5cb82011-11-08 20:40:16 +02001340 cmd = find_pairing(conn);
1341 if (!cmd)
1342 BT_DBG("Unable to find a pending command");
1343 else
1344 pairing_complete(cmd, status);
1345
1346 hci_dev_unlock_bh(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001347}
1348
Szymon Janc4e51eae2011-02-25 19:05:48 +01001349static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001350{
1351 struct hci_dev *hdev;
1352 struct mgmt_cp_pair_device *cp;
1353 struct pending_cmd *cmd;
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001354 struct adv_entry *entry;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001355 u8 sec_level, auth_type;
1356 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001357 int err;
1358
1359 BT_DBG("");
1360
1361 cp = (void *) data;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001362
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001363 if (len != sizeof(*cp))
1364 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, EINVAL);
1365
Szymon Janc4e51eae2011-02-25 19:05:48 +01001366 hdev = hci_dev_get(index);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001367 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001368 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, ENODEV);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001369
Andre Guedes8c156c32011-07-07 10:30:36 -03001370 hci_dev_lock_bh(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001371
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001372 sec_level = BT_SECURITY_MEDIUM;
1373 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001374 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001375 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03001376 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001377
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001378 entry = hci_find_adv_entry(hdev, &cp->bdaddr);
1379 if (entry)
1380 conn = hci_connect(hdev, LE_LINK, &cp->bdaddr, sec_level,
1381 auth_type);
1382 else
1383 conn = hci_connect(hdev, ACL_LINK, &cp->bdaddr, sec_level,
1384 auth_type);
1385
Ville Tervo30e76272011-02-22 16:10:53 -03001386 if (IS_ERR(conn)) {
1387 err = PTR_ERR(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001388 goto unlock;
1389 }
1390
1391 if (conn->connect_cfm_cb) {
1392 hci_conn_put(conn);
Szymon Janc4e51eae2011-02-25 19:05:48 +01001393 err = cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, EBUSY);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001394 goto unlock;
1395 }
1396
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001397 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001398 if (!cmd) {
1399 err = -ENOMEM;
1400 hci_conn_put(conn);
1401 goto unlock;
1402 }
1403
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001404 /* For LE, just connecting isn't a proof that the pairing finished */
1405 if (!entry)
1406 conn->connect_cfm_cb = pairing_complete_cb;
1407
Johan Hedberge9a416b2011-02-19 12:05:56 -03001408 conn->security_cfm_cb = pairing_complete_cb;
1409 conn->disconn_cfm_cb = pairing_complete_cb;
1410 conn->io_capability = cp->io_cap;
1411 cmd->user_data = conn;
1412
1413 if (conn->state == BT_CONNECTED &&
1414 hci_conn_security(conn, sec_level, auth_type))
1415 pairing_complete(cmd, 0);
1416
1417 err = 0;
1418
1419unlock:
Andre Guedes8c156c32011-07-07 10:30:36 -03001420 hci_dev_unlock_bh(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001421 hci_dev_put(hdev);
1422
1423 return err;
1424}
1425
Szymon Janc4e51eae2011-02-25 19:05:48 +01001426static int user_confirm_reply(struct sock *sk, u16 index, unsigned char *data,
1427 u16 len, int success)
Johan Hedberga5c29682011-02-19 12:05:57 -03001428{
1429 struct mgmt_cp_user_confirm_reply *cp = (void *) data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001430 u16 mgmt_op, hci_op;
Johan Hedberga5c29682011-02-19 12:05:57 -03001431 struct pending_cmd *cmd;
1432 struct hci_dev *hdev;
1433 int err;
1434
1435 BT_DBG("");
1436
Johan Hedberga5c29682011-02-19 12:05:57 -03001437 if (success) {
1438 mgmt_op = MGMT_OP_USER_CONFIRM_REPLY;
1439 hci_op = HCI_OP_USER_CONFIRM_REPLY;
1440 } else {
1441 mgmt_op = MGMT_OP_USER_CONFIRM_NEG_REPLY;
1442 hci_op = HCI_OP_USER_CONFIRM_NEG_REPLY;
1443 }
1444
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001445 if (len != sizeof(*cp))
1446 return cmd_status(sk, index, mgmt_op, EINVAL);
1447
Szymon Janc4e51eae2011-02-25 19:05:48 +01001448 hdev = hci_dev_get(index);
Johan Hedberga5c29682011-02-19 12:05:57 -03001449 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001450 return cmd_status(sk, index, mgmt_op, ENODEV);
Johan Hedberga5c29682011-02-19 12:05:57 -03001451
Andre Guedes8c156c32011-07-07 10:30:36 -03001452 hci_dev_lock_bh(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02001453
Johan Hedberga5c29682011-02-19 12:05:57 -03001454 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001455 err = cmd_status(sk, index, mgmt_op, ENETDOWN);
Johan Hedberga5c29682011-02-19 12:05:57 -03001456 goto failed;
1457 }
1458
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001459 cmd = mgmt_pending_add(sk, mgmt_op, hdev, data, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03001460 if (!cmd) {
1461 err = -ENOMEM;
1462 goto failed;
1463 }
1464
1465 err = hci_send_cmd(hdev, hci_op, sizeof(cp->bdaddr), &cp->bdaddr);
Johan Hedberga664b5b2011-02-19 12:06:02 -03001466 if (err < 0)
1467 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03001468
1469failed:
Andre Guedes8c156c32011-07-07 10:30:36 -03001470 hci_dev_unlock_bh(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03001471 hci_dev_put(hdev);
1472
1473 return err;
1474}
1475
Johan Hedbergb312b1612011-03-16 14:29:37 +02001476static int set_local_name(struct sock *sk, u16 index, unsigned char *data,
1477 u16 len)
1478{
1479 struct mgmt_cp_set_local_name *mgmt_cp = (void *) data;
1480 struct hci_cp_write_local_name hci_cp;
1481 struct hci_dev *hdev;
1482 struct pending_cmd *cmd;
1483 int err;
1484
1485 BT_DBG("");
1486
1487 if (len != sizeof(*mgmt_cp))
1488 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, EINVAL);
1489
1490 hdev = hci_dev_get(index);
1491 if (!hdev)
1492 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, ENODEV);
1493
Andre Guedes8c156c32011-07-07 10:30:36 -03001494 hci_dev_lock_bh(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001495
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001496 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001497 if (!cmd) {
1498 err = -ENOMEM;
1499 goto failed;
1500 }
1501
1502 memcpy(hci_cp.name, mgmt_cp->name, sizeof(hci_cp.name));
1503 err = hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(hci_cp),
1504 &hci_cp);
1505 if (err < 0)
1506 mgmt_pending_remove(cmd);
1507
1508failed:
Andre Guedes8c156c32011-07-07 10:30:36 -03001509 hci_dev_unlock_bh(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001510 hci_dev_put(hdev);
1511
1512 return err;
1513}
1514
Szymon Jancc35938b2011-03-22 13:12:21 +01001515static int read_local_oob_data(struct sock *sk, u16 index)
1516{
1517 struct hci_dev *hdev;
1518 struct pending_cmd *cmd;
1519 int err;
1520
1521 BT_DBG("hci%u", index);
1522
1523 hdev = hci_dev_get(index);
1524 if (!hdev)
1525 return cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
1526 ENODEV);
1527
Andre Guedes8c156c32011-07-07 10:30:36 -03001528 hci_dev_lock_bh(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01001529
1530 if (!test_bit(HCI_UP, &hdev->flags)) {
1531 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
1532 ENETDOWN);
1533 goto unlock;
1534 }
1535
1536 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
1537 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
1538 EOPNOTSUPP);
1539 goto unlock;
1540 }
1541
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001542 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Szymon Jancc35938b2011-03-22 13:12:21 +01001543 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA, EBUSY);
1544 goto unlock;
1545 }
1546
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001547 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01001548 if (!cmd) {
1549 err = -ENOMEM;
1550 goto unlock;
1551 }
1552
1553 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
1554 if (err < 0)
1555 mgmt_pending_remove(cmd);
1556
1557unlock:
Andre Guedes8c156c32011-07-07 10:30:36 -03001558 hci_dev_unlock_bh(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01001559 hci_dev_put(hdev);
1560
1561 return err;
1562}
1563
Szymon Janc2763eda2011-03-22 13:12:22 +01001564static int add_remote_oob_data(struct sock *sk, u16 index, unsigned char *data,
1565 u16 len)
1566{
1567 struct hci_dev *hdev;
1568 struct mgmt_cp_add_remote_oob_data *cp = (void *) data;
1569 int err;
1570
1571 BT_DBG("hci%u ", index);
1572
1573 if (len != sizeof(*cp))
1574 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
1575 EINVAL);
1576
1577 hdev = hci_dev_get(index);
1578 if (!hdev)
1579 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
1580 ENODEV);
1581
Andre Guedes8c156c32011-07-07 10:30:36 -03001582 hci_dev_lock_bh(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001583
1584 err = hci_add_remote_oob_data(hdev, &cp->bdaddr, cp->hash,
1585 cp->randomizer);
1586 if (err < 0)
1587 err = cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, -err);
1588 else
1589 err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, NULL,
1590 0);
1591
Andre Guedes8c156c32011-07-07 10:30:36 -03001592 hci_dev_unlock_bh(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001593 hci_dev_put(hdev);
1594
1595 return err;
1596}
1597
1598static int remove_remote_oob_data(struct sock *sk, u16 index,
1599 unsigned char *data, u16 len)
1600{
1601 struct hci_dev *hdev;
1602 struct mgmt_cp_remove_remote_oob_data *cp = (void *) data;
1603 int err;
1604
1605 BT_DBG("hci%u ", index);
1606
1607 if (len != sizeof(*cp))
1608 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
1609 EINVAL);
1610
1611 hdev = hci_dev_get(index);
1612 if (!hdev)
1613 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
1614 ENODEV);
1615
Andre Guedes8c156c32011-07-07 10:30:36 -03001616 hci_dev_lock_bh(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001617
1618 err = hci_remove_remote_oob_data(hdev, &cp->bdaddr);
1619 if (err < 0)
1620 err = cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
1621 -err);
1622 else
1623 err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
1624 NULL, 0);
1625
Andre Guedes8c156c32011-07-07 10:30:36 -03001626 hci_dev_unlock_bh(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001627 hci_dev_put(hdev);
1628
1629 return err;
1630}
1631
Johan Hedberg14a53662011-04-27 10:29:56 -04001632static int start_discovery(struct sock *sk, u16 index)
1633{
Johan Hedberg14a53662011-04-27 10:29:56 -04001634 struct pending_cmd *cmd;
1635 struct hci_dev *hdev;
1636 int err;
1637
1638 BT_DBG("hci%u", index);
1639
1640 hdev = hci_dev_get(index);
1641 if (!hdev)
1642 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY, ENODEV);
1643
1644 hci_dev_lock_bh(hdev);
1645
Johan Hedbergbd2d1332011-11-07 23:13:37 +02001646 if (!test_bit(HCI_UP, &hdev->flags)) {
1647 err = cmd_status(sk, index, MGMT_OP_START_DISCOVERY, ENETDOWN);
1648 goto failed;
1649 }
1650
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001651 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04001652 if (!cmd) {
1653 err = -ENOMEM;
1654 goto failed;
1655 }
1656
Andre Guedes2519a1f2011-11-07 11:45:24 -03001657 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
Johan Hedberg14a53662011-04-27 10:29:56 -04001658 if (err < 0)
1659 mgmt_pending_remove(cmd);
1660
1661failed:
1662 hci_dev_unlock_bh(hdev);
1663 hci_dev_put(hdev);
1664
1665 return err;
1666}
1667
1668static int stop_discovery(struct sock *sk, u16 index)
1669{
1670 struct hci_dev *hdev;
1671 struct pending_cmd *cmd;
1672 int err;
1673
1674 BT_DBG("hci%u", index);
1675
1676 hdev = hci_dev_get(index);
1677 if (!hdev)
1678 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY, ENODEV);
1679
1680 hci_dev_lock_bh(hdev);
1681
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001682 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04001683 if (!cmd) {
1684 err = -ENOMEM;
1685 goto failed;
1686 }
1687
Andre Guedes023d50492011-11-04 14:16:52 -03001688 err = hci_cancel_inquiry(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04001689 if (err < 0)
1690 mgmt_pending_remove(cmd);
1691
1692failed:
1693 hci_dev_unlock_bh(hdev);
1694 hci_dev_put(hdev);
1695
1696 return err;
1697}
1698
Antti Julku7fbec222011-06-15 12:01:15 +03001699static int block_device(struct sock *sk, u16 index, unsigned char *data,
1700 u16 len)
1701{
1702 struct hci_dev *hdev;
Antti Julku5e762442011-08-25 16:48:02 +03001703 struct mgmt_cp_block_device *cp = (void *) data;
Antti Julku7fbec222011-06-15 12:01:15 +03001704 int err;
1705
1706 BT_DBG("hci%u", index);
1707
Antti Julku7fbec222011-06-15 12:01:15 +03001708 if (len != sizeof(*cp))
1709 return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
1710 EINVAL);
1711
1712 hdev = hci_dev_get(index);
1713 if (!hdev)
1714 return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
1715 ENODEV);
1716
Antti Julku5e762442011-08-25 16:48:02 +03001717 hci_dev_lock_bh(hdev);
1718
Antti Julku7fbec222011-06-15 12:01:15 +03001719 err = hci_blacklist_add(hdev, &cp->bdaddr);
Antti Julku7fbec222011-06-15 12:01:15 +03001720 if (err < 0)
1721 err = cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE, -err);
1722 else
1723 err = cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE,
1724 NULL, 0);
Antti Julku5e762442011-08-25 16:48:02 +03001725
Antti Julku5e762442011-08-25 16:48:02 +03001726 hci_dev_unlock_bh(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03001727 hci_dev_put(hdev);
1728
1729 return err;
1730}
1731
1732static int unblock_device(struct sock *sk, u16 index, unsigned char *data,
1733 u16 len)
1734{
1735 struct hci_dev *hdev;
Antti Julku5e762442011-08-25 16:48:02 +03001736 struct mgmt_cp_unblock_device *cp = (void *) data;
Antti Julku7fbec222011-06-15 12:01:15 +03001737 int err;
1738
1739 BT_DBG("hci%u", index);
1740
Antti Julku7fbec222011-06-15 12:01:15 +03001741 if (len != sizeof(*cp))
1742 return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
1743 EINVAL);
1744
1745 hdev = hci_dev_get(index);
1746 if (!hdev)
1747 return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
1748 ENODEV);
1749
Antti Julku5e762442011-08-25 16:48:02 +03001750 hci_dev_lock_bh(hdev);
1751
Antti Julku7fbec222011-06-15 12:01:15 +03001752 err = hci_blacklist_del(hdev, &cp->bdaddr);
1753
1754 if (err < 0)
1755 err = cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE, -err);
1756 else
1757 err = cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE,
1758 NULL, 0);
Antti Julku5e762442011-08-25 16:48:02 +03001759
Antti Julku5e762442011-08-25 16:48:02 +03001760 hci_dev_unlock_bh(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03001761 hci_dev_put(hdev);
1762
1763 return err;
1764}
1765
Antti Julkuf6422ec2011-06-22 13:11:56 +03001766static int set_fast_connectable(struct sock *sk, u16 index,
1767 unsigned char *data, u16 len)
1768{
1769 struct hci_dev *hdev;
1770 struct mgmt_cp_set_fast_connectable *cp = (void *) data;
1771 struct hci_cp_write_page_scan_activity acp;
1772 u8 type;
1773 int err;
1774
1775 BT_DBG("hci%u", index);
1776
1777 if (len != sizeof(*cp))
1778 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
1779 EINVAL);
1780
1781 hdev = hci_dev_get(index);
1782 if (!hdev)
1783 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
1784 ENODEV);
1785
1786 hci_dev_lock(hdev);
1787
1788 if (cp->enable) {
1789 type = PAGE_SCAN_TYPE_INTERLACED;
1790 acp.interval = 0x0024; /* 22.5 msec page scan interval */
1791 } else {
1792 type = PAGE_SCAN_TYPE_STANDARD; /* default */
1793 acp.interval = 0x0800; /* default 1.28 sec page scan */
1794 }
1795
1796 acp.window = 0x0012; /* default 11.25 msec page scan window */
1797
1798 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
1799 sizeof(acp), &acp);
1800 if (err < 0) {
1801 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
1802 -err);
1803 goto done;
1804 }
1805
1806 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
1807 if (err < 0) {
1808 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
1809 -err);
1810 goto done;
1811 }
1812
1813 err = cmd_complete(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
1814 NULL, 0);
1815done:
1816 hci_dev_unlock(hdev);
1817 hci_dev_put(hdev);
1818
1819 return err;
1820}
1821
Johan Hedberg03811012010-12-08 00:21:06 +02001822int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
1823{
1824 unsigned char *buf;
1825 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001826 u16 opcode, index, len;
Johan Hedberg03811012010-12-08 00:21:06 +02001827 int err;
1828
1829 BT_DBG("got %zu bytes", msglen);
1830
1831 if (msglen < sizeof(*hdr))
1832 return -EINVAL;
1833
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03001834 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02001835 if (!buf)
1836 return -ENOMEM;
1837
1838 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
1839 err = -EFAULT;
1840 goto done;
1841 }
1842
1843 hdr = (struct mgmt_hdr *) buf;
1844 opcode = get_unaligned_le16(&hdr->opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01001845 index = get_unaligned_le16(&hdr->index);
Johan Hedberg03811012010-12-08 00:21:06 +02001846 len = get_unaligned_le16(&hdr->len);
1847
1848 if (len != msglen - sizeof(*hdr)) {
1849 err = -EINVAL;
1850 goto done;
1851 }
1852
1853 switch (opcode) {
Johan Hedberg02d98122010-12-13 21:07:04 +02001854 case MGMT_OP_READ_VERSION:
1855 err = read_version(sk);
1856 break;
Johan Hedbergfaba42e2010-12-13 21:07:05 +02001857 case MGMT_OP_READ_INDEX_LIST:
1858 err = read_index_list(sk);
1859 break;
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001860 case MGMT_OP_READ_INFO:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001861 err = read_controller_info(sk, index);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001862 break;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001863 case MGMT_OP_SET_POWERED:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001864 err = set_powered(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001865 break;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001866 case MGMT_OP_SET_DISCOVERABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001867 err = set_discoverable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001868 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001869 case MGMT_OP_SET_CONNECTABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001870 err = set_connectable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001871 break;
Johan Hedbergc542a062011-01-26 13:11:03 +02001872 case MGMT_OP_SET_PAIRABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001873 err = set_pairable(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergc542a062011-01-26 13:11:03 +02001874 break;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001875 case MGMT_OP_ADD_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001876 err = add_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001877 break;
1878 case MGMT_OP_REMOVE_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001879 err = remove_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001880 break;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001881 case MGMT_OP_SET_DEV_CLASS:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001882 err = set_dev_class(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001883 break;
1884 case MGMT_OP_SET_SERVICE_CACHE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001885 err = set_service_cache(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001886 break;
Johan Hedberg86742e12011-11-07 23:13:38 +02001887 case MGMT_OP_LOAD_LINK_KEYS:
1888 err = load_link_keys(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001889 break;
Johan Hedberg86742e12011-11-07 23:13:38 +02001890 case MGMT_OP_REMOVE_KEYS:
1891 err = remove_keys(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001892 break;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001893 case MGMT_OP_DISCONNECT:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001894 err = disconnect(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001895 break;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001896 case MGMT_OP_GET_CONNECTIONS:
Szymon Janc8ce62842011-03-01 16:55:32 +01001897 err = get_connections(sk, index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001898 break;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001899 case MGMT_OP_PIN_CODE_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001900 err = pin_code_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001901 break;
1902 case MGMT_OP_PIN_CODE_NEG_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001903 err = pin_code_neg_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001904 break;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001905 case MGMT_OP_SET_IO_CAPABILITY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001906 err = set_io_capability(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001907 break;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001908 case MGMT_OP_PAIR_DEVICE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001909 err = pair_device(sk, index, buf + sizeof(*hdr), len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001910 break;
Johan Hedberga5c29682011-02-19 12:05:57 -03001911 case MGMT_OP_USER_CONFIRM_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001912 err = user_confirm_reply(sk, index, buf + sizeof(*hdr), len, 1);
Johan Hedberga5c29682011-02-19 12:05:57 -03001913 break;
1914 case MGMT_OP_USER_CONFIRM_NEG_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001915 err = user_confirm_reply(sk, index, buf + sizeof(*hdr), len, 0);
Johan Hedberga5c29682011-02-19 12:05:57 -03001916 break;
Johan Hedbergb312b1612011-03-16 14:29:37 +02001917 case MGMT_OP_SET_LOCAL_NAME:
1918 err = set_local_name(sk, index, buf + sizeof(*hdr), len);
1919 break;
Szymon Jancc35938b2011-03-22 13:12:21 +01001920 case MGMT_OP_READ_LOCAL_OOB_DATA:
1921 err = read_local_oob_data(sk, index);
1922 break;
Szymon Janc2763eda2011-03-22 13:12:22 +01001923 case MGMT_OP_ADD_REMOTE_OOB_DATA:
1924 err = add_remote_oob_data(sk, index, buf + sizeof(*hdr), len);
1925 break;
1926 case MGMT_OP_REMOVE_REMOTE_OOB_DATA:
1927 err = remove_remote_oob_data(sk, index, buf + sizeof(*hdr),
1928 len);
1929 break;
Johan Hedberg14a53662011-04-27 10:29:56 -04001930 case MGMT_OP_START_DISCOVERY:
1931 err = start_discovery(sk, index);
1932 break;
1933 case MGMT_OP_STOP_DISCOVERY:
1934 err = stop_discovery(sk, index);
1935 break;
Antti Julku7fbec222011-06-15 12:01:15 +03001936 case MGMT_OP_BLOCK_DEVICE:
1937 err = block_device(sk, index, buf + sizeof(*hdr), len);
1938 break;
1939 case MGMT_OP_UNBLOCK_DEVICE:
1940 err = unblock_device(sk, index, buf + sizeof(*hdr), len);
1941 break;
Antti Julkuf6422ec2011-06-22 13:11:56 +03001942 case MGMT_OP_SET_FAST_CONNECTABLE:
1943 err = set_fast_connectable(sk, index, buf + sizeof(*hdr),
1944 len);
1945 break;
Johan Hedberg03811012010-12-08 00:21:06 +02001946 default:
1947 BT_DBG("Unknown op %u", opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01001948 err = cmd_status(sk, index, opcode, 0x01);
Johan Hedberg03811012010-12-08 00:21:06 +02001949 break;
1950 }
1951
Johan Hedberge41d8b42010-12-13 21:07:03 +02001952 if (err < 0)
1953 goto done;
1954
Johan Hedberg03811012010-12-08 00:21:06 +02001955 err = msglen;
1956
1957done:
1958 kfree(buf);
1959 return err;
1960}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001961
Johan Hedbergb24752f2011-11-03 14:40:33 +02001962static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
1963{
1964 u8 *status = data;
1965
1966 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
1967 mgmt_pending_remove(cmd);
1968}
1969
Johan Hedberg744cf192011-11-08 20:40:14 +02001970int mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001971{
Johan Hedberg744cf192011-11-08 20:40:14 +02001972 return mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001973}
1974
Johan Hedberg744cf192011-11-08 20:40:14 +02001975int mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001976{
Johan Hedbergb24752f2011-11-03 14:40:33 +02001977 u8 status = ENODEV;
1978
Johan Hedberg744cf192011-11-08 20:40:14 +02001979 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02001980
Johan Hedberg744cf192011-11-08 20:40:14 +02001981 return mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001982}
1983
Johan Hedberg73f22f62010-12-29 16:00:25 +02001984struct cmd_lookup {
Johan Hedberg72a734e2010-12-30 00:38:22 +02001985 u8 val;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001986 struct sock *sk;
1987};
1988
Johan Hedberg72a734e2010-12-30 00:38:22 +02001989static void mode_rsp(struct pending_cmd *cmd, void *data)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001990{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01001991 struct mgmt_mode *cp = cmd->param;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001992 struct cmd_lookup *match = data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001993
Johan Hedberg72a734e2010-12-30 00:38:22 +02001994 if (cp->val != match->val)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001995 return;
1996
Johan Hedberg053f0212011-01-26 13:07:10 +02001997 send_mode_rsp(cmd->sk, cmd->opcode, cmd->index, cp->val);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001998
1999 list_del(&cmd->list);
2000
2001 if (match->sk == NULL) {
2002 match->sk = cmd->sk;
2003 sock_hold(match->sk);
2004 }
2005
2006 mgmt_pending_free(cmd);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002007}
Johan Hedberg5add6af2010-12-16 10:00:37 +02002008
Johan Hedberg744cf192011-11-08 20:40:14 +02002009int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg5add6af2010-12-16 10:00:37 +02002010{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002011 struct mgmt_mode ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002012 struct cmd_lookup match = { powered, NULL };
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002013 int ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002014
Johan Hedberg744cf192011-11-08 20:40:14 +02002015 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, mode_rsp, &match);
Johan Hedberg5add6af2010-12-16 10:00:37 +02002016
Johan Hedbergb24752f2011-11-03 14:40:33 +02002017 if (!powered) {
2018 u8 status = ENETDOWN;
Johan Hedberg744cf192011-11-08 20:40:14 +02002019 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002020 }
2021
Johan Hedberg72a734e2010-12-30 00:38:22 +02002022 ev.val = powered;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002023
Johan Hedberg744cf192011-11-08 20:40:14 +02002024 ret = mgmt_event(MGMT_EV_POWERED, hdev, &ev, sizeof(ev), match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002025
2026 if (match.sk)
2027 sock_put(match.sk);
2028
2029 return ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002030}
Johan Hedberg73f22f62010-12-29 16:00:25 +02002031
Johan Hedberg744cf192011-11-08 20:40:14 +02002032int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg73f22f62010-12-29 16:00:25 +02002033{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002034 struct mgmt_mode ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002035 struct cmd_lookup match = { discoverable, NULL };
2036 int ret;
2037
Johan Hedberg744cf192011-11-08 20:40:14 +02002038 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, mode_rsp, &match);
Johan Hedberg72a734e2010-12-30 00:38:22 +02002039
Johan Hedberg72a734e2010-12-30 00:38:22 +02002040 ev.val = discoverable;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002041
Johan Hedberg744cf192011-11-08 20:40:14 +02002042 ret = mgmt_event(MGMT_EV_DISCOVERABLE, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01002043 match.sk);
Johan Hedberg73f22f62010-12-29 16:00:25 +02002044
2045 if (match.sk)
2046 sock_put(match.sk);
2047
2048 return ret;
2049}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002050
Johan Hedberg744cf192011-11-08 20:40:14 +02002051int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002052{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002053 struct mgmt_mode ev;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002054 struct cmd_lookup match = { connectable, NULL };
2055 int ret;
2056
Johan Hedberg744cf192011-11-08 20:40:14 +02002057 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev, mode_rsp, &match);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002058
Johan Hedberg72a734e2010-12-30 00:38:22 +02002059 ev.val = connectable;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002060
Johan Hedberg744cf192011-11-08 20:40:14 +02002061 ret = mgmt_event(MGMT_EV_CONNECTABLE, hdev, &ev, sizeof(ev), match.sk);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002062
2063 if (match.sk)
2064 sock_put(match.sk);
2065
2066 return ret;
2067}
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002068
Johan Hedberg744cf192011-11-08 20:40:14 +02002069int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002070{
2071 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02002072 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002073 cmd_status_rsp, &status);
2074
2075 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02002076 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002077 cmd_status_rsp, &status);
2078
2079 return 0;
2080}
2081
Johan Hedberg744cf192011-11-08 20:40:14 +02002082int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
2083 u8 persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002084{
Johan Hedberg86742e12011-11-07 23:13:38 +02002085 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002086
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002087 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002088
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002089 ev.store_hint = persistent;
2090 bacpy(&ev.key.bdaddr, &key->bdaddr);
2091 ev.key.type = key->type;
2092 memcpy(ev.key.val, key->val, 16);
2093 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002094
Johan Hedberg744cf192011-11-08 20:40:14 +02002095 return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002096}
Johan Hedbergf7520542011-01-20 12:34:39 +02002097
Johan Hedberg48264f02011-11-09 13:58:58 +02002098int mgmt_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
2099 u8 addr_type)
Johan Hedbergf7520542011-01-20 12:34:39 +02002100{
Johan Hedberg4c659c32011-11-07 23:13:39 +02002101 struct mgmt_addr_info ev;
Johan Hedbergf7520542011-01-20 12:34:39 +02002102
Johan Hedbergf7520542011-01-20 12:34:39 +02002103 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02002104 ev.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02002105
Johan Hedberg744cf192011-11-08 20:40:14 +02002106 return mgmt_event(MGMT_EV_CONNECTED, hdev, &ev, sizeof(ev), NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02002107}
2108
Johan Hedberg8962ee72011-01-20 12:40:27 +02002109static void disconnect_rsp(struct pending_cmd *cmd, void *data)
2110{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01002111 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002112 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02002113 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002114
Johan Hedberga38528f2011-01-22 06:46:43 +02002115 bacpy(&rp.bdaddr, &cp->bdaddr);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002116
Szymon Janc4e51eae2011-02-25 19:05:48 +01002117 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002118
2119 *sk = cmd->sk;
2120 sock_hold(*sk);
2121
Johan Hedberga664b5b2011-02-19 12:06:02 -03002122 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002123}
2124
Johan Hedberg48264f02011-11-09 13:58:58 +02002125int mgmt_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
2126 u8 addr_type)
Johan Hedbergf7520542011-01-20 12:34:39 +02002127{
Johan Hedberg4c659c32011-11-07 23:13:39 +02002128 struct mgmt_addr_info ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002129 struct sock *sk = NULL;
2130 int err;
2131
Johan Hedberg744cf192011-11-08 20:40:14 +02002132 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02002133
Johan Hedbergf7520542011-01-20 12:34:39 +02002134 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02002135 ev.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02002136
Johan Hedberg744cf192011-11-08 20:40:14 +02002137 err = mgmt_event(MGMT_EV_DISCONNECTED, hdev, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002138
2139 if (sk)
2140 sock_put(sk);
2141
2142 return err;
2143}
2144
Johan Hedberg744cf192011-11-08 20:40:14 +02002145int mgmt_disconnect_failed(struct hci_dev *hdev)
Johan Hedberg8962ee72011-01-20 12:40:27 +02002146{
2147 struct pending_cmd *cmd;
2148 int err;
2149
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002150 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002151 if (!cmd)
2152 return -ENOENT;
2153
Johan Hedberg744cf192011-11-08 20:40:14 +02002154 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_DISCONNECT, EIO);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002155
Johan Hedberga664b5b2011-02-19 12:06:02 -03002156 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002157
2158 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02002159}
Johan Hedberg17d5c042011-01-22 06:09:08 +02002160
Johan Hedberg48264f02011-11-09 13:58:58 +02002161int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
2162 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02002163{
2164 struct mgmt_ev_connect_failed ev;
2165
Johan Hedberg4c659c32011-11-07 23:13:39 +02002166 bacpy(&ev.addr.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02002167 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedberg17d5c042011-01-22 06:09:08 +02002168 ev.status = status;
2169
Johan Hedberg744cf192011-11-08 20:40:14 +02002170 return mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02002171}
Johan Hedberg980e1a52011-01-22 06:10:07 +02002172
Johan Hedberg744cf192011-11-08 20:40:14 +02002173int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002174{
2175 struct mgmt_ev_pin_code_request ev;
2176
Johan Hedberg980e1a52011-01-22 06:10:07 +02002177 bacpy(&ev.bdaddr, bdaddr);
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02002178 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002179
Johan Hedberg744cf192011-11-08 20:40:14 +02002180 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01002181 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002182}
2183
Johan Hedberg744cf192011-11-08 20:40:14 +02002184int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
2185 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002186{
2187 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002188 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002189 int err;
2190
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002191 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002192 if (!cmd)
2193 return -ENOENT;
2194
Johan Hedbergac56fb12011-02-19 12:05:59 -03002195 bacpy(&rp.bdaddr, bdaddr);
2196 rp.status = status;
2197
Johan Hedberg744cf192011-11-08 20:40:14 +02002198 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY, &rp,
Szymon Janc4e51eae2011-02-25 19:05:48 +01002199 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002200
Johan Hedberga664b5b2011-02-19 12:06:02 -03002201 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002202
2203 return err;
2204}
2205
Johan Hedberg744cf192011-11-08 20:40:14 +02002206int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
2207 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002208{
2209 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002210 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002211 int err;
2212
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002213 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002214 if (!cmd)
2215 return -ENOENT;
2216
Johan Hedbergac56fb12011-02-19 12:05:59 -03002217 bacpy(&rp.bdaddr, bdaddr);
2218 rp.status = status;
2219
Johan Hedberg744cf192011-11-08 20:40:14 +02002220 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY, &rp,
Szymon Janc4e51eae2011-02-25 19:05:48 +01002221 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002222
Johan Hedberga664b5b2011-02-19 12:06:02 -03002223 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002224
2225 return err;
2226}
Johan Hedberga5c29682011-02-19 12:05:57 -03002227
Johan Hedberg744cf192011-11-08 20:40:14 +02002228int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
2229 __le32 value, u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03002230{
2231 struct mgmt_ev_user_confirm_request ev;
2232
Johan Hedberg744cf192011-11-08 20:40:14 +02002233 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03002234
Johan Hedberga5c29682011-02-19 12:05:57 -03002235 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07002236 ev.confirm_hint = confirm_hint;
Johan Hedberga5c29682011-02-19 12:05:57 -03002237 put_unaligned_le32(value, &ev.value);
2238
Johan Hedberg744cf192011-11-08 20:40:14 +02002239 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01002240 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03002241}
2242
Johan Hedberg744cf192011-11-08 20:40:14 +02002243static int confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
2244 u8 status, u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03002245{
2246 struct pending_cmd *cmd;
2247 struct mgmt_rp_user_confirm_reply rp;
2248 int err;
2249
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002250 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002251 if (!cmd)
2252 return -ENOENT;
2253
Johan Hedberga5c29682011-02-19 12:05:57 -03002254 bacpy(&rp.bdaddr, bdaddr);
2255 rp.status = status;
Johan Hedberg744cf192011-11-08 20:40:14 +02002256 err = cmd_complete(cmd->sk, hdev->id, opcode, &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03002257
Johan Hedberga664b5b2011-02-19 12:06:02 -03002258 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002259
2260 return err;
2261}
2262
Johan Hedberg744cf192011-11-08 20:40:14 +02002263int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
2264 u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03002265{
Johan Hedberg744cf192011-11-08 20:40:14 +02002266 return confirm_reply_complete(hdev, bdaddr, status,
Johan Hedberga5c29682011-02-19 12:05:57 -03002267 MGMT_OP_USER_CONFIRM_REPLY);
2268}
2269
Johan Hedberg744cf192011-11-08 20:40:14 +02002270int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev,
2271 bdaddr_t *bdaddr, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03002272{
Johan Hedberg744cf192011-11-08 20:40:14 +02002273 return confirm_reply_complete(hdev, bdaddr, status,
Johan Hedberga5c29682011-02-19 12:05:57 -03002274 MGMT_OP_USER_CONFIRM_NEG_REPLY);
2275}
Johan Hedberg2a611692011-02-19 12:06:00 -03002276
Johan Hedberg744cf192011-11-08 20:40:14 +02002277int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03002278{
2279 struct mgmt_ev_auth_failed ev;
2280
Johan Hedberg2a611692011-02-19 12:06:00 -03002281 bacpy(&ev.bdaddr, bdaddr);
2282 ev.status = status;
2283
Johan Hedberg744cf192011-11-08 20:40:14 +02002284 return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03002285}
Johan Hedbergb312b1612011-03-16 14:29:37 +02002286
Johan Hedberg744cf192011-11-08 20:40:14 +02002287int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02002288{
2289 struct pending_cmd *cmd;
2290 struct mgmt_cp_set_local_name ev;
2291 int err;
2292
2293 memset(&ev, 0, sizeof(ev));
2294 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
2295
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002296 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002297 if (!cmd)
2298 goto send_event;
2299
2300 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02002301 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
2302 EIO);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002303 goto failed;
2304 }
2305
Johan Hedberg744cf192011-11-08 20:40:14 +02002306 update_eir(hdev);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002307
Johan Hedberg744cf192011-11-08 20:40:14 +02002308 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, &ev,
Johan Hedbergb312b1612011-03-16 14:29:37 +02002309 sizeof(ev));
2310 if (err < 0)
2311 goto failed;
2312
2313send_event:
Johan Hedberg744cf192011-11-08 20:40:14 +02002314 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
Johan Hedbergb312b1612011-03-16 14:29:37 +02002315 cmd ? cmd->sk : NULL);
2316
2317failed:
2318 if (cmd)
2319 mgmt_pending_remove(cmd);
2320 return err;
2321}
Szymon Jancc35938b2011-03-22 13:12:21 +01002322
Johan Hedberg744cf192011-11-08 20:40:14 +02002323int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
2324 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01002325{
2326 struct pending_cmd *cmd;
2327 int err;
2328
Johan Hedberg744cf192011-11-08 20:40:14 +02002329 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01002330
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002331 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002332 if (!cmd)
2333 return -ENOENT;
2334
2335 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02002336 err = cmd_status(cmd->sk, hdev->id,
2337 MGMT_OP_READ_LOCAL_OOB_DATA, EIO);
Szymon Jancc35938b2011-03-22 13:12:21 +01002338 } else {
2339 struct mgmt_rp_read_local_oob_data rp;
2340
2341 memcpy(rp.hash, hash, sizeof(rp.hash));
2342 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
2343
Johan Hedberg744cf192011-11-08 20:40:14 +02002344 err = cmd_complete(cmd->sk, hdev->id,
2345 MGMT_OP_READ_LOCAL_OOB_DATA,
2346 &rp, sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01002347 }
2348
2349 mgmt_pending_remove(cmd);
2350
2351 return err;
2352}
Johan Hedberge17acd42011-03-30 23:57:16 +03002353
Johan Hedberg48264f02011-11-09 13:58:58 +02002354int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
2355 u8 addr_type, u8 *dev_class, s8 rssi, u8 *eir)
Johan Hedberge17acd42011-03-30 23:57:16 +03002356{
2357 struct mgmt_ev_device_found ev;
2358
2359 memset(&ev, 0, sizeof(ev));
2360
Johan Hedberg4c659c32011-11-07 23:13:39 +02002361 bacpy(&ev.addr.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02002362 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedberge17acd42011-03-30 23:57:16 +03002363 ev.rssi = rssi;
2364
2365 if (eir)
2366 memcpy(ev.eir, eir, sizeof(ev.eir));
2367
Andre Guedesf8523592011-09-09 18:56:26 -03002368 if (dev_class)
2369 memcpy(ev.dev_class, dev_class, sizeof(ev.dev_class));
2370
Johan Hedberg744cf192011-11-08 20:40:14 +02002371 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, &ev, sizeof(ev), NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03002372}
Johan Hedberga88a9652011-03-30 13:18:12 +03002373
Johan Hedberg744cf192011-11-08 20:40:14 +02002374int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *name)
Johan Hedberga88a9652011-03-30 13:18:12 +03002375{
2376 struct mgmt_ev_remote_name ev;
2377
2378 memset(&ev, 0, sizeof(ev));
2379
2380 bacpy(&ev.bdaddr, bdaddr);
2381 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
2382
Johan Hedberg744cf192011-11-08 20:40:14 +02002383 return mgmt_event(MGMT_EV_REMOTE_NAME, hdev, &ev, sizeof(ev), NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03002384}
Johan Hedberg314b2382011-04-27 10:29:57 -04002385
Johan Hedberg744cf192011-11-08 20:40:14 +02002386int mgmt_inquiry_failed(struct hci_dev *hdev, u8 status)
Johan Hedberg164a6e72011-11-01 17:06:44 +02002387{
2388 struct pending_cmd *cmd;
2389 int err;
2390
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002391 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02002392 if (!cmd)
2393 return -ENOENT;
2394
Johan Hedberg744cf192011-11-08 20:40:14 +02002395 err = cmd_status(cmd->sk, hdev->id, cmd->opcode, status);
Johan Hedberg164a6e72011-11-01 17:06:44 +02002396 mgmt_pending_remove(cmd);
2397
2398 return err;
2399}
2400
Johan Hedberg744cf192011-11-08 20:40:14 +02002401int mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04002402{
Johan Hedberg164a6e72011-11-01 17:06:44 +02002403 struct pending_cmd *cmd;
2404
2405 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002406 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02002407 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002408 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02002409
2410 if (cmd != NULL) {
Johan Hedberg744cf192011-11-08 20:40:14 +02002411 cmd_complete(cmd->sk, hdev->id, cmd->opcode, NULL, 0);
Johan Hedberg164a6e72011-11-01 17:06:44 +02002412 mgmt_pending_remove(cmd);
2413 }
2414
Johan Hedberg744cf192011-11-08 20:40:14 +02002415 return mgmt_event(MGMT_EV_DISCOVERING, hdev, &discovering,
Johan Hedberg314b2382011-04-27 10:29:57 -04002416 sizeof(discovering), NULL);
2417}
Antti Julku5e762442011-08-25 16:48:02 +03002418
Johan Hedberg744cf192011-11-08 20:40:14 +02002419int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr)
Antti Julku5e762442011-08-25 16:48:02 +03002420{
2421 struct pending_cmd *cmd;
2422 struct mgmt_ev_device_blocked ev;
2423
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002424 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002425
2426 bacpy(&ev.bdaddr, bdaddr);
2427
Johan Hedberg744cf192011-11-08 20:40:14 +02002428 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
2429 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03002430}
2431
Johan Hedberg744cf192011-11-08 20:40:14 +02002432int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr)
Antti Julku5e762442011-08-25 16:48:02 +03002433{
2434 struct pending_cmd *cmd;
2435 struct mgmt_ev_device_unblocked ev;
2436
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002437 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002438
2439 bacpy(&ev.bdaddr, bdaddr);
2440
Johan Hedberg744cf192011-11-08 20:40:14 +02002441 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
2442 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03002443}