blob: d0b1a49a66fb438fd5c35f347121533f4231cf23 [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
Johan Hedberg86805702011-11-11 16:18:52 +0200293static int send_mode_rsp(struct sock *sk, u16 opcode, u16 index, u8 val)
294{
295 struct mgmt_mode rp;
296
297 rp.val = val;
298
299 return cmd_complete(sk, index, opcode, &rp, sizeof(rp));
300}
301
Szymon Janc4e51eae2011-02-25 19:05:48 +0100302static int set_powered(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200303{
Johan Hedberg72a734e2010-12-30 00:38:22 +0200304 struct mgmt_mode *cp;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200305 struct hci_dev *hdev;
Johan Hedberg366a0332011-02-19 12:05:55 -0300306 struct pending_cmd *cmd;
Johan Hedberg366a0332011-02-19 12:05:55 -0300307 int err, up;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200308
309 cp = (void *) data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200310
Szymon Janc4e51eae2011-02-25 19:05:48 +0100311 BT_DBG("request for hci%u", index);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200312
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100313 if (len != sizeof(*cp))
314 return cmd_status(sk, index, MGMT_OP_SET_POWERED, EINVAL);
315
Szymon Janc4e51eae2011-02-25 19:05:48 +0100316 hdev = hci_dev_get(index);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200317 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100318 return cmd_status(sk, index, MGMT_OP_SET_POWERED, ENODEV);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200319
Andre Guedes8c156c32011-07-07 10:30:36 -0300320 hci_dev_lock_bh(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200321
322 up = test_bit(HCI_UP, &hdev->flags);
Johan Hedberg72a734e2010-12-30 00:38:22 +0200323 if ((cp->val && up) || (!cp->val && !up)) {
Johan Hedberg86805702011-11-11 16:18:52 +0200324 err = send_mode_rsp(sk, index, MGMT_OP_SET_POWERED, cp->val);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200325 goto failed;
326 }
327
Johan Hedberg2e58ef32011-11-08 20:40:15 +0200328 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100329 err = cmd_status(sk, index, MGMT_OP_SET_POWERED, EBUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200330 goto failed;
331 }
332
Johan Hedberg2e58ef32011-11-08 20:40:15 +0200333 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -0300334 if (!cmd) {
335 err = -ENOMEM;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200336 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -0300337 }
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200338
Johan Hedberg72a734e2010-12-30 00:38:22 +0200339 if (cp->val)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200340 queue_work(hdev->workqueue, &hdev->power_on);
341 else
Johan Hedberg32435532011-11-07 22:16:04 +0200342 queue_work(hdev->workqueue, &hdev->power_off.work);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200343
Johan Hedberg366a0332011-02-19 12:05:55 -0300344 err = 0;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200345
346failed:
Andre Guedes8c156c32011-07-07 10:30:36 -0300347 hci_dev_unlock_bh(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200348 hci_dev_put(hdev);
Johan Hedberg366a0332011-02-19 12:05:55 -0300349 return err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200350}
351
Szymon Janc4e51eae2011-02-25 19:05:48 +0100352static int set_discoverable(struct sock *sk, u16 index, unsigned char *data,
353 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +0200354{
Johan Hedberg16ab91a2011-11-07 22:16:02 +0200355 struct mgmt_cp_set_discoverable *cp;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200356 struct hci_dev *hdev;
Johan Hedberg366a0332011-02-19 12:05:55 -0300357 struct pending_cmd *cmd;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200358 u8 scan;
359 int err;
360
361 cp = (void *) data;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200362
Szymon Janc4e51eae2011-02-25 19:05:48 +0100363 BT_DBG("request for hci%u", index);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200364
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100365 if (len != sizeof(*cp))
366 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, EINVAL);
367
Szymon Janc4e51eae2011-02-25 19:05:48 +0100368 hdev = hci_dev_get(index);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200369 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100370 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, ENODEV);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200371
Andre Guedes8c156c32011-07-07 10:30:36 -0300372 hci_dev_lock_bh(hdev);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200373
374 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100375 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, ENETDOWN);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200376 goto failed;
377 }
378
Johan Hedberg2e58ef32011-11-08 20:40:15 +0200379 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
380 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100381 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, EBUSY);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200382 goto failed;
383 }
384
Johan Hedberg72a734e2010-12-30 00:38:22 +0200385 if (cp->val == test_bit(HCI_ISCAN, &hdev->flags) &&
Johan Hedberg73f22f62010-12-29 16:00:25 +0200386 test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg86805702011-11-11 16:18:52 +0200387 err = send_mode_rsp(sk, index, MGMT_OP_SET_DISCOVERABLE,
388 cp->val);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200389 goto failed;
390 }
391
Johan Hedberg2e58ef32011-11-08 20:40:15 +0200392 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -0300393 if (!cmd) {
394 err = -ENOMEM;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200395 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -0300396 }
Johan Hedberg73f22f62010-12-29 16:00:25 +0200397
398 scan = SCAN_PAGE;
399
Johan Hedberg72a734e2010-12-30 00:38:22 +0200400 if (cp->val)
Johan Hedberg73f22f62010-12-29 16:00:25 +0200401 scan |= SCAN_INQUIRY;
Johan Hedberg16ab91a2011-11-07 22:16:02 +0200402 else
Johan Hedberge0f93092011-11-09 01:44:22 +0200403 cancel_delayed_work(&hdev->discov_off);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200404
405 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
406 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -0300407 mgmt_pending_remove(cmd);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200408
Johan Hedberg16ab91a2011-11-07 22:16:02 +0200409 if (cp->val)
410 hdev->discov_timeout = get_unaligned_le16(&cp->timeout);
411
Johan Hedberg73f22f62010-12-29 16:00:25 +0200412failed:
Andre Guedes8c156c32011-07-07 10:30:36 -0300413 hci_dev_unlock_bh(hdev);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200414 hci_dev_put(hdev);
415
416 return err;
417}
418
Szymon Janc4e51eae2011-02-25 19:05:48 +0100419static int set_connectable(struct sock *sk, u16 index, unsigned char *data,
420 u16 len)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200421{
Johan Hedberg72a734e2010-12-30 00:38:22 +0200422 struct mgmt_mode *cp;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200423 struct hci_dev *hdev;
Johan Hedberg366a0332011-02-19 12:05:55 -0300424 struct pending_cmd *cmd;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200425 u8 scan;
426 int err;
427
428 cp = (void *) data;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200429
Szymon Janc4e51eae2011-02-25 19:05:48 +0100430 BT_DBG("request for hci%u", index);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200431
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100432 if (len != sizeof(*cp))
433 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, EINVAL);
434
Szymon Janc4e51eae2011-02-25 19:05:48 +0100435 hdev = hci_dev_get(index);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200436 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100437 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, ENODEV);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200438
Andre Guedes8c156c32011-07-07 10:30:36 -0300439 hci_dev_lock_bh(hdev);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200440
441 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100442 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, ENETDOWN);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200443 goto failed;
444 }
445
Johan Hedberg2e58ef32011-11-08 20:40:15 +0200446 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
447 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100448 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, EBUSY);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200449 goto failed;
450 }
451
Johan Hedberg72a734e2010-12-30 00:38:22 +0200452 if (cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg86805702011-11-11 16:18:52 +0200453 err = send_mode_rsp(sk, index, MGMT_OP_SET_CONNECTABLE,
454 cp->val);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200455 goto failed;
456 }
457
Johan Hedberg2e58ef32011-11-08 20:40:15 +0200458 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -0300459 if (!cmd) {
460 err = -ENOMEM;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200461 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -0300462 }
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200463
Johan Hedberg72a734e2010-12-30 00:38:22 +0200464 if (cp->val)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200465 scan = SCAN_PAGE;
466 else
467 scan = 0;
468
469 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
470 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -0300471 mgmt_pending_remove(cmd);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200472
473failed:
Andre Guedes8c156c32011-07-07 10:30:36 -0300474 hci_dev_unlock_bh(hdev);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200475 hci_dev_put(hdev);
476
477 return err;
478}
479
Johan Hedberg744cf192011-11-08 20:40:14 +0200480static int mgmt_event(u16 event, struct hci_dev *hdev, void *data,
481 u16 data_len, struct sock *skip_sk)
Johan Hedbergc542a062011-01-26 13:11:03 +0200482{
483 struct sk_buff *skb;
484 struct mgmt_hdr *hdr;
485
486 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_ATOMIC);
487 if (!skb)
488 return -ENOMEM;
489
490 bt_cb(skb)->channel = HCI_CHANNEL_CONTROL;
491
492 hdr = (void *) skb_put(skb, sizeof(*hdr));
493 hdr->opcode = cpu_to_le16(event);
Johan Hedberg744cf192011-11-08 20:40:14 +0200494 if (hdev)
495 hdr->index = cpu_to_le16(hdev->id);
496 else
497 hdr->index = cpu_to_le16(MGMT_INDEX_NONE);
Johan Hedbergc542a062011-01-26 13:11:03 +0200498 hdr->len = cpu_to_le16(data_len);
499
Szymon Janc4e51eae2011-02-25 19:05:48 +0100500 if (data)
501 memcpy(skb_put(skb, data_len), data, data_len);
Johan Hedbergc542a062011-01-26 13:11:03 +0200502
503 hci_send_to_sock(NULL, skb, skip_sk);
504 kfree_skb(skb);
505
506 return 0;
507}
508
Szymon Janc4e51eae2011-02-25 19:05:48 +0100509static int set_pairable(struct sock *sk, u16 index, unsigned char *data,
510 u16 len)
Johan Hedbergc542a062011-01-26 13:11:03 +0200511{
512 struct mgmt_mode *cp, ev;
513 struct hci_dev *hdev;
Johan Hedbergc542a062011-01-26 13:11:03 +0200514 int err;
515
516 cp = (void *) data;
Johan Hedbergc542a062011-01-26 13:11:03 +0200517
Szymon Janc4e51eae2011-02-25 19:05:48 +0100518 BT_DBG("request for hci%u", index);
Johan Hedbergc542a062011-01-26 13:11:03 +0200519
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100520 if (len != sizeof(*cp))
521 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE, EINVAL);
522
Szymon Janc4e51eae2011-02-25 19:05:48 +0100523 hdev = hci_dev_get(index);
Johan Hedbergc542a062011-01-26 13:11:03 +0200524 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100525 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE, ENODEV);
Johan Hedbergc542a062011-01-26 13:11:03 +0200526
Andre Guedes8c156c32011-07-07 10:30:36 -0300527 hci_dev_lock_bh(hdev);
Johan Hedbergc542a062011-01-26 13:11:03 +0200528
529 if (cp->val)
530 set_bit(HCI_PAIRABLE, &hdev->flags);
531 else
532 clear_bit(HCI_PAIRABLE, &hdev->flags);
533
Szymon Janc4e51eae2011-02-25 19:05:48 +0100534 err = send_mode_rsp(sk, MGMT_OP_SET_PAIRABLE, index, cp->val);
Johan Hedbergc542a062011-01-26 13:11:03 +0200535 if (err < 0)
536 goto failed;
537
Johan Hedbergc542a062011-01-26 13:11:03 +0200538 ev.val = cp->val;
539
Johan Hedberg744cf192011-11-08 20:40:14 +0200540 err = mgmt_event(MGMT_EV_PAIRABLE, hdev, &ev, sizeof(ev), sk);
Johan Hedbergc542a062011-01-26 13:11:03 +0200541
542failed:
Andre Guedes8c156c32011-07-07 10:30:36 -0300543 hci_dev_unlock_bh(hdev);
Johan Hedbergc542a062011-01-26 13:11:03 +0200544 hci_dev_put(hdev);
545
546 return err;
547}
548
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300549#define EIR_FLAGS 0x01 /* flags */
550#define EIR_UUID16_SOME 0x02 /* 16-bit UUID, more available */
551#define EIR_UUID16_ALL 0x03 /* 16-bit UUID, all listed */
552#define EIR_UUID32_SOME 0x04 /* 32-bit UUID, more available */
553#define EIR_UUID32_ALL 0x05 /* 32-bit UUID, all listed */
554#define EIR_UUID128_SOME 0x06 /* 128-bit UUID, more available */
555#define EIR_UUID128_ALL 0x07 /* 128-bit UUID, all listed */
556#define EIR_NAME_SHORT 0x08 /* shortened local name */
557#define EIR_NAME_COMPLETE 0x09 /* complete local name */
558#define EIR_TX_POWER 0x0A /* transmit power level */
559#define EIR_DEVICE_ID 0x10 /* device ID */
560
561#define PNP_INFO_SVCLASS_ID 0x1200
562
563static u8 bluetooth_base_uuid[] = {
564 0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80,
565 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
566};
567
568static u16 get_uuid16(u8 *uuid128)
569{
570 u32 val;
571 int i;
572
573 for (i = 0; i < 12; i++) {
574 if (bluetooth_base_uuid[i] != uuid128[i])
575 return 0;
576 }
577
578 memcpy(&val, &uuid128[12], 4);
579
580 val = le32_to_cpu(val);
581 if (val > 0xffff)
582 return 0;
583
584 return (u16) val;
585}
586
587static void create_eir(struct hci_dev *hdev, u8 *data)
588{
589 u8 *ptr = data;
590 u16 eir_len = 0;
591 u16 uuid16_list[HCI_MAX_EIR_LENGTH / sizeof(u16)];
592 int i, truncated = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200593 struct bt_uuid *uuid;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300594 size_t name_len;
595
596 name_len = strlen(hdev->dev_name);
597
598 if (name_len > 0) {
599 /* EIR Data type */
600 if (name_len > 48) {
601 name_len = 48;
602 ptr[1] = EIR_NAME_SHORT;
603 } else
604 ptr[1] = EIR_NAME_COMPLETE;
605
606 /* EIR Data length */
607 ptr[0] = name_len + 1;
608
609 memcpy(ptr + 2, hdev->dev_name, name_len);
610
611 eir_len += (name_len + 2);
612 ptr += (name_len + 2);
613 }
614
615 memset(uuid16_list, 0, sizeof(uuid16_list));
616
617 /* Group all UUID16 types */
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200618 list_for_each_entry(uuid, &hdev->uuids, list) {
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300619 u16 uuid16;
620
621 uuid16 = get_uuid16(uuid->uuid);
622 if (uuid16 == 0)
623 return;
624
625 if (uuid16 < 0x1100)
626 continue;
627
628 if (uuid16 == PNP_INFO_SVCLASS_ID)
629 continue;
630
631 /* Stop if not enough space to put next UUID */
632 if (eir_len + 2 + sizeof(u16) > HCI_MAX_EIR_LENGTH) {
633 truncated = 1;
634 break;
635 }
636
637 /* Check for duplicates */
638 for (i = 0; uuid16_list[i] != 0; i++)
639 if (uuid16_list[i] == uuid16)
640 break;
641
642 if (uuid16_list[i] == 0) {
643 uuid16_list[i] = uuid16;
644 eir_len += sizeof(u16);
645 }
646 }
647
648 if (uuid16_list[0] != 0) {
649 u8 *length = ptr;
650
651 /* EIR Data type */
652 ptr[1] = truncated ? EIR_UUID16_SOME : EIR_UUID16_ALL;
653
654 ptr += 2;
655 eir_len += 2;
656
657 for (i = 0; uuid16_list[i] != 0; i++) {
658 *ptr++ = (uuid16_list[i] & 0x00ff);
659 *ptr++ = (uuid16_list[i] & 0xff00) >> 8;
660 }
661
662 /* EIR Data length */
663 *length = (i * sizeof(u16)) + 1;
664 }
665}
666
667static int update_eir(struct hci_dev *hdev)
668{
669 struct hci_cp_write_eir cp;
670
671 if (!(hdev->features[6] & LMP_EXT_INQ))
672 return 0;
673
674 if (hdev->ssp_mode == 0)
675 return 0;
676
677 if (test_bit(HCI_SERVICE_CACHE, &hdev->flags))
678 return 0;
679
680 memset(&cp, 0, sizeof(cp));
681
682 create_eir(hdev, cp.data);
683
684 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
685 return 0;
686
687 memcpy(hdev->eir, cp.data, sizeof(cp.data));
688
689 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
690}
691
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200692static u8 get_service_classes(struct hci_dev *hdev)
693{
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300694 struct bt_uuid *uuid;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200695 u8 val = 0;
696
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300697 list_for_each_entry(uuid, &hdev->uuids, list)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200698 val |= uuid->svc_hint;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200699
700 return val;
701}
702
703static int update_class(struct hci_dev *hdev)
704{
705 u8 cod[3];
706
707 BT_DBG("%s", hdev->name);
708
709 if (test_bit(HCI_SERVICE_CACHE, &hdev->flags))
710 return 0;
711
712 cod[0] = hdev->minor_class;
713 cod[1] = hdev->major_class;
714 cod[2] = get_service_classes(hdev);
715
716 if (memcmp(cod, hdev->dev_class, 3) == 0)
717 return 0;
718
719 return hci_send_cmd(hdev, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
720}
721
Szymon Janc4e51eae2011-02-25 19:05:48 +0100722static int add_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200723{
724 struct mgmt_cp_add_uuid *cp;
725 struct hci_dev *hdev;
726 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200727 int err;
728
729 cp = (void *) data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200730
Szymon Janc4e51eae2011-02-25 19:05:48 +0100731 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200732
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100733 if (len != sizeof(*cp))
734 return cmd_status(sk, index, MGMT_OP_ADD_UUID, EINVAL);
735
Szymon Janc4e51eae2011-02-25 19:05:48 +0100736 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200737 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100738 return cmd_status(sk, index, MGMT_OP_ADD_UUID, ENODEV);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200739
Andre Guedes8c156c32011-07-07 10:30:36 -0300740 hci_dev_lock_bh(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200741
742 uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC);
743 if (!uuid) {
744 err = -ENOMEM;
745 goto failed;
746 }
747
748 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200749 uuid->svc_hint = cp->svc_hint;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200750
751 list_add(&uuid->list, &hdev->uuids);
752
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200753 err = update_class(hdev);
754 if (err < 0)
755 goto failed;
756
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300757 err = update_eir(hdev);
758 if (err < 0)
759 goto failed;
760
Szymon Janc4e51eae2011-02-25 19:05:48 +0100761 err = cmd_complete(sk, index, MGMT_OP_ADD_UUID, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200762
763failed:
Andre Guedes8c156c32011-07-07 10:30:36 -0300764 hci_dev_unlock_bh(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200765 hci_dev_put(hdev);
766
767 return err;
768}
769
Szymon Janc4e51eae2011-02-25 19:05:48 +0100770static int remove_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200771{
772 struct list_head *p, *n;
Szymon Janc779cb852011-02-25 19:05:47 +0100773 struct mgmt_cp_remove_uuid *cp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200774 struct hci_dev *hdev;
775 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 +0200776 int err, found;
777
778 cp = (void *) data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200779
Szymon Janc4e51eae2011-02-25 19:05:48 +0100780 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200781
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100782 if (len != sizeof(*cp))
783 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID, EINVAL);
784
Szymon Janc4e51eae2011-02-25 19:05:48 +0100785 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200786 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100787 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID, ENODEV);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200788
Andre Guedes8c156c32011-07-07 10:30:36 -0300789 hci_dev_lock_bh(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200790
791 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
792 err = hci_uuids_clear(hdev);
793 goto unlock;
794 }
795
796 found = 0;
797
798 list_for_each_safe(p, n, &hdev->uuids) {
799 struct bt_uuid *match = list_entry(p, struct bt_uuid, list);
800
801 if (memcmp(match->uuid, cp->uuid, 16) != 0)
802 continue;
803
804 list_del(&match->list);
805 found++;
806 }
807
808 if (found == 0) {
Szymon Janc4e51eae2011-02-25 19:05:48 +0100809 err = cmd_status(sk, index, MGMT_OP_REMOVE_UUID, ENOENT);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200810 goto unlock;
811 }
812
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200813 err = update_class(hdev);
814 if (err < 0)
815 goto unlock;
816
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300817 err = update_eir(hdev);
818 if (err < 0)
819 goto unlock;
820
Szymon Janc4e51eae2011-02-25 19:05:48 +0100821 err = cmd_complete(sk, index, MGMT_OP_REMOVE_UUID, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200822
823unlock:
Andre Guedes8c156c32011-07-07 10:30:36 -0300824 hci_dev_unlock_bh(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200825 hci_dev_put(hdev);
826
827 return err;
828}
829
Szymon Janc4e51eae2011-02-25 19:05:48 +0100830static int set_dev_class(struct sock *sk, u16 index, unsigned char *data,
831 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200832{
833 struct hci_dev *hdev;
834 struct mgmt_cp_set_dev_class *cp;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200835 int err;
836
837 cp = (void *) data;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200838
Szymon Janc4e51eae2011-02-25 19:05:48 +0100839 BT_DBG("request for hci%u", index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200840
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100841 if (len != sizeof(*cp))
842 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS, EINVAL);
843
Szymon Janc4e51eae2011-02-25 19:05:48 +0100844 hdev = hci_dev_get(index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200845 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100846 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS, ENODEV);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200847
Andre Guedes8c156c32011-07-07 10:30:36 -0300848 hci_dev_lock_bh(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200849
850 hdev->major_class = cp->major;
851 hdev->minor_class = cp->minor;
852
853 err = update_class(hdev);
854
855 if (err == 0)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100856 err = cmd_complete(sk, index, MGMT_OP_SET_DEV_CLASS, NULL, 0);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200857
Andre Guedes8c156c32011-07-07 10:30:36 -0300858 hci_dev_unlock_bh(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200859 hci_dev_put(hdev);
860
861 return err;
862}
863
Szymon Janc4e51eae2011-02-25 19:05:48 +0100864static int set_service_cache(struct sock *sk, u16 index, unsigned char *data,
865 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200866{
867 struct hci_dev *hdev;
868 struct mgmt_cp_set_service_cache *cp;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200869 int err;
870
871 cp = (void *) data;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200872
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100873 if (len != sizeof(*cp))
Szymon Jancb8534e02011-03-01 16:55:34 +0100874 return cmd_status(sk, index, MGMT_OP_SET_SERVICE_CACHE, EINVAL);
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100875
Szymon Janc4e51eae2011-02-25 19:05:48 +0100876 hdev = hci_dev_get(index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200877 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100878 return cmd_status(sk, index, MGMT_OP_SET_SERVICE_CACHE, ENODEV);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200879
Andre Guedes8c156c32011-07-07 10:30:36 -0300880 hci_dev_lock_bh(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200881
Szymon Janc4e51eae2011-02-25 19:05:48 +0100882 BT_DBG("hci%u enable %d", index, cp->enable);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200883
884 if (cp->enable) {
885 set_bit(HCI_SERVICE_CACHE, &hdev->flags);
886 err = 0;
887 } else {
888 clear_bit(HCI_SERVICE_CACHE, &hdev->flags);
889 err = update_class(hdev);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300890 if (err == 0)
891 err = update_eir(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200892 }
893
894 if (err == 0)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100895 err = cmd_complete(sk, index, MGMT_OP_SET_SERVICE_CACHE, NULL,
896 0);
Gustavo F. Padovane5b82e52011-10-15 18:03:15 -0300897 else
898 cmd_status(sk, index, MGMT_OP_SET_SERVICE_CACHE, -err);
899
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200900
Andre Guedes8c156c32011-07-07 10:30:36 -0300901 hci_dev_unlock_bh(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200902 hci_dev_put(hdev);
903
904 return err;
905}
906
Johan Hedberg86742e12011-11-07 23:13:38 +0200907static int load_link_keys(struct sock *sk, u16 index, unsigned char *data,
908 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200909{
910 struct hci_dev *hdev;
Johan Hedberg86742e12011-11-07 23:13:38 +0200911 struct mgmt_cp_load_link_keys *cp;
Szymon Janc4e51eae2011-02-25 19:05:48 +0100912 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -0300913 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200914
915 cp = (void *) data;
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100916
917 if (len < sizeof(*cp))
Johan Hedberg86742e12011-11-07 23:13:38 +0200918 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS, EINVAL);
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100919
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200920 key_count = get_unaligned_le16(&cp->key_count);
921
Johan Hedberg86742e12011-11-07 23:13:38 +0200922 expected_len = sizeof(*cp) + key_count *
923 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -0300924 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +0200925 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -0300926 len, expected_len);
Johan Hedberg86742e12011-11-07 23:13:38 +0200927 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS, EINVAL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200928 }
929
Szymon Janc4e51eae2011-02-25 19:05:48 +0100930 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200931 if (!hdev)
Johan Hedberg86742e12011-11-07 23:13:38 +0200932 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS, ENODEV);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200933
Szymon Janc4e51eae2011-02-25 19:05:48 +0100934 BT_DBG("hci%u debug_keys %u key_count %u", index, cp->debug_keys,
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200935 key_count);
936
Andre Guedes8c156c32011-07-07 10:30:36 -0300937 hci_dev_lock_bh(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200938
939 hci_link_keys_clear(hdev);
940
941 set_bit(HCI_LINK_KEYS, &hdev->flags);
942
943 if (cp->debug_keys)
944 set_bit(HCI_DEBUG_KEYS, &hdev->flags);
945 else
946 clear_bit(HCI_DEBUG_KEYS, &hdev->flags);
947
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -0300948 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +0200949 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200950
Johan Hedbergd25e28a2011-04-28 11:28:59 -0700951 hci_add_link_key(hdev, NULL, 0, &key->bdaddr, key->val, key->type,
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200952 key->pin_len);
953 }
954
Andre Guedes8c156c32011-07-07 10:30:36 -0300955 hci_dev_unlock_bh(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200956 hci_dev_put(hdev);
957
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -0300958 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200959}
960
Johan Hedberg86742e12011-11-07 23:13:38 +0200961static int remove_keys(struct sock *sk, u16 index, unsigned char *data,
962 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200963{
964 struct hci_dev *hdev;
Johan Hedberg86742e12011-11-07 23:13:38 +0200965 struct mgmt_cp_remove_keys *cp;
Johan Hedberga8a1d192011-11-10 15:54:38 +0200966 struct mgmt_rp_remove_keys rp;
967 struct hci_cp_disconnect dc;
968 struct pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200969 struct hci_conn *conn;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200970 int err;
971
972 cp = (void *) data;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200973
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100974 if (len != sizeof(*cp))
Johan Hedberg86742e12011-11-07 23:13:38 +0200975 return cmd_status(sk, index, MGMT_OP_REMOVE_KEYS, EINVAL);
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100976
Szymon Janc4e51eae2011-02-25 19:05:48 +0100977 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200978 if (!hdev)
Johan Hedberg86742e12011-11-07 23:13:38 +0200979 return cmd_status(sk, index, MGMT_OP_REMOVE_KEYS, ENODEV);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200980
Andre Guedes8c156c32011-07-07 10:30:36 -0300981 hci_dev_lock_bh(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200982
Johan Hedberga8a1d192011-11-10 15:54:38 +0200983 memset(&rp, 0, sizeof(rp));
984 bacpy(&rp.bdaddr, &cp->bdaddr);
985
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200986 err = hci_remove_link_key(hdev, &cp->bdaddr);
Johan Hedberga8a1d192011-11-10 15:54:38 +0200987 if (err < 0)
988 goto unlock;
989
990 if (!test_bit(HCI_UP, &hdev->flags) || !cp->disconnect) {
991 err = cmd_complete(sk, index, MGMT_OP_REMOVE_KEYS, &rp,
992 sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200993 goto unlock;
994 }
995
Johan Hedberg55ed8ca12011-01-17 14:41:05 +0200996 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
Johan Hedberga8a1d192011-11-10 15:54:38 +0200997 if (!conn) {
998 err = cmd_complete(sk, index, MGMT_OP_REMOVE_KEYS, &rp,
999 sizeof(rp));
1000 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001001 }
1002
Johan Hedberga8a1d192011-11-10 15:54:38 +02001003 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_KEYS, hdev, cp, sizeof(*cp));
1004 if (!cmd) {
1005 err = -ENOMEM;
1006 goto unlock;
1007 }
1008
1009 put_unaligned_le16(conn->handle, &dc.handle);
1010 dc.reason = 0x13; /* Remote User Terminated Connection */
1011 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1012 if (err < 0)
1013 mgmt_pending_remove(cmd);
1014
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001015unlock:
Johan Hedberga8a1d192011-11-10 15:54:38 +02001016 if (err < 0) {
1017 rp.status = -err;
1018 err = cmd_complete(sk, index, MGMT_OP_REMOVE_KEYS, &rp,
1019 sizeof(rp));
1020 }
Andre Guedes8c156c32011-07-07 10:30:36 -03001021 hci_dev_unlock_bh(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001022 hci_dev_put(hdev);
1023
1024 return err;
1025}
1026
Szymon Janc4e51eae2011-02-25 19:05:48 +01001027static int disconnect(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02001028{
1029 struct hci_dev *hdev;
1030 struct mgmt_cp_disconnect *cp;
1031 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03001032 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001033 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001034 int err;
1035
1036 BT_DBG("");
1037
1038 cp = (void *) data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001039
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001040 if (len != sizeof(*cp))
1041 return cmd_status(sk, index, MGMT_OP_DISCONNECT, EINVAL);
1042
Szymon Janc4e51eae2011-02-25 19:05:48 +01001043 hdev = hci_dev_get(index);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001044 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001045 return cmd_status(sk, index, MGMT_OP_DISCONNECT, ENODEV);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001046
Andre Guedes8c156c32011-07-07 10:30:36 -03001047 hci_dev_lock_bh(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001048
1049 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001050 err = cmd_status(sk, index, MGMT_OP_DISCONNECT, ENETDOWN);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001051 goto failed;
1052 }
1053
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001054 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001055 err = cmd_status(sk, index, MGMT_OP_DISCONNECT, EBUSY);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001056 goto failed;
1057 }
1058
1059 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03001060 if (!conn)
1061 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->bdaddr);
1062
Johan Hedberg8962ee72011-01-20 12:40:27 +02001063 if (!conn) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001064 err = cmd_status(sk, index, MGMT_OP_DISCONNECT, ENOTCONN);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001065 goto failed;
1066 }
1067
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001068 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001069 if (!cmd) {
1070 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001071 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001072 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001073
1074 put_unaligned_le16(conn->handle, &dc.handle);
1075 dc.reason = 0x13; /* Remote User Terminated Connection */
1076
1077 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1078 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001079 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001080
1081failed:
Andre Guedes8c156c32011-07-07 10:30:36 -03001082 hci_dev_unlock_bh(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001083 hci_dev_put(hdev);
1084
1085 return err;
1086}
1087
Johan Hedberg48264f02011-11-09 13:58:58 +02001088static u8 link_to_mgmt(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02001089{
1090 switch (link_type) {
1091 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02001092 switch (addr_type) {
1093 case ADDR_LE_DEV_PUBLIC:
1094 return MGMT_ADDR_LE_PUBLIC;
1095 case ADDR_LE_DEV_RANDOM:
1096 return MGMT_ADDR_LE_RANDOM;
1097 default:
1098 return MGMT_ADDR_INVALID;
1099 }
Johan Hedberg4c659c32011-11-07 23:13:39 +02001100 case ACL_LINK:
1101 return MGMT_ADDR_BREDR;
1102 default:
1103 return MGMT_ADDR_INVALID;
1104 }
1105}
1106
Szymon Janc8ce62842011-03-01 16:55:32 +01001107static int get_connections(struct sock *sk, u16 index)
Johan Hedberg2784eb42011-01-21 13:56:35 +02001108{
Johan Hedberg2784eb42011-01-21 13:56:35 +02001109 struct mgmt_rp_get_connections *rp;
1110 struct hci_dev *hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001111 struct hci_conn *c;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001112 struct list_head *p;
Johan Hedberga38528f2011-01-22 06:46:43 +02001113 size_t rp_len;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001114 u16 count;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001115 int i, err;
1116
1117 BT_DBG("");
1118
Szymon Janc4e51eae2011-02-25 19:05:48 +01001119 hdev = hci_dev_get(index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001120 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001121 return cmd_status(sk, index, MGMT_OP_GET_CONNECTIONS, ENODEV);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001122
Andre Guedes8c156c32011-07-07 10:30:36 -03001123 hci_dev_lock_bh(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001124
1125 count = 0;
1126 list_for_each(p, &hdev->conn_hash.list) {
1127 count++;
1128 }
1129
Johan Hedberg4c659c32011-11-07 23:13:39 +02001130 rp_len = sizeof(*rp) + (count * sizeof(struct mgmt_addr_info));
Johan Hedberga38528f2011-01-22 06:46:43 +02001131 rp = kmalloc(rp_len, GFP_ATOMIC);
1132 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02001133 err = -ENOMEM;
1134 goto unlock;
1135 }
1136
Johan Hedberg2784eb42011-01-21 13:56:35 +02001137 put_unaligned_le16(count, &rp->conn_count);
1138
Johan Hedberg2784eb42011-01-21 13:56:35 +02001139 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001140 list_for_each_entry(c, &hdev->conn_hash.list, list) {
1141 bacpy(&rp->addr[i].bdaddr, &c->dst);
Johan Hedberg48264f02011-11-09 13:58:58 +02001142 rp->addr[i].type = link_to_mgmt(c->type, c->dst_type);
Johan Hedberg4c659c32011-11-07 23:13:39 +02001143 if (rp->addr[i].type == MGMT_ADDR_INVALID)
1144 continue;
1145 i++;
1146 }
1147
1148 /* Recalculate length in case of filtered SCO connections, etc */
1149 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02001150
Szymon Janc4e51eae2011-02-25 19:05:48 +01001151 err = cmd_complete(sk, index, MGMT_OP_GET_CONNECTIONS, rp, rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001152
1153unlock:
Johan Hedberga38528f2011-01-22 06:46:43 +02001154 kfree(rp);
Andre Guedes8c156c32011-07-07 10:30:36 -03001155 hci_dev_unlock_bh(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001156 hci_dev_put(hdev);
1157 return err;
1158}
1159
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001160static int send_pin_code_neg_reply(struct sock *sk, u16 index,
1161 struct hci_dev *hdev, struct mgmt_cp_pin_code_neg_reply *cp)
1162{
1163 struct pending_cmd *cmd;
1164 int err;
1165
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001166 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001167 sizeof(*cp));
1168 if (!cmd)
1169 return -ENOMEM;
1170
1171 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY, sizeof(cp->bdaddr),
1172 &cp->bdaddr);
1173 if (err < 0)
1174 mgmt_pending_remove(cmd);
1175
1176 return err;
1177}
1178
Szymon Janc4e51eae2011-02-25 19:05:48 +01001179static int pin_code_reply(struct sock *sk, u16 index, unsigned char *data,
1180 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001181{
1182 struct hci_dev *hdev;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001183 struct hci_conn *conn;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001184 struct mgmt_cp_pin_code_reply *cp;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001185 struct mgmt_cp_pin_code_neg_reply ncp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001186 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03001187 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001188 int err;
1189
1190 BT_DBG("");
1191
1192 cp = (void *) data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001193
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001194 if (len != sizeof(*cp))
1195 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, EINVAL);
1196
Szymon Janc4e51eae2011-02-25 19:05:48 +01001197 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001198 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001199 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENODEV);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001200
Andre Guedes8c156c32011-07-07 10:30:36 -03001201 hci_dev_lock_bh(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001202
1203 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001204 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENETDOWN);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001205 goto failed;
1206 }
1207
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001208 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
1209 if (!conn) {
1210 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENOTCONN);
1211 goto failed;
1212 }
1213
1214 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
1215 bacpy(&ncp.bdaddr, &cp->bdaddr);
1216
1217 BT_ERR("PIN code is not 16 bytes long");
1218
1219 err = send_pin_code_neg_reply(sk, index, hdev, &ncp);
1220 if (err >= 0)
1221 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1222 EINVAL);
1223
1224 goto failed;
1225 }
1226
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001227 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001228 if (!cmd) {
1229 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001230 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001231 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02001232
1233 bacpy(&reply.bdaddr, &cp->bdaddr);
1234 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02001235 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02001236
1237 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
1238 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001239 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001240
1241failed:
Andre Guedes8c156c32011-07-07 10:30:36 -03001242 hci_dev_unlock_bh(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001243 hci_dev_put(hdev);
1244
1245 return err;
1246}
1247
Szymon Janc4e51eae2011-02-25 19:05:48 +01001248static int pin_code_neg_reply(struct sock *sk, u16 index, unsigned char *data,
1249 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001250{
1251 struct hci_dev *hdev;
1252 struct mgmt_cp_pin_code_neg_reply *cp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001253 int err;
1254
1255 BT_DBG("");
1256
1257 cp = (void *) data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001258
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001259 if (len != sizeof(*cp))
1260 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1261 EINVAL);
1262
Szymon Janc4e51eae2011-02-25 19:05:48 +01001263 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001264 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001265 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1266 ENODEV);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001267
Andre Guedes8c156c32011-07-07 10:30:36 -03001268 hci_dev_lock_bh(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001269
1270 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001271 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
1272 ENETDOWN);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001273 goto failed;
1274 }
1275
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001276 err = send_pin_code_neg_reply(sk, index, hdev, cp);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001277
1278failed:
Andre Guedes8c156c32011-07-07 10:30:36 -03001279 hci_dev_unlock_bh(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001280 hci_dev_put(hdev);
1281
1282 return err;
1283}
1284
Szymon Janc4e51eae2011-02-25 19:05:48 +01001285static int set_io_capability(struct sock *sk, u16 index, unsigned char *data,
1286 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001287{
1288 struct hci_dev *hdev;
1289 struct mgmt_cp_set_io_capability *cp;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001290
1291 BT_DBG("");
1292
1293 cp = (void *) data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001294
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001295 if (len != sizeof(*cp))
Szymon Jancb8534e02011-03-01 16:55:34 +01001296 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY, EINVAL);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001297
Szymon Janc4e51eae2011-02-25 19:05:48 +01001298 hdev = hci_dev_get(index);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001299 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001300 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY, ENODEV);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001301
Andre Guedes8c156c32011-07-07 10:30:36 -03001302 hci_dev_lock_bh(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001303
1304 hdev->io_capability = cp->io_capability;
1305
1306 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Szymon Jancb8534e02011-03-01 16:55:34 +01001307 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001308
Andre Guedes8c156c32011-07-07 10:30:36 -03001309 hci_dev_unlock_bh(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001310 hci_dev_put(hdev);
1311
Szymon Janc4e51eae2011-02-25 19:05:48 +01001312 return cmd_complete(sk, index, MGMT_OP_SET_IO_CAPABILITY, NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001313}
1314
Johan Hedberge9a416b2011-02-19 12:05:56 -03001315static inline struct pending_cmd *find_pairing(struct hci_conn *conn)
1316{
1317 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001318 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001319
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001320 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03001321 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
1322 continue;
1323
Johan Hedberge9a416b2011-02-19 12:05:56 -03001324 if (cmd->user_data != conn)
1325 continue;
1326
1327 return cmd;
1328 }
1329
1330 return NULL;
1331}
1332
1333static void pairing_complete(struct pending_cmd *cmd, u8 status)
1334{
1335 struct mgmt_rp_pair_device rp;
1336 struct hci_conn *conn = cmd->user_data;
1337
Johan Hedbergba4e5642011-11-11 00:07:34 +02001338 bacpy(&rp.addr.bdaddr, &conn->dst);
1339 rp.addr.type = link_to_mgmt(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001340 rp.status = status;
1341
Szymon Janc4e51eae2011-02-25 19:05:48 +01001342 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001343
1344 /* So we don't get further callbacks for this connection */
1345 conn->connect_cfm_cb = NULL;
1346 conn->security_cfm_cb = NULL;
1347 conn->disconn_cfm_cb = NULL;
1348
1349 hci_conn_put(conn);
1350
Johan Hedberga664b5b2011-02-19 12:06:02 -03001351 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001352}
1353
1354static void pairing_complete_cb(struct hci_conn *conn, u8 status)
1355{
1356 struct pending_cmd *cmd;
1357
1358 BT_DBG("status %u", status);
1359
Johan Hedberg56e5cb82011-11-08 20:40:16 +02001360 cmd = find_pairing(conn);
1361 if (!cmd)
1362 BT_DBG("Unable to find a pending command");
1363 else
1364 pairing_complete(cmd, status);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001365}
1366
Szymon Janc4e51eae2011-02-25 19:05:48 +01001367static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001368{
1369 struct hci_dev *hdev;
1370 struct mgmt_cp_pair_device *cp;
Johan Hedberg1425acb2011-11-11 00:07:35 +02001371 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001372 struct pending_cmd *cmd;
1373 u8 sec_level, auth_type;
1374 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001375 int err;
1376
1377 BT_DBG("");
1378
1379 cp = (void *) data;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001380
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001381 if (len != sizeof(*cp))
1382 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, EINVAL);
1383
Szymon Janc4e51eae2011-02-25 19:05:48 +01001384 hdev = hci_dev_get(index);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001385 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001386 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, ENODEV);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001387
Andre Guedes8c156c32011-07-07 10:30:36 -03001388 hci_dev_lock_bh(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001389
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001390 sec_level = BT_SECURITY_MEDIUM;
1391 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001392 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001393 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03001394 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001395
Johan Hedbergba4e5642011-11-11 00:07:34 +02001396 if (cp->addr.type == MGMT_ADDR_BREDR)
1397 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr, sec_level,
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001398 auth_type);
1399 else
Johan Hedbergba4e5642011-11-11 00:07:34 +02001400 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr, sec_level,
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001401 auth_type);
1402
Johan Hedberg1425acb2011-11-11 00:07:35 +02001403 memset(&rp, 0, sizeof(rp));
1404 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1405 rp.addr.type = cp->addr.type;
1406
Ville Tervo30e76272011-02-22 16:10:53 -03001407 if (IS_ERR(conn)) {
Johan Hedberg1425acb2011-11-11 00:07:35 +02001408 rp.status = -PTR_ERR(conn);
1409 err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE,
1410 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001411 goto unlock;
1412 }
1413
1414 if (conn->connect_cfm_cb) {
1415 hci_conn_put(conn);
Johan Hedberg1425acb2011-11-11 00:07:35 +02001416 rp.status = EBUSY;
1417 err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE,
1418 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001419 goto unlock;
1420 }
1421
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001422 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001423 if (!cmd) {
1424 err = -ENOMEM;
1425 hci_conn_put(conn);
1426 goto unlock;
1427 }
1428
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001429 /* For LE, just connecting isn't a proof that the pairing finished */
Johan Hedbergba4e5642011-11-11 00:07:34 +02001430 if (cp->addr.type == MGMT_ADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001431 conn->connect_cfm_cb = pairing_complete_cb;
1432
Johan Hedberge9a416b2011-02-19 12:05:56 -03001433 conn->security_cfm_cb = pairing_complete_cb;
1434 conn->disconn_cfm_cb = pairing_complete_cb;
1435 conn->io_capability = cp->io_cap;
1436 cmd->user_data = conn;
1437
1438 if (conn->state == BT_CONNECTED &&
1439 hci_conn_security(conn, sec_level, auth_type))
1440 pairing_complete(cmd, 0);
1441
1442 err = 0;
1443
1444unlock:
Andre Guedes8c156c32011-07-07 10:30:36 -03001445 hci_dev_unlock_bh(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001446 hci_dev_put(hdev);
1447
1448 return err;
1449}
1450
Szymon Janc4e51eae2011-02-25 19:05:48 +01001451static int user_confirm_reply(struct sock *sk, u16 index, unsigned char *data,
1452 u16 len, int success)
Johan Hedberga5c29682011-02-19 12:05:57 -03001453{
1454 struct mgmt_cp_user_confirm_reply *cp = (void *) data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001455 u16 mgmt_op, hci_op;
Johan Hedberga5c29682011-02-19 12:05:57 -03001456 struct pending_cmd *cmd;
1457 struct hci_dev *hdev;
1458 int err;
1459
1460 BT_DBG("");
1461
Johan Hedberga5c29682011-02-19 12:05:57 -03001462 if (success) {
1463 mgmt_op = MGMT_OP_USER_CONFIRM_REPLY;
1464 hci_op = HCI_OP_USER_CONFIRM_REPLY;
1465 } else {
1466 mgmt_op = MGMT_OP_USER_CONFIRM_NEG_REPLY;
1467 hci_op = HCI_OP_USER_CONFIRM_NEG_REPLY;
1468 }
1469
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001470 if (len != sizeof(*cp))
1471 return cmd_status(sk, index, mgmt_op, EINVAL);
1472
Szymon Janc4e51eae2011-02-25 19:05:48 +01001473 hdev = hci_dev_get(index);
Johan Hedberga5c29682011-02-19 12:05:57 -03001474 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001475 return cmd_status(sk, index, mgmt_op, ENODEV);
Johan Hedberga5c29682011-02-19 12:05:57 -03001476
Andre Guedes8c156c32011-07-07 10:30:36 -03001477 hci_dev_lock_bh(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02001478
Johan Hedberga5c29682011-02-19 12:05:57 -03001479 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001480 err = cmd_status(sk, index, mgmt_op, ENETDOWN);
Johan Hedberga5c29682011-02-19 12:05:57 -03001481 goto failed;
1482 }
1483
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001484 cmd = mgmt_pending_add(sk, mgmt_op, hdev, data, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03001485 if (!cmd) {
1486 err = -ENOMEM;
1487 goto failed;
1488 }
1489
1490 err = hci_send_cmd(hdev, hci_op, sizeof(cp->bdaddr), &cp->bdaddr);
Johan Hedberga664b5b2011-02-19 12:06:02 -03001491 if (err < 0)
1492 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03001493
1494failed:
Andre Guedes8c156c32011-07-07 10:30:36 -03001495 hci_dev_unlock_bh(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03001496 hci_dev_put(hdev);
1497
1498 return err;
1499}
1500
Johan Hedbergb312b1612011-03-16 14:29:37 +02001501static int set_local_name(struct sock *sk, u16 index, unsigned char *data,
1502 u16 len)
1503{
1504 struct mgmt_cp_set_local_name *mgmt_cp = (void *) data;
1505 struct hci_cp_write_local_name hci_cp;
1506 struct hci_dev *hdev;
1507 struct pending_cmd *cmd;
1508 int err;
1509
1510 BT_DBG("");
1511
1512 if (len != sizeof(*mgmt_cp))
1513 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, EINVAL);
1514
1515 hdev = hci_dev_get(index);
1516 if (!hdev)
1517 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, ENODEV);
1518
Andre Guedes8c156c32011-07-07 10:30:36 -03001519 hci_dev_lock_bh(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001520
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001521 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001522 if (!cmd) {
1523 err = -ENOMEM;
1524 goto failed;
1525 }
1526
1527 memcpy(hci_cp.name, mgmt_cp->name, sizeof(hci_cp.name));
1528 err = hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(hci_cp),
1529 &hci_cp);
1530 if (err < 0)
1531 mgmt_pending_remove(cmd);
1532
1533failed:
Andre Guedes8c156c32011-07-07 10:30:36 -03001534 hci_dev_unlock_bh(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001535 hci_dev_put(hdev);
1536
1537 return err;
1538}
1539
Szymon Jancc35938b2011-03-22 13:12:21 +01001540static int read_local_oob_data(struct sock *sk, u16 index)
1541{
1542 struct hci_dev *hdev;
1543 struct pending_cmd *cmd;
1544 int err;
1545
1546 BT_DBG("hci%u", index);
1547
1548 hdev = hci_dev_get(index);
1549 if (!hdev)
1550 return cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
1551 ENODEV);
1552
Andre Guedes8c156c32011-07-07 10:30:36 -03001553 hci_dev_lock_bh(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01001554
1555 if (!test_bit(HCI_UP, &hdev->flags)) {
1556 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
1557 ENETDOWN);
1558 goto unlock;
1559 }
1560
1561 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
1562 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
1563 EOPNOTSUPP);
1564 goto unlock;
1565 }
1566
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001567 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Szymon Jancc35938b2011-03-22 13:12:21 +01001568 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA, EBUSY);
1569 goto unlock;
1570 }
1571
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001572 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01001573 if (!cmd) {
1574 err = -ENOMEM;
1575 goto unlock;
1576 }
1577
1578 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
1579 if (err < 0)
1580 mgmt_pending_remove(cmd);
1581
1582unlock:
Andre Guedes8c156c32011-07-07 10:30:36 -03001583 hci_dev_unlock_bh(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01001584 hci_dev_put(hdev);
1585
1586 return err;
1587}
1588
Szymon Janc2763eda2011-03-22 13:12:22 +01001589static int add_remote_oob_data(struct sock *sk, u16 index, unsigned char *data,
1590 u16 len)
1591{
1592 struct hci_dev *hdev;
1593 struct mgmt_cp_add_remote_oob_data *cp = (void *) data;
1594 int err;
1595
1596 BT_DBG("hci%u ", index);
1597
1598 if (len != sizeof(*cp))
1599 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
1600 EINVAL);
1601
1602 hdev = hci_dev_get(index);
1603 if (!hdev)
1604 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
1605 ENODEV);
1606
Andre Guedes8c156c32011-07-07 10:30:36 -03001607 hci_dev_lock_bh(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001608
1609 err = hci_add_remote_oob_data(hdev, &cp->bdaddr, cp->hash,
1610 cp->randomizer);
1611 if (err < 0)
1612 err = cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, -err);
1613 else
1614 err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, NULL,
1615 0);
1616
Andre Guedes8c156c32011-07-07 10:30:36 -03001617 hci_dev_unlock_bh(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001618 hci_dev_put(hdev);
1619
1620 return err;
1621}
1622
1623static int remove_remote_oob_data(struct sock *sk, u16 index,
1624 unsigned char *data, u16 len)
1625{
1626 struct hci_dev *hdev;
1627 struct mgmt_cp_remove_remote_oob_data *cp = (void *) data;
1628 int err;
1629
1630 BT_DBG("hci%u ", index);
1631
1632 if (len != sizeof(*cp))
1633 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
1634 EINVAL);
1635
1636 hdev = hci_dev_get(index);
1637 if (!hdev)
1638 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
1639 ENODEV);
1640
Andre Guedes8c156c32011-07-07 10:30:36 -03001641 hci_dev_lock_bh(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001642
1643 err = hci_remove_remote_oob_data(hdev, &cp->bdaddr);
1644 if (err < 0)
1645 err = cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
1646 -err);
1647 else
1648 err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
1649 NULL, 0);
1650
Andre Guedes8c156c32011-07-07 10:30:36 -03001651 hci_dev_unlock_bh(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001652 hci_dev_put(hdev);
1653
1654 return err;
1655}
1656
Johan Hedberg14a53662011-04-27 10:29:56 -04001657static int start_discovery(struct sock *sk, u16 index)
1658{
Johan Hedberg14a53662011-04-27 10:29:56 -04001659 struct pending_cmd *cmd;
1660 struct hci_dev *hdev;
1661 int err;
1662
1663 BT_DBG("hci%u", index);
1664
1665 hdev = hci_dev_get(index);
1666 if (!hdev)
1667 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY, ENODEV);
1668
1669 hci_dev_lock_bh(hdev);
1670
Johan Hedbergbd2d1332011-11-07 23:13:37 +02001671 if (!test_bit(HCI_UP, &hdev->flags)) {
1672 err = cmd_status(sk, index, MGMT_OP_START_DISCOVERY, ENETDOWN);
1673 goto failed;
1674 }
1675
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001676 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04001677 if (!cmd) {
1678 err = -ENOMEM;
1679 goto failed;
1680 }
1681
Andre Guedes2519a1f2011-11-07 11:45:24 -03001682 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
Johan Hedberg14a53662011-04-27 10:29:56 -04001683 if (err < 0)
1684 mgmt_pending_remove(cmd);
1685
1686failed:
1687 hci_dev_unlock_bh(hdev);
1688 hci_dev_put(hdev);
1689
1690 return err;
1691}
1692
1693static int stop_discovery(struct sock *sk, u16 index)
1694{
1695 struct hci_dev *hdev;
1696 struct pending_cmd *cmd;
1697 int err;
1698
1699 BT_DBG("hci%u", index);
1700
1701 hdev = hci_dev_get(index);
1702 if (!hdev)
1703 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY, ENODEV);
1704
1705 hci_dev_lock_bh(hdev);
1706
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001707 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04001708 if (!cmd) {
1709 err = -ENOMEM;
1710 goto failed;
1711 }
1712
Andre Guedes023d50492011-11-04 14:16:52 -03001713 err = hci_cancel_inquiry(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04001714 if (err < 0)
1715 mgmt_pending_remove(cmd);
1716
1717failed:
1718 hci_dev_unlock_bh(hdev);
1719 hci_dev_put(hdev);
1720
1721 return err;
1722}
1723
Antti Julku7fbec222011-06-15 12:01:15 +03001724static int block_device(struct sock *sk, u16 index, unsigned char *data,
1725 u16 len)
1726{
1727 struct hci_dev *hdev;
Antti Julku5e762442011-08-25 16:48:02 +03001728 struct mgmt_cp_block_device *cp = (void *) data;
Antti Julku7fbec222011-06-15 12:01:15 +03001729 int err;
1730
1731 BT_DBG("hci%u", index);
1732
Antti Julku7fbec222011-06-15 12:01:15 +03001733 if (len != sizeof(*cp))
1734 return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
1735 EINVAL);
1736
1737 hdev = hci_dev_get(index);
1738 if (!hdev)
1739 return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
1740 ENODEV);
1741
Antti Julku5e762442011-08-25 16:48:02 +03001742 hci_dev_lock_bh(hdev);
1743
Antti Julku7fbec222011-06-15 12:01:15 +03001744 err = hci_blacklist_add(hdev, &cp->bdaddr);
Antti Julku7fbec222011-06-15 12:01:15 +03001745 if (err < 0)
1746 err = cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE, -err);
1747 else
1748 err = cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE,
1749 NULL, 0);
Antti Julku5e762442011-08-25 16:48:02 +03001750
Antti Julku5e762442011-08-25 16:48:02 +03001751 hci_dev_unlock_bh(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03001752 hci_dev_put(hdev);
1753
1754 return err;
1755}
1756
1757static int unblock_device(struct sock *sk, u16 index, unsigned char *data,
1758 u16 len)
1759{
1760 struct hci_dev *hdev;
Antti Julku5e762442011-08-25 16:48:02 +03001761 struct mgmt_cp_unblock_device *cp = (void *) data;
Antti Julku7fbec222011-06-15 12:01:15 +03001762 int err;
1763
1764 BT_DBG("hci%u", index);
1765
Antti Julku7fbec222011-06-15 12:01:15 +03001766 if (len != sizeof(*cp))
1767 return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
1768 EINVAL);
1769
1770 hdev = hci_dev_get(index);
1771 if (!hdev)
1772 return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
1773 ENODEV);
1774
Antti Julku5e762442011-08-25 16:48:02 +03001775 hci_dev_lock_bh(hdev);
1776
Antti Julku7fbec222011-06-15 12:01:15 +03001777 err = hci_blacklist_del(hdev, &cp->bdaddr);
1778
1779 if (err < 0)
1780 err = cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE, -err);
1781 else
1782 err = cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE,
1783 NULL, 0);
Antti Julku5e762442011-08-25 16:48:02 +03001784
Antti Julku5e762442011-08-25 16:48:02 +03001785 hci_dev_unlock_bh(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03001786 hci_dev_put(hdev);
1787
1788 return err;
1789}
1790
Antti Julkuf6422ec2011-06-22 13:11:56 +03001791static int set_fast_connectable(struct sock *sk, u16 index,
1792 unsigned char *data, u16 len)
1793{
1794 struct hci_dev *hdev;
1795 struct mgmt_cp_set_fast_connectable *cp = (void *) data;
1796 struct hci_cp_write_page_scan_activity acp;
1797 u8 type;
1798 int err;
1799
1800 BT_DBG("hci%u", index);
1801
1802 if (len != sizeof(*cp))
1803 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
1804 EINVAL);
1805
1806 hdev = hci_dev_get(index);
1807 if (!hdev)
1808 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
1809 ENODEV);
1810
1811 hci_dev_lock(hdev);
1812
1813 if (cp->enable) {
1814 type = PAGE_SCAN_TYPE_INTERLACED;
1815 acp.interval = 0x0024; /* 22.5 msec page scan interval */
1816 } else {
1817 type = PAGE_SCAN_TYPE_STANDARD; /* default */
1818 acp.interval = 0x0800; /* default 1.28 sec page scan */
1819 }
1820
1821 acp.window = 0x0012; /* default 11.25 msec page scan window */
1822
1823 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
1824 sizeof(acp), &acp);
1825 if (err < 0) {
1826 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
1827 -err);
1828 goto done;
1829 }
1830
1831 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
1832 if (err < 0) {
1833 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
1834 -err);
1835 goto done;
1836 }
1837
1838 err = cmd_complete(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
1839 NULL, 0);
1840done:
1841 hci_dev_unlock(hdev);
1842 hci_dev_put(hdev);
1843
1844 return err;
1845}
1846
Johan Hedberg03811012010-12-08 00:21:06 +02001847int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
1848{
1849 unsigned char *buf;
1850 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001851 u16 opcode, index, len;
Johan Hedberg03811012010-12-08 00:21:06 +02001852 int err;
1853
1854 BT_DBG("got %zu bytes", msglen);
1855
1856 if (msglen < sizeof(*hdr))
1857 return -EINVAL;
1858
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03001859 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02001860 if (!buf)
1861 return -ENOMEM;
1862
1863 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
1864 err = -EFAULT;
1865 goto done;
1866 }
1867
1868 hdr = (struct mgmt_hdr *) buf;
1869 opcode = get_unaligned_le16(&hdr->opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01001870 index = get_unaligned_le16(&hdr->index);
Johan Hedberg03811012010-12-08 00:21:06 +02001871 len = get_unaligned_le16(&hdr->len);
1872
1873 if (len != msglen - sizeof(*hdr)) {
1874 err = -EINVAL;
1875 goto done;
1876 }
1877
1878 switch (opcode) {
Johan Hedberg02d98122010-12-13 21:07:04 +02001879 case MGMT_OP_READ_VERSION:
1880 err = read_version(sk);
1881 break;
Johan Hedbergfaba42e2010-12-13 21:07:05 +02001882 case MGMT_OP_READ_INDEX_LIST:
1883 err = read_index_list(sk);
1884 break;
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001885 case MGMT_OP_READ_INFO:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001886 err = read_controller_info(sk, index);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001887 break;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001888 case MGMT_OP_SET_POWERED:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001889 err = set_powered(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001890 break;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001891 case MGMT_OP_SET_DISCOVERABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001892 err = set_discoverable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg73f22f62010-12-29 16:00:25 +02001893 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001894 case MGMT_OP_SET_CONNECTABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001895 err = set_connectable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02001896 break;
Johan Hedbergc542a062011-01-26 13:11:03 +02001897 case MGMT_OP_SET_PAIRABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001898 err = set_pairable(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergc542a062011-01-26 13:11:03 +02001899 break;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001900 case MGMT_OP_ADD_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001901 err = add_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001902 break;
1903 case MGMT_OP_REMOVE_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001904 err = remove_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001905 break;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001906 case MGMT_OP_SET_DEV_CLASS:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001907 err = set_dev_class(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001908 break;
1909 case MGMT_OP_SET_SERVICE_CACHE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001910 err = set_service_cache(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001911 break;
Johan Hedberg86742e12011-11-07 23:13:38 +02001912 case MGMT_OP_LOAD_LINK_KEYS:
1913 err = load_link_keys(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001914 break;
Johan Hedberg86742e12011-11-07 23:13:38 +02001915 case MGMT_OP_REMOVE_KEYS:
1916 err = remove_keys(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001917 break;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001918 case MGMT_OP_DISCONNECT:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001919 err = disconnect(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001920 break;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001921 case MGMT_OP_GET_CONNECTIONS:
Szymon Janc8ce62842011-03-01 16:55:32 +01001922 err = get_connections(sk, index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001923 break;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001924 case MGMT_OP_PIN_CODE_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001925 err = pin_code_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001926 break;
1927 case MGMT_OP_PIN_CODE_NEG_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001928 err = pin_code_neg_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001929 break;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001930 case MGMT_OP_SET_IO_CAPABILITY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001931 err = set_io_capability(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001932 break;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001933 case MGMT_OP_PAIR_DEVICE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001934 err = pair_device(sk, index, buf + sizeof(*hdr), len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001935 break;
Johan Hedberga5c29682011-02-19 12:05:57 -03001936 case MGMT_OP_USER_CONFIRM_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001937 err = user_confirm_reply(sk, index, buf + sizeof(*hdr), len, 1);
Johan Hedberga5c29682011-02-19 12:05:57 -03001938 break;
1939 case MGMT_OP_USER_CONFIRM_NEG_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01001940 err = user_confirm_reply(sk, index, buf + sizeof(*hdr), len, 0);
Johan Hedberga5c29682011-02-19 12:05:57 -03001941 break;
Johan Hedbergb312b1612011-03-16 14:29:37 +02001942 case MGMT_OP_SET_LOCAL_NAME:
1943 err = set_local_name(sk, index, buf + sizeof(*hdr), len);
1944 break;
Szymon Jancc35938b2011-03-22 13:12:21 +01001945 case MGMT_OP_READ_LOCAL_OOB_DATA:
1946 err = read_local_oob_data(sk, index);
1947 break;
Szymon Janc2763eda2011-03-22 13:12:22 +01001948 case MGMT_OP_ADD_REMOTE_OOB_DATA:
1949 err = add_remote_oob_data(sk, index, buf + sizeof(*hdr), len);
1950 break;
1951 case MGMT_OP_REMOVE_REMOTE_OOB_DATA:
1952 err = remove_remote_oob_data(sk, index, buf + sizeof(*hdr),
1953 len);
1954 break;
Johan Hedberg14a53662011-04-27 10:29:56 -04001955 case MGMT_OP_START_DISCOVERY:
1956 err = start_discovery(sk, index);
1957 break;
1958 case MGMT_OP_STOP_DISCOVERY:
1959 err = stop_discovery(sk, index);
1960 break;
Antti Julku7fbec222011-06-15 12:01:15 +03001961 case MGMT_OP_BLOCK_DEVICE:
1962 err = block_device(sk, index, buf + sizeof(*hdr), len);
1963 break;
1964 case MGMT_OP_UNBLOCK_DEVICE:
1965 err = unblock_device(sk, index, buf + sizeof(*hdr), len);
1966 break;
Antti Julkuf6422ec2011-06-22 13:11:56 +03001967 case MGMT_OP_SET_FAST_CONNECTABLE:
1968 err = set_fast_connectable(sk, index, buf + sizeof(*hdr),
1969 len);
1970 break;
Johan Hedberg03811012010-12-08 00:21:06 +02001971 default:
1972 BT_DBG("Unknown op %u", opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01001973 err = cmd_status(sk, index, opcode, 0x01);
Johan Hedberg03811012010-12-08 00:21:06 +02001974 break;
1975 }
1976
Johan Hedberge41d8b42010-12-13 21:07:03 +02001977 if (err < 0)
1978 goto done;
1979
Johan Hedberg03811012010-12-08 00:21:06 +02001980 err = msglen;
1981
1982done:
1983 kfree(buf);
1984 return err;
1985}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001986
Johan Hedbergb24752f2011-11-03 14:40:33 +02001987static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
1988{
1989 u8 *status = data;
1990
1991 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
1992 mgmt_pending_remove(cmd);
1993}
1994
Johan Hedberg744cf192011-11-08 20:40:14 +02001995int mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001996{
Johan Hedberg744cf192011-11-08 20:40:14 +02001997 return mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02001998}
1999
Johan Hedberg744cf192011-11-08 20:40:14 +02002000int mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002001{
Johan Hedbergb24752f2011-11-03 14:40:33 +02002002 u8 status = ENODEV;
2003
Johan Hedberg744cf192011-11-08 20:40:14 +02002004 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002005
Johan Hedberg744cf192011-11-08 20:40:14 +02002006 return mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002007}
2008
Johan Hedberg73f22f62010-12-29 16:00:25 +02002009struct cmd_lookup {
Johan Hedberg72a734e2010-12-30 00:38:22 +02002010 u8 val;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002011 struct sock *sk;
2012};
2013
Johan Hedberg72a734e2010-12-30 00:38:22 +02002014static void mode_rsp(struct pending_cmd *cmd, void *data)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002015{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01002016 struct mgmt_mode *cp = cmd->param;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002017 struct cmd_lookup *match = data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002018
Johan Hedberg72a734e2010-12-30 00:38:22 +02002019 if (cp->val != match->val)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002020 return;
2021
Johan Hedberg053f0212011-01-26 13:07:10 +02002022 send_mode_rsp(cmd->sk, cmd->opcode, cmd->index, cp->val);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002023
2024 list_del(&cmd->list);
2025
2026 if (match->sk == NULL) {
2027 match->sk = cmd->sk;
2028 sock_hold(match->sk);
2029 }
2030
2031 mgmt_pending_free(cmd);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002032}
Johan Hedberg5add6af2010-12-16 10:00:37 +02002033
Johan Hedberg744cf192011-11-08 20:40:14 +02002034int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg5add6af2010-12-16 10:00:37 +02002035{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002036 struct mgmt_mode ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002037 struct cmd_lookup match = { powered, NULL };
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002038 int ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002039
Johan Hedberg744cf192011-11-08 20:40:14 +02002040 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, mode_rsp, &match);
Johan Hedberg5add6af2010-12-16 10:00:37 +02002041
Johan Hedbergb24752f2011-11-03 14:40:33 +02002042 if (!powered) {
2043 u8 status = ENETDOWN;
Johan Hedberg744cf192011-11-08 20:40:14 +02002044 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002045 }
2046
Johan Hedberg72a734e2010-12-30 00:38:22 +02002047 ev.val = powered;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002048
Johan Hedberg744cf192011-11-08 20:40:14 +02002049 ret = mgmt_event(MGMT_EV_POWERED, hdev, &ev, sizeof(ev), match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002050
2051 if (match.sk)
2052 sock_put(match.sk);
2053
2054 return ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002055}
Johan Hedberg73f22f62010-12-29 16:00:25 +02002056
Johan Hedberg744cf192011-11-08 20:40:14 +02002057int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg73f22f62010-12-29 16:00:25 +02002058{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002059 struct mgmt_mode ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002060 struct cmd_lookup match = { discoverable, NULL };
2061 int ret;
2062
Johan Hedberg744cf192011-11-08 20:40:14 +02002063 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, mode_rsp, &match);
Johan Hedberg72a734e2010-12-30 00:38:22 +02002064
Johan Hedberg72a734e2010-12-30 00:38:22 +02002065 ev.val = discoverable;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002066
Johan Hedberg744cf192011-11-08 20:40:14 +02002067 ret = mgmt_event(MGMT_EV_DISCOVERABLE, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01002068 match.sk);
Johan Hedberg73f22f62010-12-29 16:00:25 +02002069
2070 if (match.sk)
2071 sock_put(match.sk);
2072
2073 return ret;
2074}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002075
Johan Hedberg744cf192011-11-08 20:40:14 +02002076int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002077{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002078 struct mgmt_mode ev;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002079 struct cmd_lookup match = { connectable, NULL };
2080 int ret;
2081
Johan Hedberg744cf192011-11-08 20:40:14 +02002082 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev, mode_rsp, &match);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002083
Johan Hedberg72a734e2010-12-30 00:38:22 +02002084 ev.val = connectable;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002085
Johan Hedberg744cf192011-11-08 20:40:14 +02002086 ret = mgmt_event(MGMT_EV_CONNECTABLE, hdev, &ev, sizeof(ev), match.sk);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002087
2088 if (match.sk)
2089 sock_put(match.sk);
2090
2091 return ret;
2092}
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002093
Johan Hedberg744cf192011-11-08 20:40:14 +02002094int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002095{
2096 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02002097 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002098 cmd_status_rsp, &status);
2099
2100 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02002101 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002102 cmd_status_rsp, &status);
2103
2104 return 0;
2105}
2106
Johan Hedberg744cf192011-11-08 20:40:14 +02002107int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
2108 u8 persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002109{
Johan Hedberg86742e12011-11-07 23:13:38 +02002110 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002111
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002112 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002113
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002114 ev.store_hint = persistent;
2115 bacpy(&ev.key.bdaddr, &key->bdaddr);
2116 ev.key.type = key->type;
2117 memcpy(ev.key.val, key->val, 16);
2118 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002119
Johan Hedberg744cf192011-11-08 20:40:14 +02002120 return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002121}
Johan Hedbergf7520542011-01-20 12:34:39 +02002122
Johan Hedberg48264f02011-11-09 13:58:58 +02002123int mgmt_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
2124 u8 addr_type)
Johan Hedbergf7520542011-01-20 12:34:39 +02002125{
Johan Hedberg4c659c32011-11-07 23:13:39 +02002126 struct mgmt_addr_info ev;
Johan Hedbergf7520542011-01-20 12:34:39 +02002127
Johan Hedbergf7520542011-01-20 12:34:39 +02002128 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02002129 ev.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02002130
Johan Hedberg744cf192011-11-08 20:40:14 +02002131 return mgmt_event(MGMT_EV_CONNECTED, hdev, &ev, sizeof(ev), NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02002132}
2133
Johan Hedberg8962ee72011-01-20 12:40:27 +02002134static void disconnect_rsp(struct pending_cmd *cmd, void *data)
2135{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01002136 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002137 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02002138 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002139
Johan Hedberga38528f2011-01-22 06:46:43 +02002140 bacpy(&rp.bdaddr, &cp->bdaddr);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02002141 rp.status = 0;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002142
Szymon Janc4e51eae2011-02-25 19:05:48 +01002143 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002144
2145 *sk = cmd->sk;
2146 sock_hold(*sk);
2147
Johan Hedberga664b5b2011-02-19 12:06:02 -03002148 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002149}
2150
Johan Hedberga8a1d192011-11-10 15:54:38 +02002151static void remove_keys_rsp(struct pending_cmd *cmd, void *data)
2152{
2153 u8 *status = data;
2154 struct mgmt_cp_remove_keys *cp = cmd->param;
2155 struct mgmt_rp_remove_keys rp;
2156
2157 memset(&rp, 0, sizeof(rp));
2158 bacpy(&rp.bdaddr, &cp->bdaddr);
2159 if (status != NULL)
2160 rp.status = *status;
2161
2162 cmd_complete(cmd->sk, cmd->index, MGMT_OP_REMOVE_KEYS, &rp,
2163 sizeof(rp));
2164
2165 mgmt_pending_remove(cmd);
2166}
2167
Johan Hedberg48264f02011-11-09 13:58:58 +02002168int mgmt_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
2169 u8 addr_type)
Johan Hedbergf7520542011-01-20 12:34:39 +02002170{
Johan Hedberg4c659c32011-11-07 23:13:39 +02002171 struct mgmt_addr_info ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002172 struct sock *sk = NULL;
2173 int err;
2174
Johan Hedberg744cf192011-11-08 20:40:14 +02002175 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02002176
Johan Hedbergf7520542011-01-20 12:34:39 +02002177 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02002178 ev.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02002179
Johan Hedberg744cf192011-11-08 20:40:14 +02002180 err = mgmt_event(MGMT_EV_DISCONNECTED, hdev, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002181
2182 if (sk)
2183 sock_put(sk);
2184
Johan Hedberga8a1d192011-11-10 15:54:38 +02002185 mgmt_pending_foreach(MGMT_OP_REMOVE_KEYS, hdev, remove_keys_rsp, NULL);
2186
Johan Hedberg8962ee72011-01-20 12:40:27 +02002187 return err;
2188}
2189
Johan Hedberg37d9ef72011-11-10 15:54:39 +02002190int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02002191{
2192 struct pending_cmd *cmd;
2193 int err;
2194
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002195 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002196 if (!cmd)
2197 return -ENOENT;
2198
Johan Hedberg37d9ef72011-11-10 15:54:39 +02002199 if (bdaddr) {
2200 struct mgmt_rp_disconnect rp;
2201
2202 bacpy(&rp.bdaddr, bdaddr);
2203 rp.status = status;
2204
2205 err = cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
2206 &rp, sizeof(rp));
2207 } else
2208 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_DISCONNECT,
2209 status);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002210
Johan Hedberga664b5b2011-02-19 12:06:02 -03002211 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002212
2213 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02002214}
Johan Hedberg17d5c042011-01-22 06:09:08 +02002215
Johan Hedberg48264f02011-11-09 13:58:58 +02002216int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
2217 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02002218{
2219 struct mgmt_ev_connect_failed ev;
2220
Johan Hedberg4c659c32011-11-07 23:13:39 +02002221 bacpy(&ev.addr.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02002222 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedberg17d5c042011-01-22 06:09:08 +02002223 ev.status = status;
2224
Johan Hedberg744cf192011-11-08 20:40:14 +02002225 return mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02002226}
Johan Hedberg980e1a52011-01-22 06:10:07 +02002227
Johan Hedberg744cf192011-11-08 20:40:14 +02002228int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002229{
2230 struct mgmt_ev_pin_code_request ev;
2231
Johan Hedberg980e1a52011-01-22 06:10:07 +02002232 bacpy(&ev.bdaddr, bdaddr);
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02002233 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002234
Johan Hedberg744cf192011-11-08 20:40:14 +02002235 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01002236 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002237}
2238
Johan Hedberg744cf192011-11-08 20:40:14 +02002239int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
2240 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002241{
2242 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002243 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002244 int err;
2245
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002246 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002247 if (!cmd)
2248 return -ENOENT;
2249
Johan Hedbergac56fb12011-02-19 12:05:59 -03002250 bacpy(&rp.bdaddr, bdaddr);
2251 rp.status = status;
2252
Johan Hedberg744cf192011-11-08 20:40:14 +02002253 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY, &rp,
Szymon Janc4e51eae2011-02-25 19:05:48 +01002254 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002255
Johan Hedberga664b5b2011-02-19 12:06:02 -03002256 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002257
2258 return err;
2259}
2260
Johan Hedberg744cf192011-11-08 20:40:14 +02002261int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
2262 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002263{
2264 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002265 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002266 int err;
2267
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002268 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002269 if (!cmd)
2270 return -ENOENT;
2271
Johan Hedbergac56fb12011-02-19 12:05:59 -03002272 bacpy(&rp.bdaddr, bdaddr);
2273 rp.status = status;
2274
Johan Hedberg744cf192011-11-08 20:40:14 +02002275 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY, &rp,
Szymon Janc4e51eae2011-02-25 19:05:48 +01002276 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002277
Johan Hedberga664b5b2011-02-19 12:06:02 -03002278 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002279
2280 return err;
2281}
Johan Hedberga5c29682011-02-19 12:05:57 -03002282
Johan Hedberg744cf192011-11-08 20:40:14 +02002283int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
2284 __le32 value, u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03002285{
2286 struct mgmt_ev_user_confirm_request ev;
2287
Johan Hedberg744cf192011-11-08 20:40:14 +02002288 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03002289
Johan Hedberga5c29682011-02-19 12:05:57 -03002290 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07002291 ev.confirm_hint = confirm_hint;
Johan Hedberga5c29682011-02-19 12:05:57 -03002292 put_unaligned_le32(value, &ev.value);
2293
Johan Hedberg744cf192011-11-08 20:40:14 +02002294 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01002295 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03002296}
2297
Johan Hedberg744cf192011-11-08 20:40:14 +02002298static int confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
2299 u8 status, u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03002300{
2301 struct pending_cmd *cmd;
2302 struct mgmt_rp_user_confirm_reply rp;
2303 int err;
2304
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002305 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002306 if (!cmd)
2307 return -ENOENT;
2308
Johan Hedberga5c29682011-02-19 12:05:57 -03002309 bacpy(&rp.bdaddr, bdaddr);
2310 rp.status = status;
Johan Hedberg744cf192011-11-08 20:40:14 +02002311 err = cmd_complete(cmd->sk, hdev->id, opcode, &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03002312
Johan Hedberga664b5b2011-02-19 12:06:02 -03002313 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002314
2315 return err;
2316}
2317
Johan Hedberg744cf192011-11-08 20:40:14 +02002318int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
2319 u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03002320{
Johan Hedberg744cf192011-11-08 20:40:14 +02002321 return confirm_reply_complete(hdev, bdaddr, status,
Johan Hedberga5c29682011-02-19 12:05:57 -03002322 MGMT_OP_USER_CONFIRM_REPLY);
2323}
2324
Johan Hedberg744cf192011-11-08 20:40:14 +02002325int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev,
2326 bdaddr_t *bdaddr, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03002327{
Johan Hedberg744cf192011-11-08 20:40:14 +02002328 return confirm_reply_complete(hdev, bdaddr, status,
Johan Hedberga5c29682011-02-19 12:05:57 -03002329 MGMT_OP_USER_CONFIRM_NEG_REPLY);
2330}
Johan Hedberg2a611692011-02-19 12:06:00 -03002331
Johan Hedberg744cf192011-11-08 20:40:14 +02002332int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03002333{
2334 struct mgmt_ev_auth_failed ev;
2335
Johan Hedberg2a611692011-02-19 12:06:00 -03002336 bacpy(&ev.bdaddr, bdaddr);
2337 ev.status = status;
2338
Johan Hedberg744cf192011-11-08 20:40:14 +02002339 return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03002340}
Johan Hedbergb312b1612011-03-16 14:29:37 +02002341
Johan Hedberg744cf192011-11-08 20:40:14 +02002342int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02002343{
2344 struct pending_cmd *cmd;
2345 struct mgmt_cp_set_local_name ev;
2346 int err;
2347
2348 memset(&ev, 0, sizeof(ev));
2349 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
2350
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002351 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002352 if (!cmd)
2353 goto send_event;
2354
2355 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02002356 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
2357 EIO);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002358 goto failed;
2359 }
2360
Johan Hedberg744cf192011-11-08 20:40:14 +02002361 update_eir(hdev);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002362
Johan Hedberg744cf192011-11-08 20:40:14 +02002363 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, &ev,
Johan Hedbergb312b1612011-03-16 14:29:37 +02002364 sizeof(ev));
2365 if (err < 0)
2366 goto failed;
2367
2368send_event:
Johan Hedberg744cf192011-11-08 20:40:14 +02002369 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
Johan Hedbergb312b1612011-03-16 14:29:37 +02002370 cmd ? cmd->sk : NULL);
2371
2372failed:
2373 if (cmd)
2374 mgmt_pending_remove(cmd);
2375 return err;
2376}
Szymon Jancc35938b2011-03-22 13:12:21 +01002377
Johan Hedberg744cf192011-11-08 20:40:14 +02002378int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
2379 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01002380{
2381 struct pending_cmd *cmd;
2382 int err;
2383
Johan Hedberg744cf192011-11-08 20:40:14 +02002384 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01002385
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002386 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002387 if (!cmd)
2388 return -ENOENT;
2389
2390 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02002391 err = cmd_status(cmd->sk, hdev->id,
2392 MGMT_OP_READ_LOCAL_OOB_DATA, EIO);
Szymon Jancc35938b2011-03-22 13:12:21 +01002393 } else {
2394 struct mgmt_rp_read_local_oob_data rp;
2395
2396 memcpy(rp.hash, hash, sizeof(rp.hash));
2397 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
2398
Johan Hedberg744cf192011-11-08 20:40:14 +02002399 err = cmd_complete(cmd->sk, hdev->id,
2400 MGMT_OP_READ_LOCAL_OOB_DATA,
2401 &rp, sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01002402 }
2403
2404 mgmt_pending_remove(cmd);
2405
2406 return err;
2407}
Johan Hedberge17acd42011-03-30 23:57:16 +03002408
Johan Hedberg48264f02011-11-09 13:58:58 +02002409int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
2410 u8 addr_type, u8 *dev_class, s8 rssi, u8 *eir)
Johan Hedberge17acd42011-03-30 23:57:16 +03002411{
2412 struct mgmt_ev_device_found ev;
2413
2414 memset(&ev, 0, sizeof(ev));
2415
Johan Hedberg4c659c32011-11-07 23:13:39 +02002416 bacpy(&ev.addr.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02002417 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedberge17acd42011-03-30 23:57:16 +03002418 ev.rssi = rssi;
2419
2420 if (eir)
2421 memcpy(ev.eir, eir, sizeof(ev.eir));
2422
Andre Guedesf8523592011-09-09 18:56:26 -03002423 if (dev_class)
2424 memcpy(ev.dev_class, dev_class, sizeof(ev.dev_class));
2425
Johan Hedberg744cf192011-11-08 20:40:14 +02002426 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, &ev, sizeof(ev), NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03002427}
Johan Hedberga88a9652011-03-30 13:18:12 +03002428
Johan Hedberg744cf192011-11-08 20:40:14 +02002429int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *name)
Johan Hedberga88a9652011-03-30 13:18:12 +03002430{
2431 struct mgmt_ev_remote_name ev;
2432
2433 memset(&ev, 0, sizeof(ev));
2434
2435 bacpy(&ev.bdaddr, bdaddr);
2436 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
2437
Johan Hedberg744cf192011-11-08 20:40:14 +02002438 return mgmt_event(MGMT_EV_REMOTE_NAME, hdev, &ev, sizeof(ev), NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03002439}
Johan Hedberg314b2382011-04-27 10:29:57 -04002440
Andre Guedes7a135102011-11-09 17:14:25 -03002441int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
Johan Hedberg164a6e72011-11-01 17:06:44 +02002442{
2443 struct pending_cmd *cmd;
2444 int err;
2445
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002446 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02002447 if (!cmd)
2448 return -ENOENT;
2449
Johan Hedberg744cf192011-11-08 20:40:14 +02002450 err = cmd_status(cmd->sk, hdev->id, cmd->opcode, status);
Johan Hedberg164a6e72011-11-01 17:06:44 +02002451 mgmt_pending_remove(cmd);
2452
2453 return err;
2454}
2455
Andre Guedese6d465c2011-11-09 17:14:26 -03002456int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
2457{
2458 struct pending_cmd *cmd;
2459 int err;
2460
2461 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
2462 if (!cmd)
2463 return -ENOENT;
2464
2465 err = cmd_status(cmd->sk, hdev->id, cmd->opcode, status);
2466 mgmt_pending_remove(cmd);
2467
2468 return err;
2469}
2470
Johan Hedberg744cf192011-11-08 20:40:14 +02002471int mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04002472{
Johan Hedberg164a6e72011-11-01 17:06:44 +02002473 struct pending_cmd *cmd;
2474
2475 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002476 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02002477 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002478 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02002479
2480 if (cmd != NULL) {
Johan Hedberg744cf192011-11-08 20:40:14 +02002481 cmd_complete(cmd->sk, hdev->id, cmd->opcode, NULL, 0);
Johan Hedberg164a6e72011-11-01 17:06:44 +02002482 mgmt_pending_remove(cmd);
2483 }
2484
Johan Hedberg744cf192011-11-08 20:40:14 +02002485 return mgmt_event(MGMT_EV_DISCOVERING, hdev, &discovering,
Johan Hedberg314b2382011-04-27 10:29:57 -04002486 sizeof(discovering), NULL);
2487}
Antti Julku5e762442011-08-25 16:48:02 +03002488
Johan Hedberg744cf192011-11-08 20:40:14 +02002489int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr)
Antti Julku5e762442011-08-25 16:48:02 +03002490{
2491 struct pending_cmd *cmd;
2492 struct mgmt_ev_device_blocked ev;
2493
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002494 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002495
2496 bacpy(&ev.bdaddr, bdaddr);
2497
Johan Hedberg744cf192011-11-08 20:40:14 +02002498 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
2499 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03002500}
2501
Johan Hedberg744cf192011-11-08 20:40:14 +02002502int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr)
Antti Julku5e762442011-08-25 16:48:02 +03002503{
2504 struct pending_cmd *cmd;
2505 struct mgmt_ev_device_unblocked ev;
2506
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002507 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002508
2509 bacpy(&ev.bdaddr, bdaddr);
2510
Johan Hedberg744cf192011-11-08 20:40:14 +02002511 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
2512 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03002513}