blob: 8efbd8eaa1b33aa88dc2ba4e07dce0e73f007284 [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
Johan Hedbergca69b792011-11-11 18:10:00 +020025#include <linux/kernel.h>
Szymon Janc72359752011-02-17 14:16:32 +010026#include <linux/uaccess.h>
Paul Gortmaker3a9a2312011-05-27 09:12:25 -040027#include <linux/module.h>
Johan Hedberg03811012010-12-08 00:21:06 +020028#include <asm/unaligned.h>
29
30#include <net/bluetooth/bluetooth.h>
31#include <net/bluetooth/hci_core.h>
32#include <net/bluetooth/mgmt.h>
Brian Gix5fe57d92011-12-21 16:12:13 -080033#include <net/bluetooth/smp.h>
Johan Hedberg03811012010-12-08 00:21:06 +020034
Johan Hedberg02d98122010-12-13 21:07:04 +020035#define MGMT_VERSION 0
36#define MGMT_REVISION 1
37
Johan Hedberge70bb2e2012-02-13 16:59:33 +020038static const u16 mgmt_commands[] = {
39 MGMT_OP_READ_INDEX_LIST,
40 MGMT_OP_READ_INFO,
41 MGMT_OP_SET_POWERED,
42 MGMT_OP_SET_DISCOVERABLE,
43 MGMT_OP_SET_CONNECTABLE,
44 MGMT_OP_SET_FAST_CONNECTABLE,
45 MGMT_OP_SET_PAIRABLE,
46 MGMT_OP_SET_LINK_SECURITY,
47 MGMT_OP_SET_SSP,
48 MGMT_OP_SET_HS,
49 MGMT_OP_SET_LE,
50 MGMT_OP_SET_DEV_CLASS,
51 MGMT_OP_SET_LOCAL_NAME,
52 MGMT_OP_ADD_UUID,
53 MGMT_OP_REMOVE_UUID,
54 MGMT_OP_LOAD_LINK_KEYS,
55 MGMT_OP_LOAD_LONG_TERM_KEYS,
56 MGMT_OP_DISCONNECT,
57 MGMT_OP_GET_CONNECTIONS,
58 MGMT_OP_PIN_CODE_REPLY,
59 MGMT_OP_PIN_CODE_NEG_REPLY,
60 MGMT_OP_SET_IO_CAPABILITY,
61 MGMT_OP_PAIR_DEVICE,
62 MGMT_OP_CANCEL_PAIR_DEVICE,
63 MGMT_OP_UNPAIR_DEVICE,
64 MGMT_OP_USER_CONFIRM_REPLY,
65 MGMT_OP_USER_CONFIRM_NEG_REPLY,
66 MGMT_OP_USER_PASSKEY_REPLY,
67 MGMT_OP_USER_PASSKEY_NEG_REPLY,
68 MGMT_OP_READ_LOCAL_OOB_DATA,
69 MGMT_OP_ADD_REMOTE_OOB_DATA,
70 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
71 MGMT_OP_START_DISCOVERY,
72 MGMT_OP_STOP_DISCOVERY,
73 MGMT_OP_CONFIRM_NAME,
74 MGMT_OP_BLOCK_DEVICE,
75 MGMT_OP_UNBLOCK_DEVICE,
76};
77
78static const u16 mgmt_events[] = {
79 MGMT_EV_CONTROLLER_ERROR,
80 MGMT_EV_INDEX_ADDED,
81 MGMT_EV_INDEX_REMOVED,
82 MGMT_EV_NEW_SETTINGS,
83 MGMT_EV_CLASS_OF_DEV_CHANGED,
84 MGMT_EV_LOCAL_NAME_CHANGED,
85 MGMT_EV_NEW_LINK_KEY,
86 MGMT_EV_NEW_LONG_TERM_KEY,
87 MGMT_EV_DEVICE_CONNECTED,
88 MGMT_EV_DEVICE_DISCONNECTED,
89 MGMT_EV_CONNECT_FAILED,
90 MGMT_EV_PIN_CODE_REQUEST,
91 MGMT_EV_USER_CONFIRM_REQUEST,
92 MGMT_EV_USER_PASSKEY_REQUEST,
93 MGMT_EV_AUTH_FAILED,
94 MGMT_EV_DEVICE_FOUND,
95 MGMT_EV_DISCOVERING,
96 MGMT_EV_DEVICE_BLOCKED,
97 MGMT_EV_DEVICE_UNBLOCKED,
98 MGMT_EV_DEVICE_UNPAIRED,
99};
100
Andre Guedes3fd24152012-02-03 17:48:01 -0300101/*
102 * These LE scan and inquiry parameters were chosen according to LE General
103 * Discovery Procedure specification.
104 */
105#define LE_SCAN_TYPE 0x01
106#define LE_SCAN_WIN 0x12
107#define LE_SCAN_INT 0x12
108#define LE_SCAN_TIMEOUT_LE_ONLY 10240 /* TGAP(gen_disc_scan_min) */
109
Andre Guedese8777522012-02-03 17:48:02 -0300110#define INQUIRY_LEN_BREDR 0x08 /* TGAP(100) */
Andre Guedes2519a1f2011-11-07 11:45:24 -0300111
Johan Hedberg7d785252011-12-15 00:47:39 +0200112#define SERVICE_CACHE_TIMEOUT (5 * 1000)
113
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200114struct pending_cmd {
115 struct list_head list;
Johan Hedbergfc2f4b12011-11-09 13:58:56 +0200116 u16 opcode;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200117 int index;
Szymon Jancc68fb7f2011-03-22 13:12:19 +0100118 void *param;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200119 struct sock *sk;
Johan Hedberge9a416b2011-02-19 12:05:56 -0300120 void *user_data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200121};
122
Johan Hedbergca69b792011-11-11 18:10:00 +0200123/* HCI to MGMT error code conversion table */
124static u8 mgmt_status_table[] = {
125 MGMT_STATUS_SUCCESS,
126 MGMT_STATUS_UNKNOWN_COMMAND, /* Unknown Command */
127 MGMT_STATUS_NOT_CONNECTED, /* No Connection */
128 MGMT_STATUS_FAILED, /* Hardware Failure */
129 MGMT_STATUS_CONNECT_FAILED, /* Page Timeout */
130 MGMT_STATUS_AUTH_FAILED, /* Authentication Failed */
131 MGMT_STATUS_NOT_PAIRED, /* PIN or Key Missing */
132 MGMT_STATUS_NO_RESOURCES, /* Memory Full */
133 MGMT_STATUS_TIMEOUT, /* Connection Timeout */
134 MGMT_STATUS_NO_RESOURCES, /* Max Number of Connections */
135 MGMT_STATUS_NO_RESOURCES, /* Max Number of SCO Connections */
136 MGMT_STATUS_ALREADY_CONNECTED, /* ACL Connection Exists */
137 MGMT_STATUS_BUSY, /* Command Disallowed */
138 MGMT_STATUS_NO_RESOURCES, /* Rejected Limited Resources */
139 MGMT_STATUS_REJECTED, /* Rejected Security */
140 MGMT_STATUS_REJECTED, /* Rejected Personal */
141 MGMT_STATUS_TIMEOUT, /* Host Timeout */
142 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Feature */
143 MGMT_STATUS_INVALID_PARAMS, /* Invalid Parameters */
144 MGMT_STATUS_DISCONNECTED, /* OE User Ended Connection */
145 MGMT_STATUS_NO_RESOURCES, /* OE Low Resources */
146 MGMT_STATUS_DISCONNECTED, /* OE Power Off */
147 MGMT_STATUS_DISCONNECTED, /* Connection Terminated */
148 MGMT_STATUS_BUSY, /* Repeated Attempts */
149 MGMT_STATUS_REJECTED, /* Pairing Not Allowed */
150 MGMT_STATUS_FAILED, /* Unknown LMP PDU */
151 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Remote Feature */
152 MGMT_STATUS_REJECTED, /* SCO Offset Rejected */
153 MGMT_STATUS_REJECTED, /* SCO Interval Rejected */
154 MGMT_STATUS_REJECTED, /* Air Mode Rejected */
155 MGMT_STATUS_INVALID_PARAMS, /* Invalid LMP Parameters */
156 MGMT_STATUS_FAILED, /* Unspecified Error */
157 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported LMP Parameter Value */
158 MGMT_STATUS_FAILED, /* Role Change Not Allowed */
159 MGMT_STATUS_TIMEOUT, /* LMP Response Timeout */
160 MGMT_STATUS_FAILED, /* LMP Error Transaction Collision */
161 MGMT_STATUS_FAILED, /* LMP PDU Not Allowed */
162 MGMT_STATUS_REJECTED, /* Encryption Mode Not Accepted */
163 MGMT_STATUS_FAILED, /* Unit Link Key Used */
164 MGMT_STATUS_NOT_SUPPORTED, /* QoS Not Supported */
165 MGMT_STATUS_TIMEOUT, /* Instant Passed */
166 MGMT_STATUS_NOT_SUPPORTED, /* Pairing Not Supported */
167 MGMT_STATUS_FAILED, /* Transaction Collision */
168 MGMT_STATUS_INVALID_PARAMS, /* Unacceptable Parameter */
169 MGMT_STATUS_REJECTED, /* QoS Rejected */
170 MGMT_STATUS_NOT_SUPPORTED, /* Classification Not Supported */
171 MGMT_STATUS_REJECTED, /* Insufficient Security */
172 MGMT_STATUS_INVALID_PARAMS, /* Parameter Out Of Range */
173 MGMT_STATUS_BUSY, /* Role Switch Pending */
174 MGMT_STATUS_FAILED, /* Slot Violation */
175 MGMT_STATUS_FAILED, /* Role Switch Failed */
176 MGMT_STATUS_INVALID_PARAMS, /* EIR Too Large */
177 MGMT_STATUS_NOT_SUPPORTED, /* Simple Pairing Not Supported */
178 MGMT_STATUS_BUSY, /* Host Busy Pairing */
179 MGMT_STATUS_REJECTED, /* Rejected, No Suitable Channel */
180 MGMT_STATUS_BUSY, /* Controller Busy */
181 MGMT_STATUS_INVALID_PARAMS, /* Unsuitable Connection Interval */
182 MGMT_STATUS_TIMEOUT, /* Directed Advertising Timeout */
183 MGMT_STATUS_AUTH_FAILED, /* Terminated Due to MIC Failure */
184 MGMT_STATUS_CONNECT_FAILED, /* Connection Establishment Failed */
185 MGMT_STATUS_CONNECT_FAILED, /* MAC Connection Failed */
186};
187
188static u8 mgmt_status(u8 hci_status)
189{
190 if (hci_status < ARRAY_SIZE(mgmt_status_table))
191 return mgmt_status_table[hci_status];
192
193 return MGMT_STATUS_FAILED;
194}
195
Szymon Janc4e51eae2011-02-25 19:05:48 +0100196static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200197{
198 struct sk_buff *skb;
199 struct mgmt_hdr *hdr;
200 struct mgmt_ev_cmd_status *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300201 int err;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200202
Szymon Janc34eb5252011-02-28 14:10:08 +0100203 BT_DBG("sock %p, index %u, cmd %u, status %u", sk, index, cmd, status);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200204
205 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_ATOMIC);
206 if (!skb)
207 return -ENOMEM;
208
209 hdr = (void *) skb_put(skb, sizeof(*hdr));
210
211 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_STATUS);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100212 hdr->index = cpu_to_le16(index);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200213 hdr->len = cpu_to_le16(sizeof(*ev));
214
215 ev = (void *) skb_put(skb, sizeof(*ev));
216 ev->status = status;
217 put_unaligned_le16(cmd, &ev->opcode);
218
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300219 err = sock_queue_rcv_skb(sk, skb);
220 if (err < 0)
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200221 kfree_skb(skb);
222
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300223 return err;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200224}
225
Szymon Janc4e51eae2011-02-25 19:05:48 +0100226static int cmd_complete(struct sock *sk, u16 index, u16 cmd, void *rp,
227 size_t rp_len)
Johan Hedberg02d98122010-12-13 21:07:04 +0200228{
229 struct sk_buff *skb;
230 struct mgmt_hdr *hdr;
231 struct mgmt_ev_cmd_complete *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300232 int err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200233
234 BT_DBG("sock %p", sk);
235
Johan Hedberga38528f2011-01-22 06:46:43 +0200236 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + rp_len, GFP_ATOMIC);
Johan Hedberg02d98122010-12-13 21:07:04 +0200237 if (!skb)
238 return -ENOMEM;
239
240 hdr = (void *) skb_put(skb, sizeof(*hdr));
Johan Hedberga38528f2011-01-22 06:46:43 +0200241
Johan Hedberg02d98122010-12-13 21:07:04 +0200242 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100243 hdr->index = cpu_to_le16(index);
Johan Hedberga38528f2011-01-22 06:46:43 +0200244 hdr->len = cpu_to_le16(sizeof(*ev) + rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200245
Johan Hedberga38528f2011-01-22 06:46:43 +0200246 ev = (void *) skb_put(skb, sizeof(*ev) + rp_len);
247 put_unaligned_le16(cmd, &ev->opcode);
Szymon Janc8020c162011-02-28 14:09:50 +0100248
249 if (rp)
250 memcpy(ev->data, rp, rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200251
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300252 err = sock_queue_rcv_skb(sk, skb);
253 if (err < 0)
Johan Hedberg02d98122010-12-13 21:07:04 +0200254 kfree_skb(skb);
255
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300256 return err;;
Johan Hedberg02d98122010-12-13 21:07:04 +0200257}
258
Johan Hedberga38528f2011-01-22 06:46:43 +0200259static int read_version(struct sock *sk)
260{
261 struct mgmt_rp_read_version rp;
262
263 BT_DBG("sock %p", sk);
264
265 rp.version = MGMT_VERSION;
266 put_unaligned_le16(MGMT_REVISION, &rp.revision);
267
Szymon Janc4e51eae2011-02-25 19:05:48 +0100268 return cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, &rp,
269 sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200270}
271
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200272static int read_commands(struct sock *sk)
273{
274 struct mgmt_rp_read_commands *rp;
275 u16 num_commands = ARRAY_SIZE(mgmt_commands);
276 u16 num_events = ARRAY_SIZE(mgmt_events);
277 u16 *opcode;
278 size_t rp_size;
279 int i, err;
280
281 BT_DBG("sock %p", sk);
282
283 rp_size = sizeof(*rp) + ((num_commands + num_events) * sizeof(u16));
284
285 rp = kmalloc(rp_size, GFP_KERNEL);
286 if (!rp)
287 return -ENOMEM;
288
289 put_unaligned_le16(num_commands, &rp->num_commands);
290 put_unaligned_le16(num_events, &rp->num_events);
291
292 for (i = 0, opcode = rp->opcodes; i < num_commands; i++, opcode++)
293 put_unaligned_le16(mgmt_commands[i], opcode);
294
295 for (i = 0; i < num_events; i++, opcode++)
296 put_unaligned_le16(mgmt_events[i], opcode);
297
298 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_COMMANDS, rp,
299 rp_size);
300 kfree(rp);
301
302 return err;
303}
304
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200305static int read_index_list(struct sock *sk)
306{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200307 struct mgmt_rp_read_index_list *rp;
308 struct list_head *p;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200309 struct hci_dev *d;
Johan Hedberga38528f2011-01-22 06:46:43 +0200310 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200311 u16 count;
Johan Hedberga38528f2011-01-22 06:46:43 +0200312 int i, err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200313
314 BT_DBG("sock %p", sk);
315
316 read_lock(&hci_dev_list_lock);
317
318 count = 0;
319 list_for_each(p, &hci_dev_list) {
320 count++;
321 }
322
Johan Hedberga38528f2011-01-22 06:46:43 +0200323 rp_len = sizeof(*rp) + (2 * count);
324 rp = kmalloc(rp_len, GFP_ATOMIC);
325 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100326 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200327 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100328 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200329
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200330 put_unaligned_le16(count, &rp->num_controllers);
331
332 i = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200333 list_for_each_entry(d, &hci_dev_list, list) {
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200334 if (test_and_clear_bit(HCI_AUTO_OFF, &d->dev_flags))
Johan Hedberge0f93092011-11-09 01:44:22 +0200335 cancel_delayed_work(&d->power_off);
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200336
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200337 if (test_bit(HCI_SETUP, &d->dev_flags))
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200338 continue;
339
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200340 put_unaligned_le16(d->id, &rp->index[i++]);
341 BT_DBG("Added hci%u", d->id);
342 }
343
344 read_unlock(&hci_dev_list_lock);
345
Szymon Janc4e51eae2011-02-25 19:05:48 +0100346 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST, rp,
347 rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200348
Johan Hedberga38528f2011-01-22 06:46:43 +0200349 kfree(rp);
350
351 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200352}
353
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200354static u32 get_supported_settings(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +0200355{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200356 u32 settings = 0;
Johan Hedberg03811012010-12-08 00:21:06 +0200357
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200358 settings |= MGMT_SETTING_POWERED;
359 settings |= MGMT_SETTING_CONNECTABLE;
360 settings |= MGMT_SETTING_FAST_CONNECTABLE;
361 settings |= MGMT_SETTING_DISCOVERABLE;
362 settings |= MGMT_SETTING_PAIRABLE;
Johan Hedberg03811012010-12-08 00:21:06 +0200363
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200364 if (hdev->features[6] & LMP_SIMPLE_PAIR)
365 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200366
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200367 if (!(hdev->features[4] & LMP_NO_BREDR)) {
368 settings |= MGMT_SETTING_BREDR;
369 settings |= MGMT_SETTING_LINK_SECURITY;
370 }
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200371
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200372 if (hdev->features[4] & LMP_LE)
373 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200374
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200375 return settings;
376}
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200377
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200378static u32 get_current_settings(struct hci_dev *hdev)
379{
380 u32 settings = 0;
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200381
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200382 if (test_bit(HCI_UP, &hdev->flags))
383 settings |= MGMT_SETTING_POWERED;
384 else
385 return settings;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200386
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200387 if (test_bit(HCI_PSCAN, &hdev->flags))
388 settings |= MGMT_SETTING_CONNECTABLE;
389
390 if (test_bit(HCI_ISCAN, &hdev->flags))
391 settings |= MGMT_SETTING_DISCOVERABLE;
392
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200393 if (test_bit(HCI_PAIRABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200394 settings |= MGMT_SETTING_PAIRABLE;
395
396 if (!(hdev->features[4] & LMP_NO_BREDR))
397 settings |= MGMT_SETTING_BREDR;
398
Andre Guedes59e29402011-12-30 10:34:03 -0300399 if (hdev->host_features[0] & LMP_HOST_LE)
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200400 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200401
402 if (test_bit(HCI_AUTH, &hdev->flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200403 settings |= MGMT_SETTING_LINK_SECURITY;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200404
Johan Hedberg84bde9d2012-01-25 14:21:06 +0200405 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200406 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200407
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200408 return settings;
Johan Hedbergc542a062011-01-26 13:11:03 +0200409}
410
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300411#define PNP_INFO_SVCLASS_ID 0x1200
412
413static u8 bluetooth_base_uuid[] = {
414 0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80,
415 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
416};
417
418static u16 get_uuid16(u8 *uuid128)
419{
420 u32 val;
421 int i;
422
423 for (i = 0; i < 12; i++) {
424 if (bluetooth_base_uuid[i] != uuid128[i])
425 return 0;
426 }
427
428 memcpy(&val, &uuid128[12], 4);
429
430 val = le32_to_cpu(val);
431 if (val > 0xffff)
432 return 0;
433
434 return (u16) val;
435}
436
437static void create_eir(struct hci_dev *hdev, u8 *data)
438{
439 u8 *ptr = data;
440 u16 eir_len = 0;
441 u16 uuid16_list[HCI_MAX_EIR_LENGTH / sizeof(u16)];
442 int i, truncated = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200443 struct bt_uuid *uuid;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300444 size_t name_len;
445
446 name_len = strlen(hdev->dev_name);
447
448 if (name_len > 0) {
449 /* EIR Data type */
450 if (name_len > 48) {
451 name_len = 48;
452 ptr[1] = EIR_NAME_SHORT;
453 } else
454 ptr[1] = EIR_NAME_COMPLETE;
455
456 /* EIR Data length */
457 ptr[0] = name_len + 1;
458
459 memcpy(ptr + 2, hdev->dev_name, name_len);
460
461 eir_len += (name_len + 2);
462 ptr += (name_len + 2);
463 }
464
465 memset(uuid16_list, 0, sizeof(uuid16_list));
466
467 /* Group all UUID16 types */
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200468 list_for_each_entry(uuid, &hdev->uuids, list) {
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300469 u16 uuid16;
470
471 uuid16 = get_uuid16(uuid->uuid);
472 if (uuid16 == 0)
473 return;
474
475 if (uuid16 < 0x1100)
476 continue;
477
478 if (uuid16 == PNP_INFO_SVCLASS_ID)
479 continue;
480
481 /* Stop if not enough space to put next UUID */
482 if (eir_len + 2 + sizeof(u16) > HCI_MAX_EIR_LENGTH) {
483 truncated = 1;
484 break;
485 }
486
487 /* Check for duplicates */
488 for (i = 0; uuid16_list[i] != 0; i++)
489 if (uuid16_list[i] == uuid16)
490 break;
491
492 if (uuid16_list[i] == 0) {
493 uuid16_list[i] = uuid16;
494 eir_len += sizeof(u16);
495 }
496 }
497
498 if (uuid16_list[0] != 0) {
499 u8 *length = ptr;
500
501 /* EIR Data type */
502 ptr[1] = truncated ? EIR_UUID16_SOME : EIR_UUID16_ALL;
503
504 ptr += 2;
505 eir_len += 2;
506
507 for (i = 0; uuid16_list[i] != 0; i++) {
508 *ptr++ = (uuid16_list[i] & 0x00ff);
509 *ptr++ = (uuid16_list[i] & 0xff00) >> 8;
510 }
511
512 /* EIR Data length */
513 *length = (i * sizeof(u16)) + 1;
514 }
515}
516
517static int update_eir(struct hci_dev *hdev)
518{
519 struct hci_cp_write_eir cp;
520
521 if (!(hdev->features[6] & LMP_EXT_INQ))
522 return 0;
523
Johan Hedberg84bde9d2012-01-25 14:21:06 +0200524 if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300525 return 0;
526
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200527 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300528 return 0;
529
530 memset(&cp, 0, sizeof(cp));
531
532 create_eir(hdev, cp.data);
533
534 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
535 return 0;
536
537 memcpy(hdev->eir, cp.data, sizeof(cp.data));
538
539 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
540}
541
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200542static u8 get_service_classes(struct hci_dev *hdev)
543{
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300544 struct bt_uuid *uuid;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200545 u8 val = 0;
546
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300547 list_for_each_entry(uuid, &hdev->uuids, list)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200548 val |= uuid->svc_hint;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200549
550 return val;
551}
552
553static int update_class(struct hci_dev *hdev)
554{
555 u8 cod[3];
556
557 BT_DBG("%s", hdev->name);
558
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200559 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200560 return 0;
561
562 cod[0] = hdev->minor_class;
563 cod[1] = hdev->major_class;
564 cod[2] = get_service_classes(hdev);
565
566 if (memcmp(cod, hdev->dev_class, 3) == 0)
567 return 0;
568
569 return hci_send_cmd(hdev, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
570}
571
Johan Hedberg7d785252011-12-15 00:47:39 +0200572static void service_cache_off(struct work_struct *work)
573{
574 struct hci_dev *hdev = container_of(work, struct hci_dev,
575 service_cache.work);
576
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200577 if (!test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200578 return;
579
580 hci_dev_lock(hdev);
581
582 update_eir(hdev);
583 update_class(hdev);
584
585 hci_dev_unlock(hdev);
586}
587
588static void mgmt_init_hdev(struct hci_dev *hdev)
589{
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200590 if (!test_and_set_bit(HCI_MGMT, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200591 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
592
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200593 if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200594 schedule_delayed_work(&hdev->service_cache,
595 msecs_to_jiffies(SERVICE_CACHE_TIMEOUT));
596}
597
Johan Hedberg03811012010-12-08 00:21:06 +0200598static int read_controller_info(struct sock *sk, u16 index)
599{
600 struct mgmt_rp_read_info rp;
601 struct hci_dev *hdev;
602
603 BT_DBG("sock %p hci%u", sk, index);
604
605 hdev = hci_dev_get(index);
606 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200607 return cmd_status(sk, index, MGMT_OP_READ_INFO,
608 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200609
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200610 if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags))
Johan Hedberg03811012010-12-08 00:21:06 +0200611 cancel_delayed_work_sync(&hdev->power_off);
612
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300613 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200614
Johan Hedberg7d785252011-12-15 00:47:39 +0200615 if (test_and_clear_bit(HCI_PI_MGMT_INIT, &hci_pi(sk)->flags))
616 mgmt_init_hdev(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200617
618 memset(&rp, 0, sizeof(rp));
619
Johan Hedberg03811012010-12-08 00:21:06 +0200620 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200621
622 rp.version = hdev->hci_ver;
623
Johan Hedberg03811012010-12-08 00:21:06 +0200624 put_unaligned_le16(hdev->manufacturer, &rp.manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200625
626 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
627 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
628
629 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedberg03811012010-12-08 00:21:06 +0200630
631 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
632
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300633 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200634 hci_dev_put(hdev);
635
636 return cmd_complete(sk, index, MGMT_OP_READ_INFO, &rp, sizeof(rp));
637}
638
639static void mgmt_pending_free(struct pending_cmd *cmd)
640{
641 sock_put(cmd->sk);
642 kfree(cmd->param);
643 kfree(cmd);
644}
645
646static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
647 struct hci_dev *hdev,
648 void *data, u16 len)
649{
650 struct pending_cmd *cmd;
651
652 cmd = kmalloc(sizeof(*cmd), GFP_ATOMIC);
653 if (!cmd)
654 return NULL;
655
656 cmd->opcode = opcode;
657 cmd->index = hdev->id;
658
659 cmd->param = kmalloc(len, GFP_ATOMIC);
660 if (!cmd->param) {
661 kfree(cmd);
662 return NULL;
663 }
664
665 if (data)
666 memcpy(cmd->param, data, len);
667
668 cmd->sk = sk;
669 sock_hold(sk);
670
671 list_add(&cmd->list, &hdev->mgmt_pending);
672
673 return cmd;
674}
675
676static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
677 void (*cb)(struct pending_cmd *cmd, void *data),
678 void *data)
679{
680 struct list_head *p, *n;
681
682 list_for_each_safe(p, n, &hdev->mgmt_pending) {
683 struct pending_cmd *cmd;
684
685 cmd = list_entry(p, struct pending_cmd, list);
686
687 if (opcode > 0 && cmd->opcode != opcode)
688 continue;
689
690 cb(cmd, data);
691 }
692}
693
694static struct pending_cmd *mgmt_pending_find(u16 opcode, struct hci_dev *hdev)
695{
696 struct pending_cmd *cmd;
697
698 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
699 if (cmd->opcode == opcode)
700 return cmd;
701 }
702
703 return NULL;
704}
705
706static void mgmt_pending_remove(struct pending_cmd *cmd)
707{
708 list_del(&cmd->list);
709 mgmt_pending_free(cmd);
710}
711
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200712static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +0200713{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200714 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +0200715
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200716 return cmd_complete(sk, hdev->id, opcode, &settings, sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +0200717}
718
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300719static int set_powered(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200720{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300721 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200722 struct hci_dev *hdev;
723 struct pending_cmd *cmd;
724 int err, up;
725
Johan Hedberg03811012010-12-08 00:21:06 +0200726 BT_DBG("request for hci%u", index);
727
728 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200729 return cmd_status(sk, index, MGMT_OP_SET_POWERED,
730 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200731
732 hdev = hci_dev_get(index);
733 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200734 return cmd_status(sk, index, MGMT_OP_SET_POWERED,
735 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200736
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300737 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200738
739 up = test_bit(HCI_UP, &hdev->flags);
740 if ((cp->val && up) || (!cp->val && !up)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200741 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200742 goto failed;
743 }
744
745 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200746 err = cmd_status(sk, index, MGMT_OP_SET_POWERED,
747 MGMT_STATUS_BUSY);
Johan Hedberg03811012010-12-08 00:21:06 +0200748 goto failed;
749 }
750
751 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
752 if (!cmd) {
753 err = -ENOMEM;
754 goto failed;
755 }
756
757 if (cp->val)
Gustavo F. Padovan7f971042011-12-18 12:40:32 -0200758 schedule_work(&hdev->power_on);
Johan Hedberg03811012010-12-08 00:21:06 +0200759 else
Gustavo F. Padovan80b7ab32011-12-17 14:52:27 -0200760 schedule_work(&hdev->power_off.work);
Johan Hedberg03811012010-12-08 00:21:06 +0200761
762 err = 0;
763
764failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300765 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200766 hci_dev_put(hdev);
767 return err;
768}
769
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300770static int set_discoverable(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200771{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300772 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberge41d8b42010-12-13 21:07:03 +0200773 struct hci_dev *hdev;
Johan Hedberg03811012010-12-08 00:21:06 +0200774 struct pending_cmd *cmd;
775 u8 scan;
776 int err;
777
Johan Hedberg03811012010-12-08 00:21:06 +0200778 BT_DBG("request for hci%u", index);
779
780 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200781 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
782 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200783
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200784 hdev = hci_dev_get(index);
785 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200786 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
787 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200788
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300789 hci_dev_lock(hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200790
791 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200792 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
793 MGMT_STATUS_NOT_POWERED);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200794 goto failed;
795 }
796
797 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
798 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200799 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
800 MGMT_STATUS_BUSY);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200801 goto failed;
802 }
803
804 if (cp->val == test_bit(HCI_ISCAN, &hdev->flags) &&
805 test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200806 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200807 goto failed;
808 }
809
810 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
811 if (!cmd) {
812 err = -ENOMEM;
813 goto failed;
814 }
815
816 scan = SCAN_PAGE;
817
818 if (cp->val)
819 scan |= SCAN_INQUIRY;
820 else
821 cancel_delayed_work(&hdev->discov_off);
822
823 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
824 if (err < 0)
825 mgmt_pending_remove(cmd);
826
Johan Hedberg03811012010-12-08 00:21:06 +0200827 if (cp->val)
828 hdev->discov_timeout = get_unaligned_le16(&cp->timeout);
829
Johan Hedberge41d8b42010-12-13 21:07:03 +0200830failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300831 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200832 hci_dev_put(hdev);
833
834 return err;
835}
836
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300837static int set_connectable(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200838{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300839 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200840 struct hci_dev *hdev;
841 struct pending_cmd *cmd;
842 u8 scan;
843 int err;
844
Johan Hedberge41d8b42010-12-13 21:07:03 +0200845 BT_DBG("request for hci%u", index);
846
Johan Hedberg03811012010-12-08 00:21:06 +0200847 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200848 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
849 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200850
851 hdev = hci_dev_get(index);
852 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200853 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
854 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200855
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300856 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200857
858 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200859 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
860 MGMT_STATUS_NOT_POWERED);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200861 goto failed;
862 }
863
864 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
865 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200866 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
867 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200868 goto failed;
869 }
870
871 if (cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200872 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200873 goto failed;
874 }
875
876 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
877 if (!cmd) {
878 err = -ENOMEM;
879 goto failed;
880 }
881
882 if (cp->val)
883 scan = SCAN_PAGE;
884 else
885 scan = 0;
886
887 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
888 if (err < 0)
889 mgmt_pending_remove(cmd);
890
891failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300892 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200893 hci_dev_put(hdev);
894
895 return err;
896}
897
898static int mgmt_event(u16 event, struct hci_dev *hdev, void *data,
899 u16 data_len, struct sock *skip_sk)
900{
901 struct sk_buff *skb;
902 struct mgmt_hdr *hdr;
903
904 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_ATOMIC);
905 if (!skb)
906 return -ENOMEM;
907
908 bt_cb(skb)->channel = HCI_CHANNEL_CONTROL;
909
910 hdr = (void *) skb_put(skb, sizeof(*hdr));
911 hdr->opcode = cpu_to_le16(event);
912 if (hdev)
913 hdr->index = cpu_to_le16(hdev->id);
914 else
915 hdr->index = cpu_to_le16(MGMT_INDEX_NONE);
916 hdr->len = cpu_to_le16(data_len);
917
918 if (data)
919 memcpy(skb_put(skb, data_len), data, data_len);
920
921 hci_send_to_sock(NULL, skb, skip_sk);
922 kfree_skb(skb);
923
924 return 0;
925}
926
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300927static int set_pairable(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +0200928{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300929 struct mgmt_mode *cp = data;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200930 struct hci_dev *hdev;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200931 __le32 ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200932 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200933
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200934 BT_DBG("request for hci%u", index);
935
936 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200937 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE,
938 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200939
940 hdev = hci_dev_get(index);
941 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200942 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE,
943 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200944
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300945 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200946
947 if (cp->val)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200948 set_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200949 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200950 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200951
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200952 err = send_settings_rsp(sk, MGMT_OP_SET_PAIRABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200953 if (err < 0)
954 goto failed;
955
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200956 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200957
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200958 err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200959
960failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300961 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200962 hci_dev_put(hdev);
963
964 return err;
965}
Johan Hedberg72a734e2010-12-30 00:38:22 +0200966
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300967static int add_uuid(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200968{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300969 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200970 struct hci_dev *hdev;
971 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200972 int err;
973
Szymon Janc4e51eae2011-02-25 19:05:48 +0100974 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200975
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100976 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200977 return cmd_status(sk, index, MGMT_OP_ADD_UUID,
978 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100979
Szymon Janc4e51eae2011-02-25 19:05:48 +0100980 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200981 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200982 return cmd_status(sk, index, MGMT_OP_ADD_UUID,
983 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200984
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300985 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200986
987 uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC);
988 if (!uuid) {
989 err = -ENOMEM;
990 goto failed;
991 }
992
993 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200994 uuid->svc_hint = cp->svc_hint;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200995
996 list_add(&uuid->list, &hdev->uuids);
997
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200998 err = update_class(hdev);
999 if (err < 0)
1000 goto failed;
1001
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001002 err = update_eir(hdev);
1003 if (err < 0)
1004 goto failed;
1005
Szymon Janc4e51eae2011-02-25 19:05:48 +01001006 err = cmd_complete(sk, index, MGMT_OP_ADD_UUID, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001007
1008failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001009 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001010 hci_dev_put(hdev);
1011
1012 return err;
1013}
1014
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001015static int remove_uuid(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001016{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001017 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001018 struct list_head *p, *n;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001019 struct hci_dev *hdev;
1020 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 +02001021 int err, found;
1022
Szymon Janc4e51eae2011-02-25 19:05:48 +01001023 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001024
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001025 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001026 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
1027 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001028
Szymon Janc4e51eae2011-02-25 19:05:48 +01001029 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001030 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001031 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
1032 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001033
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001034 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001035
1036 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
1037 err = hci_uuids_clear(hdev);
1038 goto unlock;
1039 }
1040
1041 found = 0;
1042
1043 list_for_each_safe(p, n, &hdev->uuids) {
1044 struct bt_uuid *match = list_entry(p, struct bt_uuid, list);
1045
1046 if (memcmp(match->uuid, cp->uuid, 16) != 0)
1047 continue;
1048
1049 list_del(&match->list);
1050 found++;
1051 }
1052
1053 if (found == 0) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001054 err = cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
1055 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001056 goto unlock;
1057 }
1058
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001059 err = update_class(hdev);
1060 if (err < 0)
1061 goto unlock;
1062
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001063 err = update_eir(hdev);
1064 if (err < 0)
1065 goto unlock;
1066
Szymon Janc4e51eae2011-02-25 19:05:48 +01001067 err = cmd_complete(sk, index, MGMT_OP_REMOVE_UUID, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001068
1069unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001070 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001071 hci_dev_put(hdev);
1072
1073 return err;
1074}
1075
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001076static int set_dev_class(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001077{
1078 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001079 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001080 int err;
1081
Szymon Janc4e51eae2011-02-25 19:05:48 +01001082 BT_DBG("request for hci%u", index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001083
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001084 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001085 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS,
1086 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001087
Szymon Janc4e51eae2011-02-25 19:05:48 +01001088 hdev = hci_dev_get(index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001089 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001090 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS,
1091 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001092
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001093 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001094
1095 hdev->major_class = cp->major;
1096 hdev->minor_class = cp->minor;
1097
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001098 if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02001099 hci_dev_unlock(hdev);
1100 cancel_delayed_work_sync(&hdev->service_cache);
1101 hci_dev_lock(hdev);
Johan Hedberg14c0b602011-12-15 00:47:37 +02001102 update_eir(hdev);
Johan Hedberg7d785252011-12-15 00:47:39 +02001103 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02001104
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001105 err = update_class(hdev);
1106
1107 if (err == 0)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001108 err = cmd_complete(sk, index, MGMT_OP_SET_DEV_CLASS, NULL, 0);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001109
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001110 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001111 hci_dev_put(hdev);
1112
1113 return err;
1114}
1115
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001116static int load_link_keys(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001117{
1118 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001119 struct mgmt_cp_load_link_keys *cp = data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001120 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001121 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001122
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001123 if (len < sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001124 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1125 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001126
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001127 key_count = get_unaligned_le16(&cp->key_count);
1128
Johan Hedberg86742e12011-11-07 23:13:38 +02001129 expected_len = sizeof(*cp) + key_count *
1130 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001131 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001132 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001133 len, expected_len);
Johan Hedbergca69b792011-11-11 18:10:00 +02001134 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1135 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001136 }
1137
Szymon Janc4e51eae2011-02-25 19:05:48 +01001138 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001139 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001140 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1141 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001142
Szymon Janc4e51eae2011-02-25 19:05:48 +01001143 BT_DBG("hci%u debug_keys %u key_count %u", index, cp->debug_keys,
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001144 key_count);
1145
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001146 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001147
1148 hci_link_keys_clear(hdev);
1149
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001150 set_bit(HCI_LINK_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001151
1152 if (cp->debug_keys)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001153 set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001154 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001155 clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001156
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001157 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001158 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001159
Johan Hedbergd25e28a2011-04-28 11:28:59 -07001160 hci_add_link_key(hdev, NULL, 0, &key->bdaddr, key->val, key->type,
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001161 key->pin_len);
1162 }
1163
Johan Hedberg0e5f8752011-11-11 16:18:54 +02001164 cmd_complete(sk, index, MGMT_OP_LOAD_LINK_KEYS, NULL, 0);
1165
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001166 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001167 hci_dev_put(hdev);
1168
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001169 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001170}
1171
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001172static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
1173 u8 addr_type, struct sock *skip_sk)
1174{
1175 struct mgmt_ev_device_unpaired ev;
1176
1177 bacpy(&ev.addr.bdaddr, bdaddr);
1178 ev.addr.type = addr_type;
1179
1180 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
1181 skip_sk);
1182}
1183
Johan Hedberg124f6e32012-02-09 13:50:12 +02001184static int unpair_device(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001185{
1186 struct hci_dev *hdev;
Johan Hedberg124f6e32012-02-09 13:50:12 +02001187 struct mgmt_cp_unpair_device *cp = data;
1188 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001189 struct hci_cp_disconnect dc;
1190 struct pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001191 struct hci_conn *conn;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001192 int err;
1193
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001194 if (len != sizeof(*cp))
Johan Hedberg124f6e32012-02-09 13:50:12 +02001195 return cmd_status(sk, index, MGMT_OP_UNPAIR_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02001196 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001197
Szymon Janc4e51eae2011-02-25 19:05:48 +01001198 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001199 if (!hdev)
Johan Hedberg124f6e32012-02-09 13:50:12 +02001200 return cmd_status(sk, index, MGMT_OP_UNPAIR_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02001201 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001202
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001203 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001204
Johan Hedberga8a1d192011-11-10 15:54:38 +02001205 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02001206 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1207 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001208
Johan Hedberg124f6e32012-02-09 13:50:12 +02001209 if (cp->addr.type == MGMT_ADDR_BREDR)
1210 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
1211 else
1212 err = hci_remove_ltk(hdev, &cp->addr.bdaddr);
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03001213
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001214 if (err < 0) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001215 rp.status = MGMT_STATUS_NOT_PAIRED;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001216 goto unlock;
1217 }
1218
Johan Hedberga8a1d192011-11-10 15:54:38 +02001219 if (!test_bit(HCI_UP, &hdev->flags) || !cp->disconnect) {
Johan Hedberg124f6e32012-02-09 13:50:12 +02001220 err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE, &rp,
Johan Hedberga8a1d192011-11-10 15:54:38 +02001221 sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001222 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001223 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001224 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001225
Johan Hedberg124f6e32012-02-09 13:50:12 +02001226 if (cp->addr.type == MGMT_ADDR_BREDR)
1227 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
1228 &cp->addr.bdaddr);
1229 else
1230 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
1231 &cp->addr.bdaddr);
1232
Johan Hedberga8a1d192011-11-10 15:54:38 +02001233 if (!conn) {
Johan Hedberg124f6e32012-02-09 13:50:12 +02001234 err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE, &rp,
Johan Hedberga8a1d192011-11-10 15:54:38 +02001235 sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001236 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001237 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001238 }
1239
Johan Hedberg124f6e32012-02-09 13:50:12 +02001240 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
1241 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02001242 if (!cmd) {
1243 err = -ENOMEM;
1244 goto unlock;
1245 }
1246
1247 put_unaligned_le16(conn->handle, &dc.handle);
1248 dc.reason = 0x13; /* Remote User Terminated Connection */
1249 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1250 if (err < 0)
1251 mgmt_pending_remove(cmd);
1252
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001253unlock:
Johan Hedbergca69b792011-11-11 18:10:00 +02001254 if (err < 0)
Johan Hedberg124f6e32012-02-09 13:50:12 +02001255 err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE, &rp,
Johan Hedberga8a1d192011-11-10 15:54:38 +02001256 sizeof(rp));
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001257 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001258 hci_dev_put(hdev);
1259
1260 return err;
1261}
1262
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001263static int disconnect(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02001264{
1265 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001266 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001267 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03001268 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001269 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001270 int err;
1271
1272 BT_DBG("");
1273
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001274 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001275 return cmd_status(sk, index, MGMT_OP_DISCONNECT,
1276 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001277
Szymon Janc4e51eae2011-02-25 19:05:48 +01001278 hdev = hci_dev_get(index);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001279 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001280 return cmd_status(sk, index, MGMT_OP_DISCONNECT,
1281 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001282
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001283 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001284
1285 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001286 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1287 MGMT_STATUS_NOT_POWERED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001288 goto failed;
1289 }
1290
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001291 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001292 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1293 MGMT_STATUS_BUSY);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001294 goto failed;
1295 }
1296
Johan Hedberg88c3df12012-02-09 14:27:38 +02001297 if (cp->addr.type == MGMT_ADDR_BREDR)
1298 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
1299 else
1300 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03001301
Johan Hedberg8962ee72011-01-20 12:40:27 +02001302 if (!conn) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001303 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1304 MGMT_STATUS_NOT_CONNECTED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001305 goto failed;
1306 }
1307
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001308 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001309 if (!cmd) {
1310 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001311 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001312 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001313
1314 put_unaligned_le16(conn->handle, &dc.handle);
1315 dc.reason = 0x13; /* Remote User Terminated Connection */
1316
1317 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1318 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001319 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001320
1321failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001322 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001323 hci_dev_put(hdev);
1324
1325 return err;
1326}
1327
Johan Hedberg48264f02011-11-09 13:58:58 +02001328static u8 link_to_mgmt(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02001329{
1330 switch (link_type) {
1331 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02001332 switch (addr_type) {
1333 case ADDR_LE_DEV_PUBLIC:
1334 return MGMT_ADDR_LE_PUBLIC;
1335 case ADDR_LE_DEV_RANDOM:
1336 return MGMT_ADDR_LE_RANDOM;
1337 default:
1338 return MGMT_ADDR_INVALID;
1339 }
Johan Hedberg4c659c32011-11-07 23:13:39 +02001340 case ACL_LINK:
1341 return MGMT_ADDR_BREDR;
1342 default:
1343 return MGMT_ADDR_INVALID;
1344 }
1345}
1346
Szymon Janc8ce62842011-03-01 16:55:32 +01001347static int get_connections(struct sock *sk, u16 index)
Johan Hedberg2784eb42011-01-21 13:56:35 +02001348{
Johan Hedberg2784eb42011-01-21 13:56:35 +02001349 struct mgmt_rp_get_connections *rp;
1350 struct hci_dev *hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001351 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02001352 size_t rp_len;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001353 u16 count;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001354 int i, err;
1355
1356 BT_DBG("");
1357
Szymon Janc4e51eae2011-02-25 19:05:48 +01001358 hdev = hci_dev_get(index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001359 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001360 return cmd_status(sk, index, MGMT_OP_GET_CONNECTIONS,
1361 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001362
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001363 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001364
1365 count = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02001366 list_for_each_entry(c, &hdev->conn_hash.list, list) {
1367 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
1368 count++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001369 }
1370
Johan Hedberg4c659c32011-11-07 23:13:39 +02001371 rp_len = sizeof(*rp) + (count * sizeof(struct mgmt_addr_info));
Johan Hedberga38528f2011-01-22 06:46:43 +02001372 rp = kmalloc(rp_len, GFP_ATOMIC);
1373 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02001374 err = -ENOMEM;
1375 goto unlock;
1376 }
1377
Johan Hedberg2784eb42011-01-21 13:56:35 +02001378 put_unaligned_le16(count, &rp->conn_count);
1379
Johan Hedberg2784eb42011-01-21 13:56:35 +02001380 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001381 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02001382 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
1383 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001384 bacpy(&rp->addr[i].bdaddr, &c->dst);
Johan Hedberg48264f02011-11-09 13:58:58 +02001385 rp->addr[i].type = link_to_mgmt(c->type, c->dst_type);
Johan Hedberg4c659c32011-11-07 23:13:39 +02001386 if (rp->addr[i].type == MGMT_ADDR_INVALID)
1387 continue;
1388 i++;
1389 }
1390
1391 /* Recalculate length in case of filtered SCO connections, etc */
1392 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02001393
Szymon Janc4e51eae2011-02-25 19:05:48 +01001394 err = cmd_complete(sk, index, MGMT_OP_GET_CONNECTIONS, rp, rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001395
1396unlock:
Johan Hedberga38528f2011-01-22 06:46:43 +02001397 kfree(rp);
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001398 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001399 hci_dev_put(hdev);
1400 return err;
1401}
1402
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001403static int send_pin_code_neg_reply(struct sock *sk, u16 index,
1404 struct hci_dev *hdev, struct mgmt_cp_pin_code_neg_reply *cp)
1405{
1406 struct pending_cmd *cmd;
1407 int err;
1408
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001409 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001410 sizeof(*cp));
1411 if (!cmd)
1412 return -ENOMEM;
1413
1414 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY, sizeof(cp->bdaddr),
1415 &cp->bdaddr);
1416 if (err < 0)
1417 mgmt_pending_remove(cmd);
1418
1419 return err;
1420}
1421
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001422static int pin_code_reply(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001423{
1424 struct hci_dev *hdev;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001425 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001426 struct mgmt_cp_pin_code_reply *cp = data;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001427 struct mgmt_cp_pin_code_neg_reply ncp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001428 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03001429 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001430 int err;
1431
1432 BT_DBG("");
1433
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001434 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001435 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1436 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001437
Szymon Janc4e51eae2011-02-25 19:05:48 +01001438 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001439 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001440 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1441 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001442
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001443 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001444
1445 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001446 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1447 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001448 goto failed;
1449 }
1450
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001451 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
1452 if (!conn) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001453 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1454 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001455 goto failed;
1456 }
1457
1458 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
1459 bacpy(&ncp.bdaddr, &cp->bdaddr);
1460
1461 BT_ERR("PIN code is not 16 bytes long");
1462
1463 err = send_pin_code_neg_reply(sk, index, hdev, &ncp);
1464 if (err >= 0)
1465 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001466 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001467
1468 goto failed;
1469 }
1470
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001471 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data,
1472 len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001473 if (!cmd) {
1474 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001475 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001476 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02001477
1478 bacpy(&reply.bdaddr, &cp->bdaddr);
1479 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02001480 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02001481
1482 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
1483 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001484 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001485
1486failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001487 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001488 hci_dev_put(hdev);
1489
1490 return err;
1491}
1492
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001493static int pin_code_neg_reply(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001494{
1495 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001496 struct mgmt_cp_pin_code_neg_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001497 int err;
1498
1499 BT_DBG("");
1500
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001501 if (len != sizeof(*cp))
1502 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001503 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001504
Szymon Janc4e51eae2011-02-25 19:05:48 +01001505 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001506 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001507 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001508 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001509
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001510 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001511
1512 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001513 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001514 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001515 goto failed;
1516 }
1517
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001518 err = send_pin_code_neg_reply(sk, index, hdev, cp);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001519
1520failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001521 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001522 hci_dev_put(hdev);
1523
1524 return err;
1525}
1526
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001527static int set_io_capability(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001528{
1529 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001530 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001531
1532 BT_DBG("");
1533
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001534 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001535 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY,
1536 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001537
Szymon Janc4e51eae2011-02-25 19:05:48 +01001538 hdev = hci_dev_get(index);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001539 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001540 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY,
1541 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001542
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001543 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001544
1545 hdev->io_capability = cp->io_capability;
1546
1547 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Szymon Jancb8534e02011-03-01 16:55:34 +01001548 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001549
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001550 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001551 hci_dev_put(hdev);
1552
Szymon Janc4e51eae2011-02-25 19:05:48 +01001553 return cmd_complete(sk, index, MGMT_OP_SET_IO_CAPABILITY, NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001554}
1555
Johan Hedberge9a416b2011-02-19 12:05:56 -03001556static inline struct pending_cmd *find_pairing(struct hci_conn *conn)
1557{
1558 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001559 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001560
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001561 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03001562 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
1563 continue;
1564
Johan Hedberge9a416b2011-02-19 12:05:56 -03001565 if (cmd->user_data != conn)
1566 continue;
1567
1568 return cmd;
1569 }
1570
1571 return NULL;
1572}
1573
1574static void pairing_complete(struct pending_cmd *cmd, u8 status)
1575{
1576 struct mgmt_rp_pair_device rp;
1577 struct hci_conn *conn = cmd->user_data;
1578
Johan Hedbergba4e5642011-11-11 00:07:34 +02001579 bacpy(&rp.addr.bdaddr, &conn->dst);
1580 rp.addr.type = link_to_mgmt(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001581 rp.status = status;
1582
Szymon Janc4e51eae2011-02-25 19:05:48 +01001583 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001584
1585 /* So we don't get further callbacks for this connection */
1586 conn->connect_cfm_cb = NULL;
1587 conn->security_cfm_cb = NULL;
1588 conn->disconn_cfm_cb = NULL;
1589
1590 hci_conn_put(conn);
1591
Johan Hedberga664b5b2011-02-19 12:06:02 -03001592 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001593}
1594
1595static void pairing_complete_cb(struct hci_conn *conn, u8 status)
1596{
1597 struct pending_cmd *cmd;
1598
1599 BT_DBG("status %u", status);
1600
Johan Hedberg56e5cb82011-11-08 20:40:16 +02001601 cmd = find_pairing(conn);
1602 if (!cmd)
1603 BT_DBG("Unable to find a pending command");
1604 else
1605 pairing_complete(cmd, status);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001606}
1607
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001608static int pair_device(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001609{
1610 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001611 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02001612 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001613 struct pending_cmd *cmd;
1614 u8 sec_level, auth_type;
1615 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001616 int err;
1617
1618 BT_DBG("");
1619
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001620 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001621 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE,
1622 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001623
Szymon Janc4e51eae2011-02-25 19:05:48 +01001624 hdev = hci_dev_get(index);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001625 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001626 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE,
1627 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001628
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001629 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001630
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001631 sec_level = BT_SECURITY_MEDIUM;
1632 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001633 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001634 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03001635 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001636
Johan Hedbergba4e5642011-11-11 00:07:34 +02001637 if (cp->addr.type == MGMT_ADDR_BREDR)
1638 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr, sec_level,
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001639 auth_type);
1640 else
Johan Hedbergba4e5642011-11-11 00:07:34 +02001641 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr, sec_level,
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001642 auth_type);
1643
Johan Hedberg1425acb2011-11-11 00:07:35 +02001644 memset(&rp, 0, sizeof(rp));
1645 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1646 rp.addr.type = cp->addr.type;
1647
Ville Tervo30e76272011-02-22 16:10:53 -03001648 if (IS_ERR(conn)) {
Johan Hedberg1425acb2011-11-11 00:07:35 +02001649 rp.status = -PTR_ERR(conn);
1650 err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE,
1651 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001652 goto unlock;
1653 }
1654
1655 if (conn->connect_cfm_cb) {
1656 hci_conn_put(conn);
Johan Hedberg1425acb2011-11-11 00:07:35 +02001657 rp.status = EBUSY;
1658 err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE,
1659 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001660 goto unlock;
1661 }
1662
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001663 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001664 if (!cmd) {
1665 err = -ENOMEM;
1666 hci_conn_put(conn);
1667 goto unlock;
1668 }
1669
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001670 /* For LE, just connecting isn't a proof that the pairing finished */
Johan Hedbergba4e5642011-11-11 00:07:34 +02001671 if (cp->addr.type == MGMT_ADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001672 conn->connect_cfm_cb = pairing_complete_cb;
1673
Johan Hedberge9a416b2011-02-19 12:05:56 -03001674 conn->security_cfm_cb = pairing_complete_cb;
1675 conn->disconn_cfm_cb = pairing_complete_cb;
1676 conn->io_capability = cp->io_cap;
1677 cmd->user_data = conn;
1678
1679 if (conn->state == BT_CONNECTED &&
1680 hci_conn_security(conn, sec_level, auth_type))
1681 pairing_complete(cmd, 0);
1682
1683 err = 0;
1684
1685unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001686 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001687 hci_dev_put(hdev);
1688
1689 return err;
1690}
1691
Johan Hedberg28424702012-02-02 04:02:29 +02001692static int cancel_pair_device(struct sock *sk, u16 index,
1693 unsigned char *data, u16 len)
1694{
1695 struct mgmt_addr_info *addr = (void *) data;
1696 struct hci_dev *hdev;
1697 struct pending_cmd *cmd;
1698 struct hci_conn *conn;
1699 int err;
1700
1701 BT_DBG("");
1702
1703 if (len != sizeof(*addr))
1704 return cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
1705 MGMT_STATUS_INVALID_PARAMS);
1706
1707 hdev = hci_dev_get(index);
1708 if (!hdev)
1709 return cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
1710 MGMT_STATUS_INVALID_PARAMS);
1711
1712 hci_dev_lock(hdev);
1713
1714 cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
1715 if (!cmd) {
1716 err = cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
1717 MGMT_STATUS_INVALID_PARAMS);
1718 goto unlock;
1719 }
1720
1721 conn = cmd->user_data;
1722
1723 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
1724 err = cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
1725 MGMT_STATUS_INVALID_PARAMS);
1726 goto unlock;
1727 }
1728
1729 pairing_complete(cmd, MGMT_STATUS_CANCELLED);
1730
1731 err = cmd_complete(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE, addr,
1732 sizeof(*addr));
1733unlock:
1734 hci_dev_unlock(hdev);
1735 hci_dev_put(hdev);
1736
1737 return err;
1738}
1739
Brian Gix0df4c182011-11-16 13:53:13 -08001740static int user_pairing_resp(struct sock *sk, u16 index, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02001741 u8 type, u16 mgmt_op, u16 hci_op,
1742 __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03001743{
Johan Hedberga5c29682011-02-19 12:05:57 -03001744 struct pending_cmd *cmd;
1745 struct hci_dev *hdev;
Brian Gix0df4c182011-11-16 13:53:13 -08001746 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03001747 int err;
1748
Szymon Janc4e51eae2011-02-25 19:05:48 +01001749 hdev = hci_dev_get(index);
Johan Hedberga5c29682011-02-19 12:05:57 -03001750 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001751 return cmd_status(sk, index, mgmt_op,
1752 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga5c29682011-02-19 12:05:57 -03001753
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001754 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02001755
Johan Hedberga5c29682011-02-19 12:05:57 -03001756 if (!test_bit(HCI_UP, &hdev->flags)) {
Brian Gix0df4c182011-11-16 13:53:13 -08001757 err = cmd_status(sk, index, mgmt_op, MGMT_STATUS_NOT_POWERED);
1758 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03001759 }
1760
Johan Hedberg272d90d2012-02-09 15:26:12 +02001761 if (type == MGMT_ADDR_BREDR)
1762 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, bdaddr);
1763 else
Brian Gix47c15e22011-11-16 13:53:14 -08001764 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, bdaddr);
Brian Gix47c15e22011-11-16 13:53:14 -08001765
Johan Hedberg272d90d2012-02-09 15:26:12 +02001766 if (!conn) {
1767 err = cmd_status(sk, index, mgmt_op,
1768 MGMT_STATUS_NOT_CONNECTED);
1769 goto done;
1770 }
1771
1772 if (type == MGMT_ADDR_LE_PUBLIC || type == MGMT_ADDR_LE_RANDOM) {
Brian Gix47c15e22011-11-16 13:53:14 -08001773 /* Continue with pairing via SMP */
Brian Gix5fe57d92011-12-21 16:12:13 -08001774 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix47c15e22011-11-16 13:53:14 -08001775
Brian Gix5fe57d92011-12-21 16:12:13 -08001776 if (!err)
1777 err = cmd_status(sk, index, mgmt_op,
1778 MGMT_STATUS_SUCCESS);
1779 else
1780 err = cmd_status(sk, index, mgmt_op,
1781 MGMT_STATUS_FAILED);
1782
Brian Gix47c15e22011-11-16 13:53:14 -08001783 goto done;
1784 }
1785
Brian Gix0df4c182011-11-16 13:53:13 -08001786 cmd = mgmt_pending_add(sk, mgmt_op, hdev, bdaddr, sizeof(*bdaddr));
Johan Hedberga5c29682011-02-19 12:05:57 -03001787 if (!cmd) {
1788 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08001789 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03001790 }
1791
Brian Gix0df4c182011-11-16 13:53:13 -08001792 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08001793 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
1794 struct hci_cp_user_passkey_reply cp;
1795
1796 bacpy(&cp.bdaddr, bdaddr);
1797 cp.passkey = passkey;
1798 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
1799 } else
1800 err = hci_send_cmd(hdev, hci_op, sizeof(*bdaddr), bdaddr);
1801
Johan Hedberga664b5b2011-02-19 12:06:02 -03001802 if (err < 0)
1803 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03001804
Brian Gix0df4c182011-11-16 13:53:13 -08001805done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001806 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03001807 hci_dev_put(hdev);
1808
1809 return err;
1810}
1811
Brian Gix0df4c182011-11-16 13:53:13 -08001812static int user_confirm_reply(struct sock *sk, u16 index, void *data, u16 len)
1813{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001814 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08001815
1816 BT_DBG("");
1817
1818 if (len != sizeof(*cp))
1819 return cmd_status(sk, index, MGMT_OP_USER_CONFIRM_REPLY,
1820 MGMT_STATUS_INVALID_PARAMS);
1821
Johan Hedberg272d90d2012-02-09 15:26:12 +02001822 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
1823 MGMT_OP_USER_CONFIRM_REPLY,
1824 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08001825}
1826
1827static int user_confirm_neg_reply(struct sock *sk, u16 index, void *data,
1828 u16 len)
1829{
Johan Hedbergc9c26592011-12-15 00:47:41 +02001830 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08001831
1832 BT_DBG("");
1833
1834 if (len != sizeof(*cp))
1835 return cmd_status(sk, index, MGMT_OP_USER_CONFIRM_NEG_REPLY,
1836 MGMT_STATUS_INVALID_PARAMS);
1837
Johan Hedberg272d90d2012-02-09 15:26:12 +02001838 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
1839 MGMT_OP_USER_CONFIRM_NEG_REPLY,
1840 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08001841}
1842
Brian Gix604086b2011-11-23 08:28:33 -08001843static int user_passkey_reply(struct sock *sk, u16 index, void *data, u16 len)
1844{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001845 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08001846
1847 BT_DBG("");
1848
1849 if (len != sizeof(*cp))
1850 return cmd_status(sk, index, MGMT_OP_USER_PASSKEY_REPLY,
1851 EINVAL);
1852
Johan Hedberg272d90d2012-02-09 15:26:12 +02001853 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
1854 MGMT_OP_USER_PASSKEY_REPLY,
1855 HCI_OP_USER_PASSKEY_REPLY,
1856 cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08001857}
1858
1859static int user_passkey_neg_reply(struct sock *sk, u16 index, void *data,
1860 u16 len)
1861{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001862 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08001863
1864 BT_DBG("");
1865
1866 if (len != sizeof(*cp))
1867 return cmd_status(sk, index, MGMT_OP_USER_PASSKEY_NEG_REPLY,
1868 EINVAL);
1869
Johan Hedberg272d90d2012-02-09 15:26:12 +02001870 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
1871 MGMT_OP_USER_PASSKEY_NEG_REPLY,
1872 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08001873}
1874
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001875static int set_local_name(struct sock *sk, u16 index, void *data,
Johan Hedbergb312b1612011-03-16 14:29:37 +02001876 u16 len)
1877{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001878 struct mgmt_cp_set_local_name *mgmt_cp = data;
Johan Hedbergb312b1612011-03-16 14:29:37 +02001879 struct hci_cp_write_local_name hci_cp;
1880 struct hci_dev *hdev;
1881 struct pending_cmd *cmd;
1882 int err;
1883
1884 BT_DBG("");
1885
1886 if (len != sizeof(*mgmt_cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001887 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME,
1888 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001889
1890 hdev = hci_dev_get(index);
1891 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001892 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME,
1893 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001894
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001895 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001896
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001897 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data,
1898 len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001899 if (!cmd) {
1900 err = -ENOMEM;
1901 goto failed;
1902 }
1903
1904 memcpy(hci_cp.name, mgmt_cp->name, sizeof(hci_cp.name));
1905 err = hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(hci_cp),
1906 &hci_cp);
1907 if (err < 0)
1908 mgmt_pending_remove(cmd);
1909
1910failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001911 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001912 hci_dev_put(hdev);
1913
1914 return err;
1915}
1916
Szymon Jancc35938b2011-03-22 13:12:21 +01001917static int read_local_oob_data(struct sock *sk, u16 index)
1918{
1919 struct hci_dev *hdev;
1920 struct pending_cmd *cmd;
1921 int err;
1922
1923 BT_DBG("hci%u", index);
1924
1925 hdev = hci_dev_get(index);
1926 if (!hdev)
1927 return cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001928 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancc35938b2011-03-22 13:12:21 +01001929
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001930 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01001931
1932 if (!test_bit(HCI_UP, &hdev->flags)) {
1933 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001934 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01001935 goto unlock;
1936 }
1937
1938 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
1939 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001940 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01001941 goto unlock;
1942 }
1943
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001944 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001945 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
1946 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01001947 goto unlock;
1948 }
1949
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001950 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01001951 if (!cmd) {
1952 err = -ENOMEM;
1953 goto unlock;
1954 }
1955
1956 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
1957 if (err < 0)
1958 mgmt_pending_remove(cmd);
1959
1960unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001961 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01001962 hci_dev_put(hdev);
1963
1964 return err;
1965}
1966
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001967static int add_remote_oob_data(struct sock *sk, u16 index, void *data,
1968 u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01001969{
1970 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001971 struct mgmt_cp_add_remote_oob_data *cp = data;
Szymon Janc2763eda2011-03-22 13:12:22 +01001972 int err;
1973
1974 BT_DBG("hci%u ", index);
1975
1976 if (len != sizeof(*cp))
1977 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001978 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01001979
1980 hdev = hci_dev_get(index);
1981 if (!hdev)
1982 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001983 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01001984
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001985 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001986
Johan Hedberg664ce4c2012-02-09 15:44:09 +02001987 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, cp->hash,
Szymon Janc2763eda2011-03-22 13:12:22 +01001988 cp->randomizer);
1989 if (err < 0)
Johan Hedbergca69b792011-11-11 18:10:00 +02001990 err = cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
1991 MGMT_STATUS_FAILED);
Szymon Janc2763eda2011-03-22 13:12:22 +01001992 else
1993 err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, NULL,
1994 0);
1995
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001996 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001997 hci_dev_put(hdev);
1998
1999 return err;
2000}
2001
2002static int remove_remote_oob_data(struct sock *sk, u16 index,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002003 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002004{
2005 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002006 struct mgmt_cp_remove_remote_oob_data *cp = data;
Szymon Janc2763eda2011-03-22 13:12:22 +01002007 int err;
2008
2009 BT_DBG("hci%u ", index);
2010
2011 if (len != sizeof(*cp))
2012 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002013 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01002014
2015 hdev = hci_dev_get(index);
2016 if (!hdev)
2017 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002018 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01002019
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002020 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002021
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002022 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr);
Szymon Janc2763eda2011-03-22 13:12:22 +01002023 if (err < 0)
2024 err = cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002025 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01002026 else
2027 err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2028 NULL, 0);
2029
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002030 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002031 hci_dev_put(hdev);
2032
2033 return err;
2034}
2035
Johan Hedberg450dfda2011-11-12 11:58:22 +02002036static int start_discovery(struct sock *sk, u16 index,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002037 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002038{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002039 struct mgmt_cp_start_discovery *cp = data;
Andre Guedes3fd24152012-02-03 17:48:01 -03002040 unsigned long discov_type = cp->type;
Johan Hedberg14a53662011-04-27 10:29:56 -04002041 struct pending_cmd *cmd;
2042 struct hci_dev *hdev;
2043 int err;
2044
2045 BT_DBG("hci%u", index);
2046
Johan Hedberg450dfda2011-11-12 11:58:22 +02002047 if (len != sizeof(*cp))
2048 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2049 MGMT_STATUS_INVALID_PARAMS);
2050
Johan Hedberg14a53662011-04-27 10:29:56 -04002051 hdev = hci_dev_get(index);
2052 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002053 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2054 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg14a53662011-04-27 10:29:56 -04002055
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002056 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002057
Johan Hedbergbd2d1332011-11-07 23:13:37 +02002058 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02002059 err = cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2060 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02002061 goto failed;
2062 }
2063
Johan Hedbergff9ef572012-01-04 14:23:45 +02002064 if (hdev->discovery.state != DISCOVERY_STOPPED) {
2065 err = cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2066 MGMT_STATUS_BUSY);
2067 goto failed;
2068 }
2069
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002070 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002071 if (!cmd) {
2072 err = -ENOMEM;
2073 goto failed;
2074 }
2075
Andre Guedes3fd24152012-02-03 17:48:01 -03002076 if (test_bit(MGMT_ADDR_BREDR, &discov_type))
2077 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
2078 else if (test_bit(MGMT_ADDR_LE_PUBLIC, &discov_type) &&
2079 test_bit(MGMT_ADDR_LE_RANDOM, &discov_type))
2080 err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT,
2081 LE_SCAN_WIN, LE_SCAN_TIMEOUT_LE_ONLY);
2082 else
2083 err = -EINVAL;
2084
Johan Hedberg14a53662011-04-27 10:29:56 -04002085 if (err < 0)
2086 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002087 else
2088 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002089
2090failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002091 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002092 hci_dev_put(hdev);
2093
2094 return err;
2095}
2096
2097static int stop_discovery(struct sock *sk, u16 index)
2098{
2099 struct hci_dev *hdev;
2100 struct pending_cmd *cmd;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002101 struct hci_cp_remote_name_req_cancel cp;
2102 struct inquiry_entry *e;
Johan Hedberg14a53662011-04-27 10:29:56 -04002103 int err;
2104
2105 BT_DBG("hci%u", index);
2106
2107 hdev = hci_dev_get(index);
2108 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002109 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY,
2110 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg14a53662011-04-27 10:29:56 -04002111
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002112 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002113
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002114 if (!hci_discovery_active(hdev)) {
Johan Hedbergff9ef572012-01-04 14:23:45 +02002115 err = cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY,
2116 MGMT_STATUS_REJECTED);
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002117 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02002118 }
2119
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002120 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002121 if (!cmd) {
2122 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002123 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04002124 }
2125
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002126 if (hdev->discovery.state == DISCOVERY_INQUIRY) {
2127 err = hci_cancel_inquiry(hdev);
2128 if (err < 0)
2129 mgmt_pending_remove(cmd);
2130 else
2131 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
2132 goto unlock;
2133 }
2134
2135 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY, NAME_PENDING);
2136 if (!e) {
2137 mgmt_pending_remove(cmd);
2138 err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY, NULL, 0);
2139 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2140 goto unlock;
2141 }
2142
2143 bacpy(&cp.bdaddr, &e->data.bdaddr);
2144 err = hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ_CANCEL,
2145 sizeof(cp), &cp);
Johan Hedberg14a53662011-04-27 10:29:56 -04002146 if (err < 0)
2147 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002148 else
2149 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002150
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002151unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002152 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002153 hci_dev_put(hdev);
2154
2155 return err;
2156}
2157
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002158static int confirm_name(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02002159{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002160 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002161 struct inquiry_entry *e;
2162 struct hci_dev *hdev;
2163 int err;
2164
2165 BT_DBG("hci%u", index);
2166
2167 if (len != sizeof(*cp))
2168 return cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2169 MGMT_STATUS_INVALID_PARAMS);
2170
2171 hdev = hci_dev_get(index);
2172 if (!hdev)
2173 return cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2174 MGMT_STATUS_INVALID_PARAMS);
2175
2176 hci_dev_lock(hdev);
2177
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002178 if (!hci_discovery_active(hdev)) {
2179 err = cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2180 MGMT_STATUS_FAILED);
2181 goto failed;
2182 }
2183
Johan Hedberg561aafb2012-01-04 13:31:59 +02002184 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->bdaddr);
2185 if (!e) {
2186 err = cmd_status (sk, index, MGMT_OP_CONFIRM_NAME,
2187 MGMT_STATUS_INVALID_PARAMS);
2188 goto failed;
2189 }
2190
2191 if (cp->name_known) {
2192 e->name_state = NAME_KNOWN;
2193 list_del(&e->list);
2194 } else {
2195 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e202012-01-09 00:53:02 +02002196 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002197 }
2198
2199 err = 0;
2200
2201failed:
2202 hci_dev_unlock(hdev);
2203
2204 return err;
2205}
2206
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002207static int block_device(struct sock *sk, u16 index, void *data, u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002208{
2209 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002210 struct mgmt_cp_block_device *cp = data;
Antti Julku7fbec222011-06-15 12:01:15 +03002211 int err;
2212
2213 BT_DBG("hci%u", index);
2214
Antti Julku7fbec222011-06-15 12:01:15 +03002215 if (len != sizeof(*cp))
2216 return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002217 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002218
2219 hdev = hci_dev_get(index);
2220 if (!hdev)
2221 return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002222 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002223
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002224 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002225
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002226 err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002227 if (err < 0)
Johan Hedbergca69b792011-11-11 18:10:00 +02002228 err = cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
2229 MGMT_STATUS_FAILED);
Antti Julku7fbec222011-06-15 12:01:15 +03002230 else
2231 err = cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE,
2232 NULL, 0);
Antti Julku5e762442011-08-25 16:48:02 +03002233
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002234 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002235 hci_dev_put(hdev);
2236
2237 return err;
2238}
2239
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002240static int unblock_device(struct sock *sk, u16 index, void *data, u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002241{
2242 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002243 struct mgmt_cp_unblock_device *cp = data;
Antti Julku7fbec222011-06-15 12:01:15 +03002244 int err;
2245
2246 BT_DBG("hci%u", index);
2247
Antti Julku7fbec222011-06-15 12:01:15 +03002248 if (len != sizeof(*cp))
2249 return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002250 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002251
2252 hdev = hci_dev_get(index);
2253 if (!hdev)
2254 return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002255 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002256
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002257 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002258
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002259 err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002260
2261 if (err < 0)
Johan Hedbergca69b792011-11-11 18:10:00 +02002262 err = cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
2263 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002264 else
2265 err = cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE,
2266 NULL, 0);
Antti Julku5e762442011-08-25 16:48:02 +03002267
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002268 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002269 hci_dev_put(hdev);
2270
2271 return err;
2272}
2273
Antti Julkuf6422ec2011-06-22 13:11:56 +03002274static int set_fast_connectable(struct sock *sk, u16 index,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002275 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03002276{
2277 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002278 struct mgmt_mode *cp = data;
Antti Julkuf6422ec2011-06-22 13:11:56 +03002279 struct hci_cp_write_page_scan_activity acp;
2280 u8 type;
2281 int err;
2282
2283 BT_DBG("hci%u", index);
2284
2285 if (len != sizeof(*cp))
2286 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002287 MGMT_STATUS_INVALID_PARAMS);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002288
2289 hdev = hci_dev_get(index);
2290 if (!hdev)
2291 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002292 MGMT_STATUS_INVALID_PARAMS);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002293
2294 hci_dev_lock(hdev);
2295
Johan Hedbergf7c68692011-12-15 00:47:36 +02002296 if (cp->val) {
Antti Julkuf6422ec2011-06-22 13:11:56 +03002297 type = PAGE_SCAN_TYPE_INTERLACED;
2298 acp.interval = 0x0024; /* 22.5 msec page scan interval */
2299 } else {
2300 type = PAGE_SCAN_TYPE_STANDARD; /* default */
2301 acp.interval = 0x0800; /* default 1.28 sec page scan */
2302 }
2303
2304 acp.window = 0x0012; /* default 11.25 msec page scan window */
2305
2306 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
2307 sizeof(acp), &acp);
2308 if (err < 0) {
2309 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002310 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002311 goto done;
2312 }
2313
2314 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
2315 if (err < 0) {
2316 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002317 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002318 goto done;
2319 }
2320
2321 err = cmd_complete(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
2322 NULL, 0);
2323done:
2324 hci_dev_unlock(hdev);
2325 hci_dev_put(hdev);
2326
2327 return err;
2328}
2329
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002330static int load_long_term_keys(struct sock *sk, u16 index,
2331 void *cp_data, u16 len)
2332{
2333 struct hci_dev *hdev;
2334 struct mgmt_cp_load_long_term_keys *cp = cp_data;
2335 u16 key_count, expected_len;
2336 int i;
2337
2338 if (len < sizeof(*cp))
2339 return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS,
2340 EINVAL);
2341
2342 key_count = get_unaligned_le16(&cp->key_count);
2343
2344 expected_len = sizeof(*cp) + key_count *
2345 sizeof(struct mgmt_ltk_info);
2346 if (expected_len != len) {
2347 BT_ERR("load_keys: expected %u bytes, got %u bytes",
2348 len, expected_len);
2349 return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS,
2350 EINVAL);
2351 }
2352
2353 hdev = hci_dev_get(index);
2354 if (!hdev)
2355 return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS,
2356 ENODEV);
2357
2358 BT_DBG("hci%u key_count %u", index, key_count);
2359
2360 hci_dev_lock(hdev);
2361
2362 hci_smp_ltks_clear(hdev);
2363
2364 for (i = 0; i < key_count; i++) {
2365 struct mgmt_ltk_info *key = &cp->keys[i];
2366 u8 type;
2367
2368 if (key->master)
2369 type = HCI_SMP_LTK;
2370 else
2371 type = HCI_SMP_LTK_SLAVE;
2372
2373 hci_add_ltk(hdev, &key->addr.bdaddr, key->addr.type,
2374 type, 0, key->authenticated, key->val,
2375 key->enc_size, key->ediv, key->rand);
2376 }
2377
2378 hci_dev_unlock(hdev);
2379 hci_dev_put(hdev);
2380
2381 return 0;
2382}
2383
Johan Hedberg03811012010-12-08 00:21:06 +02002384int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
2385{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002386 void *buf;
2387 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02002388 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002389 u16 opcode, index, len;
Johan Hedberg03811012010-12-08 00:21:06 +02002390 int err;
2391
2392 BT_DBG("got %zu bytes", msglen);
2393
2394 if (msglen < sizeof(*hdr))
2395 return -EINVAL;
2396
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03002397 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02002398 if (!buf)
2399 return -ENOMEM;
2400
2401 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
2402 err = -EFAULT;
2403 goto done;
2404 }
2405
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002406 hdr = buf;
Johan Hedberg03811012010-12-08 00:21:06 +02002407 opcode = get_unaligned_le16(&hdr->opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002408 index = get_unaligned_le16(&hdr->index);
Johan Hedberg03811012010-12-08 00:21:06 +02002409 len = get_unaligned_le16(&hdr->len);
2410
2411 if (len != msglen - sizeof(*hdr)) {
2412 err = -EINVAL;
2413 goto done;
2414 }
2415
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002416 cp = buf + sizeof(*hdr);
2417
Johan Hedberg03811012010-12-08 00:21:06 +02002418 switch (opcode) {
Johan Hedberg02d98122010-12-13 21:07:04 +02002419 case MGMT_OP_READ_VERSION:
2420 err = read_version(sk);
2421 break;
Johan Hedberge70bb2e2012-02-13 16:59:33 +02002422 case MGMT_OP_READ_COMMANDS:
2423 err = read_commands(sk);
2424 break;
Johan Hedbergfaba42e2010-12-13 21:07:05 +02002425 case MGMT_OP_READ_INDEX_LIST:
2426 err = read_index_list(sk);
2427 break;
Johan Hedbergf7b64e62010-12-13 21:07:06 +02002428 case MGMT_OP_READ_INFO:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002429 err = read_controller_info(sk, index);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02002430 break;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002431 case MGMT_OP_SET_POWERED:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002432 err = set_powered(sk, index, cp, len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002433 break;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002434 case MGMT_OP_SET_DISCOVERABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002435 err = set_discoverable(sk, index, cp, len);
Johan Hedberg73f22f62010-12-29 16:00:25 +02002436 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002437 case MGMT_OP_SET_CONNECTABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002438 err = set_connectable(sk, index, cp, len);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002439 break;
Johan Hedbergf7c68692011-12-15 00:47:36 +02002440 case MGMT_OP_SET_FAST_CONNECTABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002441 err = set_fast_connectable(sk, index, cp, len);
Johan Hedbergf7c68692011-12-15 00:47:36 +02002442 break;
Johan Hedbergc542a062011-01-26 13:11:03 +02002443 case MGMT_OP_SET_PAIRABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002444 err = set_pairable(sk, index, cp, len);
Johan Hedbergc542a062011-01-26 13:11:03 +02002445 break;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002446 case MGMT_OP_ADD_UUID:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002447 err = add_uuid(sk, index, cp, len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002448 break;
2449 case MGMT_OP_REMOVE_UUID:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002450 err = remove_uuid(sk, index, cp, len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002451 break;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002452 case MGMT_OP_SET_DEV_CLASS:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002453 err = set_dev_class(sk, index, cp, len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002454 break;
Johan Hedberg86742e12011-11-07 23:13:38 +02002455 case MGMT_OP_LOAD_LINK_KEYS:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002456 err = load_link_keys(sk, index, cp, len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002457 break;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002458 case MGMT_OP_DISCONNECT:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002459 err = disconnect(sk, index, cp, len);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002460 break;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002461 case MGMT_OP_GET_CONNECTIONS:
Szymon Janc8ce62842011-03-01 16:55:32 +01002462 err = get_connections(sk, index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002463 break;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002464 case MGMT_OP_PIN_CODE_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002465 err = pin_code_reply(sk, index, cp, len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002466 break;
2467 case MGMT_OP_PIN_CODE_NEG_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002468 err = pin_code_neg_reply(sk, index, cp, len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002469 break;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002470 case MGMT_OP_SET_IO_CAPABILITY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002471 err = set_io_capability(sk, index, cp, len);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002472 break;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002473 case MGMT_OP_PAIR_DEVICE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002474 err = pair_device(sk, index, cp, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002475 break;
Johan Hedberg28424702012-02-02 04:02:29 +02002476 case MGMT_OP_CANCEL_PAIR_DEVICE:
2477 err = cancel_pair_device(sk, index, buf + sizeof(*hdr), len);
2478 break;
Johan Hedberg124f6e32012-02-09 13:50:12 +02002479 case MGMT_OP_UNPAIR_DEVICE:
2480 err = unpair_device(sk, index, cp, len);
2481 break;
Johan Hedberga5c29682011-02-19 12:05:57 -03002482 case MGMT_OP_USER_CONFIRM_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002483 err = user_confirm_reply(sk, index, cp, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03002484 break;
2485 case MGMT_OP_USER_CONFIRM_NEG_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002486 err = user_confirm_neg_reply(sk, index, cp, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03002487 break;
Brian Gix604086b2011-11-23 08:28:33 -08002488 case MGMT_OP_USER_PASSKEY_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002489 err = user_passkey_reply(sk, index, cp, len);
Brian Gix604086b2011-11-23 08:28:33 -08002490 break;
2491 case MGMT_OP_USER_PASSKEY_NEG_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002492 err = user_passkey_neg_reply(sk, index, cp, len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002493 break;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002494 case MGMT_OP_SET_LOCAL_NAME:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002495 err = set_local_name(sk, index, cp, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002496 break;
Szymon Jancc35938b2011-03-22 13:12:21 +01002497 case MGMT_OP_READ_LOCAL_OOB_DATA:
2498 err = read_local_oob_data(sk, index);
2499 break;
Szymon Janc2763eda2011-03-22 13:12:22 +01002500 case MGMT_OP_ADD_REMOTE_OOB_DATA:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002501 err = add_remote_oob_data(sk, index, cp, len);
Szymon Janc2763eda2011-03-22 13:12:22 +01002502 break;
2503 case MGMT_OP_REMOVE_REMOTE_OOB_DATA:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002504 err = remove_remote_oob_data(sk, index, cp, len);
Szymon Janc2763eda2011-03-22 13:12:22 +01002505 break;
Johan Hedberg14a53662011-04-27 10:29:56 -04002506 case MGMT_OP_START_DISCOVERY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002507 err = start_discovery(sk, index, cp, len);
Johan Hedberg14a53662011-04-27 10:29:56 -04002508 break;
2509 case MGMT_OP_STOP_DISCOVERY:
2510 err = stop_discovery(sk, index);
2511 break;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002512 case MGMT_OP_CONFIRM_NAME:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002513 err = confirm_name(sk, index, cp, len);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002514 break;
Antti Julku7fbec222011-06-15 12:01:15 +03002515 case MGMT_OP_BLOCK_DEVICE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002516 err = block_device(sk, index, cp, len);
Antti Julku7fbec222011-06-15 12:01:15 +03002517 break;
2518 case MGMT_OP_UNBLOCK_DEVICE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002519 err = unblock_device(sk, index, cp, len);
Antti Julku7fbec222011-06-15 12:01:15 +03002520 break;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002521 case MGMT_OP_LOAD_LONG_TERM_KEYS:
2522 err = load_long_term_keys(sk, index, cp, len);
2523 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002524 default:
Johan Hedberg72a734e2010-12-30 00:38:22 +02002525 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02002526 err = cmd_status(sk, index, opcode,
2527 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002528 break;
2529 }
Johan Hedberg72a734e2010-12-30 00:38:22 +02002530
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002531 if (err < 0)
Johan Hedberg72a734e2010-12-30 00:38:22 +02002532 goto done;
2533
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002534 err = msglen;
2535
2536done:
2537 kfree(buf);
2538 return err;
2539}
2540
Johan Hedbergb24752f2011-11-03 14:40:33 +02002541static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
2542{
2543 u8 *status = data;
2544
2545 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
2546 mgmt_pending_remove(cmd);
2547}
2548
Johan Hedberg744cf192011-11-08 20:40:14 +02002549int mgmt_index_added(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +02002550{
Johan Hedberg744cf192011-11-08 20:40:14 +02002551 return mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02002552}
2553
Johan Hedberg744cf192011-11-08 20:40:14 +02002554int mgmt_index_removed(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +02002555{
Johan Hedbergb24752f2011-11-03 14:40:33 +02002556 u8 status = ENODEV;
2557
Johan Hedberg744cf192011-11-08 20:40:14 +02002558 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002559
Johan Hedberg744cf192011-11-08 20:40:14 +02002560 return mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02002561}
2562
2563struct cmd_lookup {
2564 u8 val;
2565 struct sock *sk;
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002566 struct hci_dev *hdev;
Johan Hedberg03811012010-12-08 00:21:06 +02002567};
2568
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002569static void settings_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberg03811012010-12-08 00:21:06 +02002570{
Johan Hedberg03811012010-12-08 00:21:06 +02002571 struct cmd_lookup *match = data;
2572
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002573 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02002574
2575 list_del(&cmd->list);
2576
2577 if (match->sk == NULL) {
2578 match->sk = cmd->sk;
2579 sock_hold(match->sk);
2580 }
2581
2582 mgmt_pending_free(cmd);
2583}
2584
Johan Hedberg744cf192011-11-08 20:40:14 +02002585int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg03811012010-12-08 00:21:06 +02002586{
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002587 struct cmd_lookup match = { powered, NULL, hdev };
2588 __le32 ev;
Johan Hedberg03811012010-12-08 00:21:06 +02002589 int ret;
2590
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002591 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
Johan Hedberg03811012010-12-08 00:21:06 +02002592
Johan Hedbergb24752f2011-11-03 14:40:33 +02002593 if (!powered) {
2594 u8 status = ENETDOWN;
Johan Hedberg744cf192011-11-08 20:40:14 +02002595 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002596 }
2597
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002598 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg03811012010-12-08 00:21:06 +02002599
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002600 ret = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev),
2601 match.sk);
Johan Hedberg03811012010-12-08 00:21:06 +02002602
2603 if (match.sk)
2604 sock_put(match.sk);
2605
2606 return ret;
2607}
2608
Johan Hedberg744cf192011-11-08 20:40:14 +02002609int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg03811012010-12-08 00:21:06 +02002610{
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002611 struct cmd_lookup match = { discoverable, NULL, hdev };
2612 __le32 ev;
Johan Hedberg03811012010-12-08 00:21:06 +02002613 int ret;
2614
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002615 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp, &match);
Johan Hedberg03811012010-12-08 00:21:06 +02002616
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002617 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg03811012010-12-08 00:21:06 +02002618
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002619 ret = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01002620 match.sk);
Johan Hedberg03811012010-12-08 00:21:06 +02002621 if (match.sk)
2622 sock_put(match.sk);
2623
2624 return ret;
2625}
2626
Johan Hedberg744cf192011-11-08 20:40:14 +02002627int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg03811012010-12-08 00:21:06 +02002628{
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002629 __le32 ev;
2630 struct cmd_lookup match = { connectable, NULL, hdev };
Johan Hedberg03811012010-12-08 00:21:06 +02002631 int ret;
2632
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002633 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev, settings_rsp,
2634 &match);
Johan Hedberg03811012010-12-08 00:21:06 +02002635
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002636 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg03811012010-12-08 00:21:06 +02002637
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002638 ret = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), match.sk);
Johan Hedberg03811012010-12-08 00:21:06 +02002639
2640 if (match.sk)
2641 sock_put(match.sk);
2642
2643 return ret;
2644}
2645
Johan Hedberg744cf192011-11-08 20:40:14 +02002646int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002647{
Johan Hedbergca69b792011-11-11 18:10:00 +02002648 u8 mgmt_err = mgmt_status(status);
2649
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002650 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02002651 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Johan Hedbergca69b792011-11-11 18:10:00 +02002652 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002653
2654 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02002655 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Johan Hedbergca69b792011-11-11 18:10:00 +02002656 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002657
2658 return 0;
2659}
2660
Johan Hedberg744cf192011-11-08 20:40:14 +02002661int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
2662 u8 persistent)
Johan Hedberg03811012010-12-08 00:21:06 +02002663{
Johan Hedberg86742e12011-11-07 23:13:38 +02002664 struct mgmt_ev_new_link_key ev;
Johan Hedberg03811012010-12-08 00:21:06 +02002665
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002666 memset(&ev, 0, sizeof(ev));
Johan Hedberg03811012010-12-08 00:21:06 +02002667
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002668 ev.store_hint = persistent;
2669 bacpy(&ev.key.bdaddr, &key->bdaddr);
2670 ev.key.type = key->type;
2671 memcpy(ev.key.val, key->val, 16);
2672 ev.key.pin_len = key->pin_len;
Johan Hedberg03811012010-12-08 00:21:06 +02002673
Johan Hedberg744cf192011-11-08 20:40:14 +02002674 return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02002675}
Johan Hedbergf7520542011-01-20 12:34:39 +02002676
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002677int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
2678{
2679 struct mgmt_ev_new_long_term_key ev;
2680
2681 memset(&ev, 0, sizeof(ev));
2682
2683 ev.store_hint = persistent;
2684 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
2685 ev.key.addr.type = key->bdaddr_type;
2686 ev.key.authenticated = key->authenticated;
2687 ev.key.enc_size = key->enc_size;
2688 ev.key.ediv = key->ediv;
2689
2690 if (key->type == HCI_SMP_LTK)
2691 ev.key.master = 1;
2692
2693 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
2694 memcpy(ev.key.val, key->val, sizeof(key->val));
2695
2696 return mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev,
2697 &ev, sizeof(ev), NULL);
2698}
2699
Johan Hedbergafc747a2012-01-15 18:11:07 +02002700int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Johan Hedbergb644ba32012-01-17 21:48:47 +02002701 u8 addr_type, u8 *name, u8 name_len,
2702 u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02002703{
Johan Hedbergb644ba32012-01-17 21:48:47 +02002704 char buf[512];
2705 struct mgmt_ev_device_connected *ev = (void *) buf;
2706 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02002707
Johan Hedbergb644ba32012-01-17 21:48:47 +02002708 bacpy(&ev->addr.bdaddr, bdaddr);
2709 ev->addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02002710
Johan Hedbergb644ba32012-01-17 21:48:47 +02002711 if (name_len > 0)
2712 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
2713 name, name_len);
2714
2715 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
2716 eir_len = eir_append_data(&ev->eir[eir_len], eir_len,
2717 EIR_CLASS_OF_DEV, dev_class, 3);
2718
2719 put_unaligned_le16(eir_len, &ev->eir_len);
2720
2721 return mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
2722 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02002723}
2724
Johan Hedberg8962ee72011-01-20 12:40:27 +02002725static void disconnect_rsp(struct pending_cmd *cmd, void *data)
2726{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01002727 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002728 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02002729 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002730
Johan Hedberg88c3df12012-02-09 14:27:38 +02002731 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2732 rp.addr.type = cp->addr.type;
Johan Hedberg37d9ef72011-11-10 15:54:39 +02002733 rp.status = 0;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002734
Szymon Janc4e51eae2011-02-25 19:05:48 +01002735 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002736
2737 *sk = cmd->sk;
2738 sock_hold(*sk);
2739
Johan Hedberga664b5b2011-02-19 12:06:02 -03002740 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002741}
2742
Johan Hedberg124f6e32012-02-09 13:50:12 +02002743static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02002744{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002745 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02002746 struct mgmt_cp_unpair_device *cp = cmd->param;
2747 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002748
2749 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02002750 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2751 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002752
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002753 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
2754
2755 cmd_complete(cmd->sk, cmd->index, cmd->opcode, &rp, sizeof(rp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02002756
2757 mgmt_pending_remove(cmd);
2758}
2759
Johan Hedbergafc747a2012-01-15 18:11:07 +02002760int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
2761 u8 link_type, u8 addr_type)
Johan Hedbergf7520542011-01-20 12:34:39 +02002762{
Johan Hedberg4c659c32011-11-07 23:13:39 +02002763 struct mgmt_addr_info ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002764 struct sock *sk = NULL;
2765 int err;
2766
Johan Hedberg744cf192011-11-08 20:40:14 +02002767 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02002768
Johan Hedbergf7520542011-01-20 12:34:39 +02002769 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02002770 ev.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02002771
Johan Hedbergafc747a2012-01-15 18:11:07 +02002772 err = mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev),
2773 sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002774
2775 if (sk)
2776 sock_put(sk);
2777
Johan Hedberg124f6e32012-02-09 13:50:12 +02002778 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002779 hdev);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002780
Johan Hedberg8962ee72011-01-20 12:40:27 +02002781 return err;
2782}
2783
Johan Hedberg88c3df12012-02-09 14:27:38 +02002784int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
2785 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02002786{
Johan Hedberg88c3df12012-02-09 14:27:38 +02002787 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002788 struct pending_cmd *cmd;
2789 int err;
2790
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002791 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002792 if (!cmd)
2793 return -ENOENT;
2794
Johan Hedberg88c3df12012-02-09 14:27:38 +02002795 bacpy(&rp.addr.bdaddr, bdaddr);
2796 rp.addr.type = link_to_mgmt(link_type, addr_type);
2797 rp.status = mgmt_status(status);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02002798
Johan Hedberg88c3df12012-02-09 14:27:38 +02002799 err = cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
Johan Hedberg37d9ef72011-11-10 15:54:39 +02002800 &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002801
Johan Hedberga664b5b2011-02-19 12:06:02 -03002802 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002803
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002804 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
2805 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002806 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02002807}
Johan Hedberg17d5c042011-01-22 06:09:08 +02002808
Johan Hedberg48264f02011-11-09 13:58:58 +02002809int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
2810 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02002811{
2812 struct mgmt_ev_connect_failed ev;
2813
Johan Hedberg4c659c32011-11-07 23:13:39 +02002814 bacpy(&ev.addr.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02002815 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02002816 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02002817
Johan Hedberg744cf192011-11-08 20:40:14 +02002818 return mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02002819}
Johan Hedberg980e1a52011-01-22 06:10:07 +02002820
Johan Hedberg744cf192011-11-08 20:40:14 +02002821int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002822{
2823 struct mgmt_ev_pin_code_request ev;
2824
Johan Hedberg980e1a52011-01-22 06:10:07 +02002825 bacpy(&ev.bdaddr, bdaddr);
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02002826 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002827
Johan Hedberg744cf192011-11-08 20:40:14 +02002828 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01002829 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002830}
2831
Johan Hedberg744cf192011-11-08 20:40:14 +02002832int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
2833 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002834{
2835 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002836 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002837 int err;
2838
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002839 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002840 if (!cmd)
2841 return -ENOENT;
2842
Johan Hedbergac56fb12011-02-19 12:05:59 -03002843 bacpy(&rp.bdaddr, bdaddr);
Johan Hedbergca69b792011-11-11 18:10:00 +02002844 rp.status = mgmt_status(status);
Johan Hedbergac56fb12011-02-19 12:05:59 -03002845
Johan Hedberg744cf192011-11-08 20:40:14 +02002846 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY, &rp,
Szymon Janc4e51eae2011-02-25 19:05:48 +01002847 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002848
Johan Hedberga664b5b2011-02-19 12:06:02 -03002849 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002850
2851 return err;
2852}
2853
Johan Hedberg744cf192011-11-08 20:40:14 +02002854int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
2855 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002856{
2857 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002858 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002859 int err;
2860
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002861 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002862 if (!cmd)
2863 return -ENOENT;
2864
Johan Hedbergac56fb12011-02-19 12:05:59 -03002865 bacpy(&rp.bdaddr, bdaddr);
Johan Hedbergca69b792011-11-11 18:10:00 +02002866 rp.status = mgmt_status(status);
Johan Hedbergac56fb12011-02-19 12:05:59 -03002867
Johan Hedberg744cf192011-11-08 20:40:14 +02002868 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY, &rp,
Szymon Janc4e51eae2011-02-25 19:05:48 +01002869 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002870
Johan Hedberga664b5b2011-02-19 12:06:02 -03002871 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002872
2873 return err;
2874}
Johan Hedberga5c29682011-02-19 12:05:57 -03002875
Johan Hedberg744cf192011-11-08 20:40:14 +02002876int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02002877 u8 link_type, u8 addr_type, __le32 value,
2878 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03002879{
2880 struct mgmt_ev_user_confirm_request ev;
2881
Johan Hedberg744cf192011-11-08 20:40:14 +02002882 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03002883
Johan Hedberg272d90d2012-02-09 15:26:12 +02002884 bacpy(&ev.addr.bdaddr, bdaddr);
2885 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07002886 ev.confirm_hint = confirm_hint;
Johan Hedberga5c29682011-02-19 12:05:57 -03002887 put_unaligned_le32(value, &ev.value);
2888
Johan Hedberg744cf192011-11-08 20:40:14 +02002889 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01002890 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03002891}
2892
Johan Hedberg272d90d2012-02-09 15:26:12 +02002893int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
2894 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08002895{
2896 struct mgmt_ev_user_passkey_request ev;
2897
2898 BT_DBG("%s", hdev->name);
2899
Johan Hedberg272d90d2012-02-09 15:26:12 +02002900 bacpy(&ev.addr.bdaddr, bdaddr);
2901 ev.addr.type = link_to_mgmt(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08002902
2903 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
2904 NULL);
2905}
2906
Brian Gix0df4c182011-11-16 13:53:13 -08002907static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02002908 u8 link_type, u8 addr_type, u8 status,
2909 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03002910{
2911 struct pending_cmd *cmd;
2912 struct mgmt_rp_user_confirm_reply rp;
2913 int err;
2914
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002915 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002916 if (!cmd)
2917 return -ENOENT;
2918
Johan Hedberg272d90d2012-02-09 15:26:12 +02002919 bacpy(&rp.addr.bdaddr, bdaddr);
2920 rp.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02002921 rp.status = mgmt_status(status);
Johan Hedberg744cf192011-11-08 20:40:14 +02002922 err = cmd_complete(cmd->sk, hdev->id, opcode, &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03002923
Johan Hedberga664b5b2011-02-19 12:06:02 -03002924 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002925
2926 return err;
2927}
2928
Johan Hedberg744cf192011-11-08 20:40:14 +02002929int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02002930 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03002931{
Johan Hedberg272d90d2012-02-09 15:26:12 +02002932 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
2933 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03002934}
2935
Johan Hedberg272d90d2012-02-09 15:26:12 +02002936int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
2937 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03002938{
Johan Hedberg272d90d2012-02-09 15:26:12 +02002939 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
2940 status, MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03002941}
Johan Hedberg2a611692011-02-19 12:06:00 -03002942
Brian Gix604086b2011-11-23 08:28:33 -08002943int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02002944 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08002945{
Johan Hedberg272d90d2012-02-09 15:26:12 +02002946 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
2947 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08002948}
2949
Johan Hedberg272d90d2012-02-09 15:26:12 +02002950int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
2951 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08002952{
Johan Hedberg272d90d2012-02-09 15:26:12 +02002953 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
2954 status, MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08002955}
2956
Johan Hedbergbab73cb2012-02-09 16:07:29 +02002957int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
2958 u8 addr_type, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03002959{
2960 struct mgmt_ev_auth_failed ev;
2961
Johan Hedbergbab73cb2012-02-09 16:07:29 +02002962 bacpy(&ev.addr.bdaddr, bdaddr);
2963 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02002964 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03002965
Johan Hedberg744cf192011-11-08 20:40:14 +02002966 return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03002967}
Johan Hedbergb312b1612011-03-16 14:29:37 +02002968
Johan Hedberg744cf192011-11-08 20:40:14 +02002969int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02002970{
2971 struct pending_cmd *cmd;
2972 struct mgmt_cp_set_local_name ev;
2973 int err;
2974
2975 memset(&ev, 0, sizeof(ev));
2976 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
2977
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002978 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002979 if (!cmd)
2980 goto send_event;
2981
2982 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02002983 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
Johan Hedbergca69b792011-11-11 18:10:00 +02002984 mgmt_status(status));
Johan Hedbergb312b1612011-03-16 14:29:37 +02002985 goto failed;
2986 }
2987
Johan Hedberg744cf192011-11-08 20:40:14 +02002988 update_eir(hdev);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002989
Johan Hedberg744cf192011-11-08 20:40:14 +02002990 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, &ev,
Johan Hedbergb312b1612011-03-16 14:29:37 +02002991 sizeof(ev));
2992 if (err < 0)
2993 goto failed;
2994
2995send_event:
Johan Hedberg744cf192011-11-08 20:40:14 +02002996 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
Johan Hedbergb312b1612011-03-16 14:29:37 +02002997 cmd ? cmd->sk : NULL);
2998
2999failed:
3000 if (cmd)
3001 mgmt_pending_remove(cmd);
3002 return err;
3003}
Szymon Jancc35938b2011-03-22 13:12:21 +01003004
Johan Hedberg744cf192011-11-08 20:40:14 +02003005int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
3006 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01003007{
3008 struct pending_cmd *cmd;
3009 int err;
3010
Johan Hedberg744cf192011-11-08 20:40:14 +02003011 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01003012
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003013 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003014 if (!cmd)
3015 return -ENOENT;
3016
3017 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02003018 err = cmd_status(cmd->sk, hdev->id,
Johan Hedbergca69b792011-11-11 18:10:00 +02003019 MGMT_OP_READ_LOCAL_OOB_DATA,
3020 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01003021 } else {
3022 struct mgmt_rp_read_local_oob_data rp;
3023
3024 memcpy(rp.hash, hash, sizeof(rp.hash));
3025 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
3026
Johan Hedberg744cf192011-11-08 20:40:14 +02003027 err = cmd_complete(cmd->sk, hdev->id,
3028 MGMT_OP_READ_LOCAL_OOB_DATA,
3029 &rp, sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01003030 }
3031
3032 mgmt_pending_remove(cmd);
3033
3034 return err;
3035}
Johan Hedberge17acd42011-03-30 23:57:16 +03003036
Johan Hedberg48264f02011-11-09 13:58:58 +02003037int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Johan Hedberg561aafb2012-01-04 13:31:59 +02003038 u8 addr_type, u8 *dev_class, s8 rssi,
Johan Hedberge319d2e2012-01-15 19:51:59 +02003039 u8 cfm_name, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03003040{
Johan Hedberge319d2e2012-01-15 19:51:59 +02003041 char buf[512];
3042 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02003043 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03003044
Johan Hedberg1dc06092012-01-15 21:01:23 +02003045 /* Leave 5 bytes for a potential CoD field */
3046 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Andre Guedes7d262f82012-01-10 18:20:49 -03003047 return -EINVAL;
3048
Johan Hedberg1dc06092012-01-15 21:01:23 +02003049 memset(buf, 0, sizeof(buf));
3050
Johan Hedberge319d2e2012-01-15 19:51:59 +02003051 bacpy(&ev->addr.bdaddr, bdaddr);
3052 ev->addr.type = link_to_mgmt(link_type, addr_type);
3053 ev->rssi = rssi;
3054 ev->confirm_name = cfm_name;
Johan Hedberge17acd42011-03-30 23:57:16 +03003055
Johan Hedberg1dc06092012-01-15 21:01:23 +02003056 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02003057 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03003058
Johan Hedberg1dc06092012-01-15 21:01:23 +02003059 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
3060 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
3061 dev_class, 3);
3062
3063 put_unaligned_le16(eir_len, &ev->eir_len);
3064
3065 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03003066
Johan Hedberge319d2e2012-01-15 19:51:59 +02003067 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03003068}
Johan Hedberga88a9652011-03-30 13:18:12 +03003069
Johan Hedbergb644ba32012-01-17 21:48:47 +02003070int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
3071 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03003072{
Johan Hedbergb644ba32012-01-17 21:48:47 +02003073 struct mgmt_ev_device_found *ev;
3074 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
3075 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03003076
Johan Hedbergb644ba32012-01-17 21:48:47 +02003077 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03003078
Johan Hedbergb644ba32012-01-17 21:48:47 +02003079 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03003080
Johan Hedbergb644ba32012-01-17 21:48:47 +02003081 bacpy(&ev->addr.bdaddr, bdaddr);
3082 ev->addr.type = link_to_mgmt(link_type, addr_type);
3083 ev->rssi = rssi;
3084
3085 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
3086 name_len);
3087
3088 put_unaligned_le16(eir_len, &ev->eir_len);
3089
Johan Hedberg053c7e02012-02-04 00:06:00 +02003090 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev,
3091 sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03003092}
Johan Hedberg314b2382011-04-27 10:29:57 -04003093
Andre Guedes7a135102011-11-09 17:14:25 -03003094int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
Johan Hedberg164a6e72011-11-01 17:06:44 +02003095{
3096 struct pending_cmd *cmd;
3097 int err;
3098
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003099 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003100 if (!cmd)
3101 return -ENOENT;
3102
Johan Hedbergca69b792011-11-11 18:10:00 +02003103 err = cmd_status(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status));
Johan Hedberg164a6e72011-11-01 17:06:44 +02003104 mgmt_pending_remove(cmd);
3105
3106 return err;
3107}
3108
Andre Guedese6d465c2011-11-09 17:14:26 -03003109int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
3110{
3111 struct pending_cmd *cmd;
3112 int err;
3113
3114 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
3115 if (!cmd)
3116 return -ENOENT;
3117
Andre Guedese75a8b0c2012-01-02 16:50:53 -03003118 err = cmd_status(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status));
Johan Hedberg03811012010-12-08 00:21:06 +02003119 mgmt_pending_remove(cmd);
3120
3121 return err;
3122}
Johan Hedberg314b2382011-04-27 10:29:57 -04003123
Johan Hedberg744cf192011-11-08 20:40:14 +02003124int mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04003125{
Johan Hedberg164a6e72011-11-01 17:06:44 +02003126 struct pending_cmd *cmd;
3127
Andre Guedes343fb142011-11-22 17:14:19 -03003128 BT_DBG("%s discovering %u", hdev->name, discovering);
3129
Johan Hedberg164a6e72011-11-01 17:06:44 +02003130 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003131 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003132 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003133 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003134
3135 if (cmd != NULL) {
Johan Hedberg744cf192011-11-08 20:40:14 +02003136 cmd_complete(cmd->sk, hdev->id, cmd->opcode, NULL, 0);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003137 mgmt_pending_remove(cmd);
3138 }
3139
Johan Hedberg744cf192011-11-08 20:40:14 +02003140 return mgmt_event(MGMT_EV_DISCOVERING, hdev, &discovering,
Johan Hedberg314b2382011-04-27 10:29:57 -04003141 sizeof(discovering), NULL);
3142}
Antti Julku5e762442011-08-25 16:48:02 +03003143
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003144int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003145{
3146 struct pending_cmd *cmd;
3147 struct mgmt_ev_device_blocked ev;
3148
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003149 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003150
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003151 bacpy(&ev.addr.bdaddr, bdaddr);
3152 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003153
Johan Hedberg744cf192011-11-08 20:40:14 +02003154 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
3155 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003156}
3157
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003158int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003159{
3160 struct pending_cmd *cmd;
3161 struct mgmt_ev_device_unblocked ev;
3162
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003163 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003164
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003165 bacpy(&ev.addr.bdaddr, bdaddr);
3166 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003167
Johan Hedberg744cf192011-11-08 20:40:14 +02003168 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
3169 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003170}