blob: 93f2c1348add2930ed631e4dba2d1f8b205210f5 [file] [log] [blame]
Johan Hedberg03811012010-12-08 00:21:06 +02001/*
2 BlueZ - Bluetooth protocol stack for Linux
Johan Hedbergea585ab2012-02-17 14:50:39 +02003
Johan Hedberg03811012010-12-08 00:21:06 +02004 Copyright (C) 2010 Nokia Corporation
Johan Hedbergea585ab2012-02-17 14:50:39 +02005 Copyright (C) 2011-2012 Intel Corporation
Johan Hedberg03811012010-12-08 00:21:06 +02006
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License version 2 as
9 published by the Free Software Foundation;
10
11 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
12 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
13 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
14 IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
15 CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
16 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19
20 ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
21 COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
22 SOFTWARE IS DISCLAIMED.
23*/
24
25/* Bluetooth HCI Management interface */
26
Johan Hedbergca69b792011-11-11 18:10:00 +020027#include <linux/kernel.h>
Szymon Janc72359752011-02-17 14:16:32 +010028#include <linux/uaccess.h>
Paul Gortmaker3a9a2312011-05-27 09:12:25 -040029#include <linux/module.h>
Johan Hedberg03811012010-12-08 00:21:06 +020030#include <asm/unaligned.h>
31
32#include <net/bluetooth/bluetooth.h>
33#include <net/bluetooth/hci_core.h>
34#include <net/bluetooth/mgmt.h>
Brian Gix5fe57d92011-12-21 16:12:13 -080035#include <net/bluetooth/smp.h>
Johan Hedberg03811012010-12-08 00:21:06 +020036
Marcel Holtmannd7b7e792012-02-20 21:47:49 +010037bool enable_hs;
38bool enable_le;
39
Johan Hedberg2da9c552012-02-17 14:39:28 +020040#define MGMT_VERSION 1
41#define MGMT_REVISION 0
Johan Hedberg02d98122010-12-13 21:07:04 +020042
Johan Hedberge70bb2e2012-02-13 16:59:33 +020043static const u16 mgmt_commands[] = {
44 MGMT_OP_READ_INDEX_LIST,
45 MGMT_OP_READ_INFO,
46 MGMT_OP_SET_POWERED,
47 MGMT_OP_SET_DISCOVERABLE,
48 MGMT_OP_SET_CONNECTABLE,
49 MGMT_OP_SET_FAST_CONNECTABLE,
50 MGMT_OP_SET_PAIRABLE,
51 MGMT_OP_SET_LINK_SECURITY,
52 MGMT_OP_SET_SSP,
53 MGMT_OP_SET_HS,
54 MGMT_OP_SET_LE,
55 MGMT_OP_SET_DEV_CLASS,
56 MGMT_OP_SET_LOCAL_NAME,
57 MGMT_OP_ADD_UUID,
58 MGMT_OP_REMOVE_UUID,
59 MGMT_OP_LOAD_LINK_KEYS,
60 MGMT_OP_LOAD_LONG_TERM_KEYS,
61 MGMT_OP_DISCONNECT,
62 MGMT_OP_GET_CONNECTIONS,
63 MGMT_OP_PIN_CODE_REPLY,
64 MGMT_OP_PIN_CODE_NEG_REPLY,
65 MGMT_OP_SET_IO_CAPABILITY,
66 MGMT_OP_PAIR_DEVICE,
67 MGMT_OP_CANCEL_PAIR_DEVICE,
68 MGMT_OP_UNPAIR_DEVICE,
69 MGMT_OP_USER_CONFIRM_REPLY,
70 MGMT_OP_USER_CONFIRM_NEG_REPLY,
71 MGMT_OP_USER_PASSKEY_REPLY,
72 MGMT_OP_USER_PASSKEY_NEG_REPLY,
73 MGMT_OP_READ_LOCAL_OOB_DATA,
74 MGMT_OP_ADD_REMOTE_OOB_DATA,
75 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
76 MGMT_OP_START_DISCOVERY,
77 MGMT_OP_STOP_DISCOVERY,
78 MGMT_OP_CONFIRM_NAME,
79 MGMT_OP_BLOCK_DEVICE,
80 MGMT_OP_UNBLOCK_DEVICE,
81};
82
83static const u16 mgmt_events[] = {
84 MGMT_EV_CONTROLLER_ERROR,
85 MGMT_EV_INDEX_ADDED,
86 MGMT_EV_INDEX_REMOVED,
87 MGMT_EV_NEW_SETTINGS,
88 MGMT_EV_CLASS_OF_DEV_CHANGED,
89 MGMT_EV_LOCAL_NAME_CHANGED,
90 MGMT_EV_NEW_LINK_KEY,
91 MGMT_EV_NEW_LONG_TERM_KEY,
92 MGMT_EV_DEVICE_CONNECTED,
93 MGMT_EV_DEVICE_DISCONNECTED,
94 MGMT_EV_CONNECT_FAILED,
95 MGMT_EV_PIN_CODE_REQUEST,
96 MGMT_EV_USER_CONFIRM_REQUEST,
97 MGMT_EV_USER_PASSKEY_REQUEST,
98 MGMT_EV_AUTH_FAILED,
99 MGMT_EV_DEVICE_FOUND,
100 MGMT_EV_DISCOVERING,
101 MGMT_EV_DEVICE_BLOCKED,
102 MGMT_EV_DEVICE_UNBLOCKED,
103 MGMT_EV_DEVICE_UNPAIRED,
104};
105
Andre Guedes3fd24152012-02-03 17:48:01 -0300106/*
107 * These LE scan and inquiry parameters were chosen according to LE General
108 * Discovery Procedure specification.
109 */
110#define LE_SCAN_TYPE 0x01
111#define LE_SCAN_WIN 0x12
112#define LE_SCAN_INT 0x12
113#define LE_SCAN_TIMEOUT_LE_ONLY 10240 /* TGAP(gen_disc_scan_min) */
Andre Guedes5e0452c2012-02-17 20:39:38 -0300114#define LE_SCAN_TIMEOUT_BREDR_LE 5120 /* TGAP(100)/2 */
Andre Guedes3fd24152012-02-03 17:48:01 -0300115
Andre Guedese8777522012-02-03 17:48:02 -0300116#define INQUIRY_LEN_BREDR 0x08 /* TGAP(100) */
Andre Guedes5e0452c2012-02-17 20:39:38 -0300117#define INQUIRY_LEN_BREDR_LE 0x04 /* TGAP(100)/2 */
Andre Guedes2519a1f2011-11-07 11:45:24 -0300118
Johan Hedberg7d785252011-12-15 00:47:39 +0200119#define SERVICE_CACHE_TIMEOUT (5 * 1000)
120
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200121#define hdev_is_powered(hdev) (test_bit(HCI_UP, &hdev->flags) && \
122 !test_bit(HCI_AUTO_OFF, &hdev->dev_flags))
123
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200124struct pending_cmd {
125 struct list_head list;
Johan Hedbergfc2f4b12011-11-09 13:58:56 +0200126 u16 opcode;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200127 int index;
Szymon Jancc68fb7f2011-03-22 13:12:19 +0100128 void *param;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200129 struct sock *sk;
Johan Hedberge9a416b2011-02-19 12:05:56 -0300130 void *user_data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200131};
132
Johan Hedbergca69b792011-11-11 18:10:00 +0200133/* HCI to MGMT error code conversion table */
134static u8 mgmt_status_table[] = {
135 MGMT_STATUS_SUCCESS,
136 MGMT_STATUS_UNKNOWN_COMMAND, /* Unknown Command */
137 MGMT_STATUS_NOT_CONNECTED, /* No Connection */
138 MGMT_STATUS_FAILED, /* Hardware Failure */
139 MGMT_STATUS_CONNECT_FAILED, /* Page Timeout */
140 MGMT_STATUS_AUTH_FAILED, /* Authentication Failed */
141 MGMT_STATUS_NOT_PAIRED, /* PIN or Key Missing */
142 MGMT_STATUS_NO_RESOURCES, /* Memory Full */
143 MGMT_STATUS_TIMEOUT, /* Connection Timeout */
144 MGMT_STATUS_NO_RESOURCES, /* Max Number of Connections */
145 MGMT_STATUS_NO_RESOURCES, /* Max Number of SCO Connections */
146 MGMT_STATUS_ALREADY_CONNECTED, /* ACL Connection Exists */
147 MGMT_STATUS_BUSY, /* Command Disallowed */
148 MGMT_STATUS_NO_RESOURCES, /* Rejected Limited Resources */
149 MGMT_STATUS_REJECTED, /* Rejected Security */
150 MGMT_STATUS_REJECTED, /* Rejected Personal */
151 MGMT_STATUS_TIMEOUT, /* Host Timeout */
152 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Feature */
153 MGMT_STATUS_INVALID_PARAMS, /* Invalid Parameters */
154 MGMT_STATUS_DISCONNECTED, /* OE User Ended Connection */
155 MGMT_STATUS_NO_RESOURCES, /* OE Low Resources */
156 MGMT_STATUS_DISCONNECTED, /* OE Power Off */
157 MGMT_STATUS_DISCONNECTED, /* Connection Terminated */
158 MGMT_STATUS_BUSY, /* Repeated Attempts */
159 MGMT_STATUS_REJECTED, /* Pairing Not Allowed */
160 MGMT_STATUS_FAILED, /* Unknown LMP PDU */
161 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Remote Feature */
162 MGMT_STATUS_REJECTED, /* SCO Offset Rejected */
163 MGMT_STATUS_REJECTED, /* SCO Interval Rejected */
164 MGMT_STATUS_REJECTED, /* Air Mode Rejected */
165 MGMT_STATUS_INVALID_PARAMS, /* Invalid LMP Parameters */
166 MGMT_STATUS_FAILED, /* Unspecified Error */
167 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported LMP Parameter Value */
168 MGMT_STATUS_FAILED, /* Role Change Not Allowed */
169 MGMT_STATUS_TIMEOUT, /* LMP Response Timeout */
170 MGMT_STATUS_FAILED, /* LMP Error Transaction Collision */
171 MGMT_STATUS_FAILED, /* LMP PDU Not Allowed */
172 MGMT_STATUS_REJECTED, /* Encryption Mode Not Accepted */
173 MGMT_STATUS_FAILED, /* Unit Link Key Used */
174 MGMT_STATUS_NOT_SUPPORTED, /* QoS Not Supported */
175 MGMT_STATUS_TIMEOUT, /* Instant Passed */
176 MGMT_STATUS_NOT_SUPPORTED, /* Pairing Not Supported */
177 MGMT_STATUS_FAILED, /* Transaction Collision */
178 MGMT_STATUS_INVALID_PARAMS, /* Unacceptable Parameter */
179 MGMT_STATUS_REJECTED, /* QoS Rejected */
180 MGMT_STATUS_NOT_SUPPORTED, /* Classification Not Supported */
181 MGMT_STATUS_REJECTED, /* Insufficient Security */
182 MGMT_STATUS_INVALID_PARAMS, /* Parameter Out Of Range */
183 MGMT_STATUS_BUSY, /* Role Switch Pending */
184 MGMT_STATUS_FAILED, /* Slot Violation */
185 MGMT_STATUS_FAILED, /* Role Switch Failed */
186 MGMT_STATUS_INVALID_PARAMS, /* EIR Too Large */
187 MGMT_STATUS_NOT_SUPPORTED, /* Simple Pairing Not Supported */
188 MGMT_STATUS_BUSY, /* Host Busy Pairing */
189 MGMT_STATUS_REJECTED, /* Rejected, No Suitable Channel */
190 MGMT_STATUS_BUSY, /* Controller Busy */
191 MGMT_STATUS_INVALID_PARAMS, /* Unsuitable Connection Interval */
192 MGMT_STATUS_TIMEOUT, /* Directed Advertising Timeout */
193 MGMT_STATUS_AUTH_FAILED, /* Terminated Due to MIC Failure */
194 MGMT_STATUS_CONNECT_FAILED, /* Connection Establishment Failed */
195 MGMT_STATUS_CONNECT_FAILED, /* MAC Connection Failed */
196};
197
198static u8 mgmt_status(u8 hci_status)
199{
200 if (hci_status < ARRAY_SIZE(mgmt_status_table))
201 return mgmt_status_table[hci_status];
202
203 return MGMT_STATUS_FAILED;
204}
205
Szymon Janc4e51eae2011-02-25 19:05:48 +0100206static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200207{
208 struct sk_buff *skb;
209 struct mgmt_hdr *hdr;
210 struct mgmt_ev_cmd_status *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300211 int err;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200212
Szymon Janc34eb5252011-02-28 14:10:08 +0100213 BT_DBG("sock %p, index %u, cmd %u, status %u", sk, index, cmd, status);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200214
215 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_ATOMIC);
216 if (!skb)
217 return -ENOMEM;
218
219 hdr = (void *) skb_put(skb, sizeof(*hdr));
220
221 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_STATUS);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100222 hdr->index = cpu_to_le16(index);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200223 hdr->len = cpu_to_le16(sizeof(*ev));
224
225 ev = (void *) skb_put(skb, sizeof(*ev));
226 ev->status = status;
227 put_unaligned_le16(cmd, &ev->opcode);
228
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300229 err = sock_queue_rcv_skb(sk, skb);
230 if (err < 0)
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200231 kfree_skb(skb);
232
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300233 return err;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200234}
235
Johan Hedbergaee9b212012-02-18 15:07:59 +0200236static int cmd_complete(struct sock *sk, u16 index, u16 cmd, u8 status,
237 void *rp, size_t rp_len)
Johan Hedberg02d98122010-12-13 21:07:04 +0200238{
239 struct sk_buff *skb;
240 struct mgmt_hdr *hdr;
241 struct mgmt_ev_cmd_complete *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300242 int err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200243
244 BT_DBG("sock %p", sk);
245
Johan Hedberga38528f2011-01-22 06:46:43 +0200246 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + rp_len, GFP_ATOMIC);
Johan Hedberg02d98122010-12-13 21:07:04 +0200247 if (!skb)
248 return -ENOMEM;
249
250 hdr = (void *) skb_put(skb, sizeof(*hdr));
Johan Hedberga38528f2011-01-22 06:46:43 +0200251
Johan Hedberg02d98122010-12-13 21:07:04 +0200252 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100253 hdr->index = cpu_to_le16(index);
Johan Hedberga38528f2011-01-22 06:46:43 +0200254 hdr->len = cpu_to_le16(sizeof(*ev) + rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200255
Johan Hedberga38528f2011-01-22 06:46:43 +0200256 ev = (void *) skb_put(skb, sizeof(*ev) + rp_len);
257 put_unaligned_le16(cmd, &ev->opcode);
Johan Hedbergaee9b212012-02-18 15:07:59 +0200258 ev->status = status;
Szymon Janc8020c162011-02-28 14:09:50 +0100259
260 if (rp)
261 memcpy(ev->data, rp, rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200262
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300263 err = sock_queue_rcv_skb(sk, skb);
264 if (err < 0)
Johan Hedberg02d98122010-12-13 21:07:04 +0200265 kfree_skb(skb);
266
Marcel Holtmanne5f0e152012-02-22 11:59:01 +0100267 return err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200268}
269
Johan Hedberga38528f2011-01-22 06:46:43 +0200270static int read_version(struct sock *sk)
271{
272 struct mgmt_rp_read_version rp;
273
274 BT_DBG("sock %p", sk);
275
276 rp.version = MGMT_VERSION;
277 put_unaligned_le16(MGMT_REVISION, &rp.revision);
278
Johan Hedbergaee9b212012-02-18 15:07:59 +0200279 return cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, 0, &rp,
Szymon Janc4e51eae2011-02-25 19:05:48 +0100280 sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200281}
282
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200283static int read_commands(struct sock *sk)
284{
285 struct mgmt_rp_read_commands *rp;
286 u16 num_commands = ARRAY_SIZE(mgmt_commands);
287 u16 num_events = ARRAY_SIZE(mgmt_events);
288 u16 *opcode;
289 size_t rp_size;
290 int i, err;
291
292 BT_DBG("sock %p", sk);
293
294 rp_size = sizeof(*rp) + ((num_commands + num_events) * sizeof(u16));
295
296 rp = kmalloc(rp_size, GFP_KERNEL);
297 if (!rp)
298 return -ENOMEM;
299
300 put_unaligned_le16(num_commands, &rp->num_commands);
301 put_unaligned_le16(num_events, &rp->num_events);
302
303 for (i = 0, opcode = rp->opcodes; i < num_commands; i++, opcode++)
304 put_unaligned_le16(mgmt_commands[i], opcode);
305
306 for (i = 0; i < num_events; i++, opcode++)
307 put_unaligned_le16(mgmt_events[i], opcode);
308
Johan Hedbergaee9b212012-02-18 15:07:59 +0200309 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_COMMANDS, 0, rp,
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200310 rp_size);
311 kfree(rp);
312
313 return err;
314}
315
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200316static int read_index_list(struct sock *sk)
317{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200318 struct mgmt_rp_read_index_list *rp;
319 struct list_head *p;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200320 struct hci_dev *d;
Johan Hedberga38528f2011-01-22 06:46:43 +0200321 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200322 u16 count;
Johan Hedberga38528f2011-01-22 06:46:43 +0200323 int i, err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200324
325 BT_DBG("sock %p", sk);
326
327 read_lock(&hci_dev_list_lock);
328
329 count = 0;
330 list_for_each(p, &hci_dev_list) {
331 count++;
332 }
333
Johan Hedberga38528f2011-01-22 06:46:43 +0200334 rp_len = sizeof(*rp) + (2 * count);
335 rp = kmalloc(rp_len, GFP_ATOMIC);
336 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100337 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200338 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100339 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200340
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200341 put_unaligned_le16(count, &rp->num_controllers);
342
343 i = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200344 list_for_each_entry(d, &hci_dev_list, list) {
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200345 if (test_bit(HCI_SETUP, &d->dev_flags))
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200346 continue;
347
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200348 put_unaligned_le16(d->id, &rp->index[i++]);
349 BT_DBG("Added hci%u", d->id);
350 }
351
352 read_unlock(&hci_dev_list_lock);
353
Johan Hedbergaee9b212012-02-18 15:07:59 +0200354 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST, 0, rp,
Szymon Janc4e51eae2011-02-25 19:05:48 +0100355 rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200356
Johan Hedberga38528f2011-01-22 06:46:43 +0200357 kfree(rp);
358
359 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200360}
361
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200362static u32 get_supported_settings(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +0200363{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200364 u32 settings = 0;
Johan Hedberg03811012010-12-08 00:21:06 +0200365
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200366 settings |= MGMT_SETTING_POWERED;
367 settings |= MGMT_SETTING_CONNECTABLE;
368 settings |= MGMT_SETTING_FAST_CONNECTABLE;
369 settings |= MGMT_SETTING_DISCOVERABLE;
370 settings |= MGMT_SETTING_PAIRABLE;
Johan Hedberg03811012010-12-08 00:21:06 +0200371
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200372 if (hdev->features[6] & LMP_SIMPLE_PAIR)
373 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200374
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200375 if (!(hdev->features[4] & LMP_NO_BREDR)) {
376 settings |= MGMT_SETTING_BREDR;
377 settings |= MGMT_SETTING_LINK_SECURITY;
378 }
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200379
Marcel Holtmannd7b7e792012-02-20 21:47:49 +0100380 if (enable_hs)
381 settings |= MGMT_SETTING_HS;
382
383 if (enable_le) {
384 if (hdev->features[4] & LMP_LE)
385 settings |= MGMT_SETTING_LE;
386 }
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200387
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200388 return settings;
389}
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200390
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200391static u32 get_current_settings(struct hci_dev *hdev)
392{
393 u32 settings = 0;
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200394
Johan Hedbergf1f0eb02012-02-21 17:15:41 +0200395 if (hdev_is_powered(hdev))
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100396 settings |= MGMT_SETTING_POWERED;
397
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200398 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200399 settings |= MGMT_SETTING_CONNECTABLE;
400
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200401 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200402 settings |= MGMT_SETTING_DISCOVERABLE;
403
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200404 if (test_bit(HCI_PAIRABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200405 settings |= MGMT_SETTING_PAIRABLE;
406
407 if (!(hdev->features[4] & LMP_NO_BREDR))
408 settings |= MGMT_SETTING_BREDR;
409
Johan Hedberg06199cf2012-02-22 16:37:11 +0200410 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200411 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200412
Johan Hedberg47990ea2012-02-22 11:58:37 +0200413 if (test_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200414 settings |= MGMT_SETTING_LINK_SECURITY;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200415
Johan Hedberg84bde9d6c2012-01-25 14:21:06 +0200416 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200417 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200418
Johan Hedberg6d80dfd2012-02-20 23:50:38 +0200419 if (test_bit(HCI_HS_ENABLED, &hdev->dev_flags))
420 settings |= MGMT_SETTING_HS;
421
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200422 return settings;
Johan Hedbergc542a062011-01-26 13:11:03 +0200423}
424
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300425#define PNP_INFO_SVCLASS_ID 0x1200
426
427static u8 bluetooth_base_uuid[] = {
428 0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80,
429 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
430};
431
432static u16 get_uuid16(u8 *uuid128)
433{
434 u32 val;
435 int i;
436
437 for (i = 0; i < 12; i++) {
438 if (bluetooth_base_uuid[i] != uuid128[i])
439 return 0;
440 }
441
442 memcpy(&val, &uuid128[12], 4);
443
444 val = le32_to_cpu(val);
445 if (val > 0xffff)
446 return 0;
447
448 return (u16) val;
449}
450
451static void create_eir(struct hci_dev *hdev, u8 *data)
452{
453 u8 *ptr = data;
454 u16 eir_len = 0;
455 u16 uuid16_list[HCI_MAX_EIR_LENGTH / sizeof(u16)];
456 int i, truncated = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200457 struct bt_uuid *uuid;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300458 size_t name_len;
459
460 name_len = strlen(hdev->dev_name);
461
462 if (name_len > 0) {
463 /* EIR Data type */
464 if (name_len > 48) {
465 name_len = 48;
466 ptr[1] = EIR_NAME_SHORT;
467 } else
468 ptr[1] = EIR_NAME_COMPLETE;
469
470 /* EIR Data length */
471 ptr[0] = name_len + 1;
472
473 memcpy(ptr + 2, hdev->dev_name, name_len);
474
475 eir_len += (name_len + 2);
476 ptr += (name_len + 2);
477 }
478
479 memset(uuid16_list, 0, sizeof(uuid16_list));
480
481 /* Group all UUID16 types */
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200482 list_for_each_entry(uuid, &hdev->uuids, list) {
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300483 u16 uuid16;
484
485 uuid16 = get_uuid16(uuid->uuid);
486 if (uuid16 == 0)
487 return;
488
489 if (uuid16 < 0x1100)
490 continue;
491
492 if (uuid16 == PNP_INFO_SVCLASS_ID)
493 continue;
494
495 /* Stop if not enough space to put next UUID */
496 if (eir_len + 2 + sizeof(u16) > HCI_MAX_EIR_LENGTH) {
497 truncated = 1;
498 break;
499 }
500
501 /* Check for duplicates */
502 for (i = 0; uuid16_list[i] != 0; i++)
503 if (uuid16_list[i] == uuid16)
504 break;
505
506 if (uuid16_list[i] == 0) {
507 uuid16_list[i] = uuid16;
508 eir_len += sizeof(u16);
509 }
510 }
511
512 if (uuid16_list[0] != 0) {
513 u8 *length = ptr;
514
515 /* EIR Data type */
516 ptr[1] = truncated ? EIR_UUID16_SOME : EIR_UUID16_ALL;
517
518 ptr += 2;
519 eir_len += 2;
520
521 for (i = 0; uuid16_list[i] != 0; i++) {
522 *ptr++ = (uuid16_list[i] & 0x00ff);
523 *ptr++ = (uuid16_list[i] & 0xff00) >> 8;
524 }
525
526 /* EIR Data length */
527 *length = (i * sizeof(u16)) + 1;
528 }
529}
530
531static int update_eir(struct hci_dev *hdev)
532{
533 struct hci_cp_write_eir cp;
534
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200535 if (!hdev_is_powered(hdev))
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200536 return 0;
537
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300538 if (!(hdev->features[6] & LMP_EXT_INQ))
539 return 0;
540
Johan Hedberg84bde9d6c2012-01-25 14:21:06 +0200541 if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300542 return 0;
543
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200544 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300545 return 0;
546
547 memset(&cp, 0, sizeof(cp));
548
549 create_eir(hdev, cp.data);
550
551 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
552 return 0;
553
554 memcpy(hdev->eir, cp.data, sizeof(cp.data));
555
556 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
557}
558
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200559static u8 get_service_classes(struct hci_dev *hdev)
560{
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300561 struct bt_uuid *uuid;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200562 u8 val = 0;
563
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300564 list_for_each_entry(uuid, &hdev->uuids, list)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200565 val |= uuid->svc_hint;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200566
567 return val;
568}
569
570static int update_class(struct hci_dev *hdev)
571{
572 u8 cod[3];
573
574 BT_DBG("%s", hdev->name);
575
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200576 if (!hdev_is_powered(hdev))
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200577 return 0;
578
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200579 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200580 return 0;
581
582 cod[0] = hdev->minor_class;
583 cod[1] = hdev->major_class;
584 cod[2] = get_service_classes(hdev);
585
586 if (memcmp(cod, hdev->dev_class, 3) == 0)
587 return 0;
588
589 return hci_send_cmd(hdev, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
590}
591
Johan Hedberg7d785252011-12-15 00:47:39 +0200592static void service_cache_off(struct work_struct *work)
593{
594 struct hci_dev *hdev = container_of(work, struct hci_dev,
595 service_cache.work);
596
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200597 if (!test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200598 return;
599
600 hci_dev_lock(hdev);
601
602 update_eir(hdev);
603 update_class(hdev);
604
605 hci_dev_unlock(hdev);
606}
607
608static void mgmt_init_hdev(struct hci_dev *hdev)
609{
Johan Hedberg0cbf4ed2012-02-21 17:25:22 +0200610 if (!test_and_set_bit(HCI_MGMT, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +0200611 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
612
Johan Hedberg0cbf4ed2012-02-21 17:25:22 +0200613 /* Non-mgmt controlled devices get this bit set
614 * implicitly so that pairing works for them, however
615 * for mgmt we require user-space to explicitly enable
616 * it
617 */
618 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
619 }
Johan Hedberg7d785252011-12-15 00:47:39 +0200620}
621
Johan Hedberg03811012010-12-08 00:21:06 +0200622static int read_controller_info(struct sock *sk, u16 index)
623{
624 struct mgmt_rp_read_info rp;
625 struct hci_dev *hdev;
626
627 BT_DBG("sock %p hci%u", sk, index);
628
629 hdev = hci_dev_get(index);
630 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200631 return cmd_status(sk, index, MGMT_OP_READ_INFO,
632 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200633
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300634 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200635
Johan Hedberg7d785252011-12-15 00:47:39 +0200636 if (test_and_clear_bit(HCI_PI_MGMT_INIT, &hci_pi(sk)->flags))
637 mgmt_init_hdev(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200638
639 memset(&rp, 0, sizeof(rp));
640
Johan Hedberg03811012010-12-08 00:21:06 +0200641 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200642
643 rp.version = hdev->hci_ver;
644
Johan Hedberg03811012010-12-08 00:21:06 +0200645 put_unaligned_le16(hdev->manufacturer, &rp.manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200646
647 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
648 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
649
650 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedberg03811012010-12-08 00:21:06 +0200651
652 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
Johan Hedberg27fcc362012-02-22 21:46:22 +0200653 memcpy(rp.short_name, hdev->short_name, sizeof(hdev->short_name));
Johan Hedberg03811012010-12-08 00:21:06 +0200654
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300655 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200656 hci_dev_put(hdev);
657
Johan Hedbergaee9b212012-02-18 15:07:59 +0200658 return cmd_complete(sk, index, MGMT_OP_READ_INFO, 0, &rp, sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +0200659}
660
661static void mgmt_pending_free(struct pending_cmd *cmd)
662{
663 sock_put(cmd->sk);
664 kfree(cmd->param);
665 kfree(cmd);
666}
667
668static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
669 struct hci_dev *hdev,
670 void *data, u16 len)
671{
672 struct pending_cmd *cmd;
673
674 cmd = kmalloc(sizeof(*cmd), GFP_ATOMIC);
675 if (!cmd)
676 return NULL;
677
678 cmd->opcode = opcode;
679 cmd->index = hdev->id;
680
681 cmd->param = kmalloc(len, GFP_ATOMIC);
682 if (!cmd->param) {
683 kfree(cmd);
684 return NULL;
685 }
686
687 if (data)
688 memcpy(cmd->param, data, len);
689
690 cmd->sk = sk;
691 sock_hold(sk);
692
693 list_add(&cmd->list, &hdev->mgmt_pending);
694
695 return cmd;
696}
697
698static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
699 void (*cb)(struct pending_cmd *cmd, void *data),
700 void *data)
701{
702 struct list_head *p, *n;
703
704 list_for_each_safe(p, n, &hdev->mgmt_pending) {
705 struct pending_cmd *cmd;
706
707 cmd = list_entry(p, struct pending_cmd, list);
708
709 if (opcode > 0 && cmd->opcode != opcode)
710 continue;
711
712 cb(cmd, data);
713 }
714}
715
716static struct pending_cmd *mgmt_pending_find(u16 opcode, struct hci_dev *hdev)
717{
718 struct pending_cmd *cmd;
719
720 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
721 if (cmd->opcode == opcode)
722 return cmd;
723 }
724
725 return NULL;
726}
727
728static void mgmt_pending_remove(struct pending_cmd *cmd)
729{
730 list_del(&cmd->list);
731 mgmt_pending_free(cmd);
732}
733
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200734static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +0200735{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200736 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +0200737
Johan Hedbergaee9b212012-02-18 15:07:59 +0200738 return cmd_complete(sk, hdev->id, opcode, 0, &settings,
739 sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +0200740}
741
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300742static int set_powered(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200743{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300744 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200745 struct hci_dev *hdev;
746 struct pending_cmd *cmd;
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200747 int err;
Johan Hedberg03811012010-12-08 00:21:06 +0200748
Johan Hedberg03811012010-12-08 00:21:06 +0200749 BT_DBG("request for hci%u", index);
750
751 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200752 return cmd_status(sk, index, MGMT_OP_SET_POWERED,
753 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200754
755 hdev = hci_dev_get(index);
756 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200757 return cmd_status(sk, index, MGMT_OP_SET_POWERED,
758 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200759
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300760 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200761
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100762 if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) {
763 cancel_delayed_work(&hdev->power_off);
764
765 if (cp->val) {
766 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
767 mgmt_powered(hdev, 1);
768 goto failed;
769 }
770 }
771
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200772 if (!!cp->val == hdev_is_powered(hdev)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200773 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200774 goto failed;
775 }
776
777 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200778 err = cmd_status(sk, index, MGMT_OP_SET_POWERED,
779 MGMT_STATUS_BUSY);
Johan Hedberg03811012010-12-08 00:21:06 +0200780 goto failed;
781 }
782
783 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
784 if (!cmd) {
785 err = -ENOMEM;
786 goto failed;
787 }
788
789 if (cp->val)
Gustavo F. Padovan7f971042011-12-18 12:40:32 -0200790 schedule_work(&hdev->power_on);
Johan Hedberg03811012010-12-08 00:21:06 +0200791 else
Gustavo F. Padovan80b7ab32011-12-17 14:52:27 -0200792 schedule_work(&hdev->power_off.work);
Johan Hedberg03811012010-12-08 00:21:06 +0200793
794 err = 0;
795
796failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300797 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200798 hci_dev_put(hdev);
799 return err;
800}
801
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200802static int mgmt_event(u16 event, struct hci_dev *hdev, void *data,
803 u16 data_len, struct sock *skip_sk)
804{
805 struct sk_buff *skb;
806 struct mgmt_hdr *hdr;
807
808 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_ATOMIC);
809 if (!skb)
810 return -ENOMEM;
811
812 hdr = (void *) skb_put(skb, sizeof(*hdr));
813 hdr->opcode = cpu_to_le16(event);
814 if (hdev)
815 hdr->index = cpu_to_le16(hdev->id);
816 else
817 hdr->index = cpu_to_le16(MGMT_INDEX_NONE);
818 hdr->len = cpu_to_le16(data_len);
819
820 if (data)
821 memcpy(skb_put(skb, data_len), data, data_len);
822
Marcel Holtmann97e0bde2012-02-22 13:49:28 +0100823 /* Time stamp */
824 __net_timestamp(skb);
825
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200826 hci_send_to_control(skb, skip_sk);
827 kfree_skb(skb);
828
829 return 0;
830}
831
832static int new_settings(struct hci_dev *hdev, struct sock *skip)
833{
834 __le32 ev;
835
836 ev = cpu_to_le32(get_current_settings(hdev));
837
838 return mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), skip);
839}
840
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300841static int set_discoverable(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200842{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300843 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberge41d8b42010-12-13 21:07:03 +0200844 struct hci_dev *hdev;
Johan Hedberg03811012010-12-08 00:21:06 +0200845 struct pending_cmd *cmd;
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200846 u16 timeout;
Johan Hedberg03811012010-12-08 00:21:06 +0200847 u8 scan;
848 int err;
849
Johan Hedberg03811012010-12-08 00:21:06 +0200850 BT_DBG("request for hci%u", index);
851
852 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200853 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
854 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200855
Marcel Holtmann24c54a92012-02-22 18:06:34 +0100856 timeout = get_unaligned_le16(&cp->timeout);
857 if (!cp->val && timeout > 0)
858 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
859 MGMT_STATUS_INVALID_PARAMS);
860
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200861 hdev = hci_dev_get(index);
862 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200863 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
864 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200865
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300866 hci_dev_lock(hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200867
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200868 if (!hdev_is_powered(hdev) && timeout > 0) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200869 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
870 MGMT_STATUS_NOT_POWERED);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200871 goto failed;
872 }
873
874 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
875 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200876 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
877 MGMT_STATUS_BUSY);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200878 goto failed;
879 }
880
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200881 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) {
882 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
883 MGMT_STATUS_REJECTED);
884 goto failed;
885 }
886
887 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200888 bool changed = false;
889
890 if (!!cp->val != test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
891 change_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
892 changed = true;
893 }
894
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200895 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200896 if (err < 0)
897 goto failed;
898
899 if (changed)
900 err = new_settings(hdev, sk);
901
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200902 goto failed;
903 }
904
905 if (!!cp->val == test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
Marcel Holtmann955638e2012-02-22 18:21:00 +0100906 if (hdev->discov_timeout > 0) {
907 cancel_delayed_work(&hdev->discov_off);
908 hdev->discov_timeout = 0;
909 }
910
911 if (cp->val && timeout > 0) {
912 hdev->discov_timeout = timeout;
913 queue_delayed_work(hdev->workqueue, &hdev->discov_off,
914 msecs_to_jiffies(hdev->discov_timeout * 1000));
915 }
916
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200917 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200918 goto failed;
919 }
920
921 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
922 if (!cmd) {
923 err = -ENOMEM;
924 goto failed;
925 }
926
927 scan = SCAN_PAGE;
928
929 if (cp->val)
930 scan |= SCAN_INQUIRY;
931 else
932 cancel_delayed_work(&hdev->discov_off);
933
934 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
935 if (err < 0)
936 mgmt_pending_remove(cmd);
937
Johan Hedberg03811012010-12-08 00:21:06 +0200938 if (cp->val)
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200939 hdev->discov_timeout = timeout;
Johan Hedberg03811012010-12-08 00:21:06 +0200940
941failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300942 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200943 hci_dev_put(hdev);
944
945 return err;
946}
947
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300948static int set_connectable(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200949{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300950 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200951 struct hci_dev *hdev;
952 struct pending_cmd *cmd;
953 u8 scan;
954 int err;
955
Johan Hedberge41d8b42010-12-13 21:07:03 +0200956 BT_DBG("request for hci%u", index);
957
Johan Hedberg03811012010-12-08 00:21:06 +0200958 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200959 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
960 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200961
962 hdev = hci_dev_get(index);
963 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200964 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
965 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200966
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300967 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200968
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200969 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200970 bool changed = false;
971
972 if (!!cp->val != test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
973 changed = true;
974
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +0200975 if (cp->val) {
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200976 set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +0200977 } else {
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200978 clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
979 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
980 }
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200981
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200982 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200983 if (err < 0)
984 goto failed;
985
986 if (changed)
987 err = new_settings(hdev, sk);
988
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200989 goto failed;
990 }
991
992 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
993 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200994 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
995 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200996 goto failed;
997 }
998
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200999 if (!!cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001000 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001001 goto failed;
1002 }
1003
1004 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
1005 if (!cmd) {
1006 err = -ENOMEM;
1007 goto failed;
1008 }
1009
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001010 if (cp->val) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001011 scan = SCAN_PAGE;
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001012 } else {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001013 scan = 0;
1014
Johan Hedbergdf2c6c52012-02-21 19:15:49 +02001015 if (test_bit(HCI_ISCAN, &hdev->flags) &&
1016 hdev->discov_timeout > 0)
1017 cancel_delayed_work(&hdev->discov_off);
1018 }
1019
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001020 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1021 if (err < 0)
1022 mgmt_pending_remove(cmd);
1023
1024failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001025 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001026 hci_dev_put(hdev);
1027
1028 return err;
1029}
1030
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001031static int set_pairable(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001032{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001033 struct mgmt_mode *cp = data;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001034 struct hci_dev *hdev;
1035 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001036
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001037 BT_DBG("request for hci%u", index);
1038
1039 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001040 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE,
1041 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001042
1043 hdev = hci_dev_get(index);
1044 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001045 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE,
1046 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001047
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001048 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001049
1050 if (cp->val)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001051 set_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001052 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001053 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001054
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001055 err = send_settings_rsp(sk, MGMT_OP_SET_PAIRABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001056 if (err < 0)
1057 goto failed;
1058
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001059 err = new_settings(hdev, sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001060
1061failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001062 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001063 hci_dev_put(hdev);
1064
1065 return err;
1066}
Johan Hedberg72a734e2010-12-30 00:38:22 +02001067
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001068static int set_link_security(struct sock *sk, u16 index, void *data, u16 len)
1069{
1070 struct mgmt_mode *cp = data;
1071 struct pending_cmd *cmd;
1072 struct hci_dev *hdev;
1073 uint8_t val;
1074 int err;
1075
1076 BT_DBG("request for hci%u", index);
1077
1078 if (len != sizeof(*cp))
1079 return cmd_status(sk, index, MGMT_OP_SET_LINK_SECURITY,
1080 MGMT_STATUS_INVALID_PARAMS);
1081
1082 hdev = hci_dev_get(index);
1083 if (!hdev)
1084 return cmd_status(sk, index, MGMT_OP_SET_LINK_SECURITY,
1085 MGMT_STATUS_INVALID_PARAMS);
1086
1087 hci_dev_lock(hdev);
1088
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001089 if (!hdev_is_powered(hdev)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001090 bool changed = false;
1091
1092 if (!!cp->val != test_bit(HCI_LINK_SECURITY,
1093 &hdev->dev_flags)) {
1094 change_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
1095 changed = true;
1096 }
1097
1098 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1099 if (err < 0)
1100 goto failed;
1101
1102 if (changed)
1103 err = new_settings(hdev, sk);
1104
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001105 goto failed;
1106 }
1107
1108 if (mgmt_pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
1109 err = cmd_status(sk, index, MGMT_OP_SET_LINK_SECURITY,
1110 MGMT_STATUS_BUSY);
1111 goto failed;
1112 }
1113
1114 val = !!cp->val;
1115
1116 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1117 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1118 goto failed;
1119 }
1120
1121 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1122 if (!cmd) {
1123 err = -ENOMEM;
1124 goto failed;
1125 }
1126
1127 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1128 if (err < 0) {
1129 mgmt_pending_remove(cmd);
1130 goto failed;
1131 }
1132
1133failed:
1134 hci_dev_unlock(hdev);
1135 hci_dev_put(hdev);
1136
1137 return err;
1138}
1139
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001140static int set_ssp(struct sock *sk, u16 index, void *data, u16 len)
1141{
1142 struct mgmt_mode *cp = data;
1143 struct pending_cmd *cmd;
1144 struct hci_dev *hdev;
1145 uint8_t val;
1146 int err;
1147
1148 BT_DBG("request for hci%u", index);
1149
1150 if (len != sizeof(*cp))
1151 return cmd_status(sk, index, MGMT_OP_SET_SSP,
1152 MGMT_STATUS_INVALID_PARAMS);
1153
1154 hdev = hci_dev_get(index);
1155 if (!hdev)
1156 return cmd_status(sk, index, MGMT_OP_SET_SSP,
1157 MGMT_STATUS_INVALID_PARAMS);
1158
1159 hci_dev_lock(hdev);
1160
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001161 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
1162 err = cmd_status(sk, index, MGMT_OP_SET_SSP,
1163 MGMT_STATUS_NOT_SUPPORTED);
1164 goto failed;
1165 }
1166
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001167 val = !!cp->val;
1168
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001169 if (!hdev_is_powered(hdev)) {
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001170 bool changed = false;
1171
1172 if (val != test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) {
1173 change_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
1174 changed = true;
1175 }
1176
1177 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1178 if (err < 0)
1179 goto failed;
1180
1181 if (changed)
1182 err = new_settings(hdev, sk);
1183
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001184 goto failed;
1185 }
1186
1187 if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev)) {
1188 err = cmd_status(sk, index, MGMT_OP_SET_SSP, MGMT_STATUS_BUSY);
1189 goto failed;
1190 }
1191
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001192 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) == val) {
1193 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1194 goto failed;
1195 }
1196
1197 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1198 if (!cmd) {
1199 err = -ENOMEM;
1200 goto failed;
1201 }
1202
1203 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, sizeof(val), &val);
1204 if (err < 0) {
1205 mgmt_pending_remove(cmd);
1206 goto failed;
1207 }
1208
1209failed:
1210 hci_dev_unlock(hdev);
1211 hci_dev_put(hdev);
1212
1213 return err;
1214}
1215
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001216static int set_hs(struct sock *sk, u16 index, void *data, u16 len)
1217{
1218 struct mgmt_mode *cp = data;
1219 struct hci_dev *hdev;
1220 int err;
1221
1222 BT_DBG("request for hci%u", index);
1223
1224 if (len != sizeof(*cp))
1225 return cmd_status(sk, index, MGMT_OP_SET_HS,
1226 MGMT_STATUS_INVALID_PARAMS);
1227
1228 hdev = hci_dev_get(index);
1229 if (!hdev)
1230 return cmd_status(sk, index, MGMT_OP_SET_HS,
1231 MGMT_STATUS_INVALID_PARAMS);
1232
1233 if (!enable_hs) {
1234 err = cmd_status(sk, index, MGMT_OP_SET_HS,
1235 MGMT_STATUS_NOT_SUPPORTED);
1236 goto failed;
1237 }
1238
1239 if (cp->val)
1240 set_bit(HCI_HS_ENABLED, &hdev->dev_flags);
1241 else
1242 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
1243
1244 err = send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
1245
1246failed:
1247 hci_dev_put(hdev);
1248 return err;
1249}
1250
Johan Hedberg06199cf2012-02-22 16:37:11 +02001251static int set_le(struct sock *sk, u16 index, void *data, u16 len)
1252{
1253 struct mgmt_mode *cp = data;
1254 struct hci_cp_write_le_host_supported hci_cp;
1255 struct pending_cmd *cmd;
1256 struct hci_dev *hdev;
1257 int err;
1258 u8 val;
1259
1260 BT_DBG("request for hci%u", index);
1261
1262 if (len != sizeof(*cp))
1263 return cmd_status(sk, index, MGMT_OP_SET_LE,
1264 MGMT_STATUS_INVALID_PARAMS);
1265
1266 hdev = hci_dev_get(index);
1267 if (!hdev)
1268 return cmd_status(sk, index, MGMT_OP_SET_LE,
1269 MGMT_STATUS_INVALID_PARAMS);
1270
1271 if (!enable_le || !(hdev->features[4] & LMP_LE)) {
1272 err = cmd_status(sk, index, MGMT_OP_SET_LE,
1273 MGMT_STATUS_NOT_SUPPORTED);
1274 goto failed;
1275 }
1276
1277 val = !!cp->val;
1278
1279 if (!hdev_is_powered(hdev)) {
1280 bool changed = false;
1281
1282 if (val != test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
1283 change_bit(HCI_LE_ENABLED, &hdev->dev_flags);
1284 changed = true;
1285 }
1286
1287 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1288 if (err < 0)
1289 goto failed;
1290
1291 if (changed)
1292 err = new_settings(hdev, sk);
1293
1294 goto failed;
1295 }
1296
1297 if (mgmt_pending_find(MGMT_OP_SET_LE, hdev)) {
1298 err = cmd_status(sk, index, MGMT_OP_SET_LE, MGMT_STATUS_BUSY);
1299 goto failed;
1300 }
1301
1302 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
1303 if (!cmd) {
1304 err = -ENOMEM;
1305 goto failed;
1306 }
1307
1308 memset(&hci_cp, 0, sizeof(hci_cp));
1309
1310 if (val) {
1311 hci_cp.le = val;
1312 hci_cp.simul = !!(hdev->features[6] & LMP_SIMUL_LE_BR);
1313 }
1314
1315 err = hci_send_cmd(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED,
1316 sizeof(hci_cp), &hci_cp);
1317 if (err < 0) {
1318 mgmt_pending_remove(cmd);
1319 goto failed;
1320 }
1321
1322failed:
1323 hci_dev_put(hdev);
1324 return err;
1325}
1326
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001327static int add_uuid(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001328{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001329 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001330 struct hci_dev *hdev;
1331 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001332 int err;
1333
Szymon Janc4e51eae2011-02-25 19:05:48 +01001334 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001335
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001336 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001337 return cmd_status(sk, index, MGMT_OP_ADD_UUID,
1338 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001339
Szymon Janc4e51eae2011-02-25 19:05:48 +01001340 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001341 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001342 return cmd_status(sk, index, MGMT_OP_ADD_UUID,
1343 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001344
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001345 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001346
1347 uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC);
1348 if (!uuid) {
1349 err = -ENOMEM;
1350 goto failed;
1351 }
1352
1353 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001354 uuid->svc_hint = cp->svc_hint;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001355
1356 list_add(&uuid->list, &hdev->uuids);
1357
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001358 err = update_class(hdev);
1359 if (err < 0)
1360 goto failed;
1361
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001362 err = update_eir(hdev);
1363 if (err < 0)
1364 goto failed;
1365
Johan Hedberg9997a532012-02-23 15:57:46 +02001366 err = cmd_complete(sk, index, MGMT_OP_ADD_UUID, 0, hdev->dev_class, 3);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001367
1368failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001369 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001370 hci_dev_put(hdev);
1371
1372 return err;
1373}
1374
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001375static int remove_uuid(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001376{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001377 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001378 struct list_head *p, *n;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001379 struct hci_dev *hdev;
1380 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 +02001381 int err, found;
1382
Szymon Janc4e51eae2011-02-25 19:05:48 +01001383 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001384
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001385 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001386 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
1387 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001388
Szymon Janc4e51eae2011-02-25 19:05:48 +01001389 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001390 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001391 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
1392 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001393
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001394 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001395
1396 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
1397 err = hci_uuids_clear(hdev);
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001398
1399 if (hdev_is_powered(hdev) &&
1400 !test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
1401 schedule_delayed_work(&hdev->service_cache,
1402 msecs_to_jiffies(SERVICE_CACHE_TIMEOUT));
1403
Johan Hedberg9246a862012-02-23 21:33:16 +02001404 goto update_class;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001405 }
1406
1407 found = 0;
1408
1409 list_for_each_safe(p, n, &hdev->uuids) {
1410 struct bt_uuid *match = list_entry(p, struct bt_uuid, list);
1411
1412 if (memcmp(match->uuid, cp->uuid, 16) != 0)
1413 continue;
1414
1415 list_del(&match->list);
1416 found++;
1417 }
1418
1419 if (found == 0) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001420 err = cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
1421 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001422 goto unlock;
1423 }
1424
Johan Hedberg9246a862012-02-23 21:33:16 +02001425update_class:
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001426 err = update_class(hdev);
1427 if (err < 0)
1428 goto unlock;
1429
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001430 err = update_eir(hdev);
1431 if (err < 0)
1432 goto unlock;
1433
Johan Hedberg9997a532012-02-23 15:57:46 +02001434 err = cmd_complete(sk, index, MGMT_OP_REMOVE_UUID, 0,
1435 hdev->dev_class, 3);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001436
1437unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001438 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001439 hci_dev_put(hdev);
1440
1441 return err;
1442}
1443
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001444static int set_dev_class(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001445{
1446 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001447 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001448 int err;
1449
Szymon Janc4e51eae2011-02-25 19:05:48 +01001450 BT_DBG("request for hci%u", index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001451
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001452 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001453 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS,
1454 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001455
Szymon Janc4e51eae2011-02-25 19:05:48 +01001456 hdev = hci_dev_get(index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001457 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001458 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS,
1459 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001460
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001461 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001462
1463 hdev->major_class = cp->major;
1464 hdev->minor_class = cp->minor;
1465
Johan Hedberg932f5ff2012-02-22 22:11:32 +02001466 if (!hdev_is_powered(hdev)) {
1467 err = cmd_complete(sk, index, MGMT_OP_SET_DEV_CLASS, 0,
1468 hdev->dev_class, 3);
1469 goto unlock;
1470 }
1471
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001472 if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02001473 hci_dev_unlock(hdev);
1474 cancel_delayed_work_sync(&hdev->service_cache);
1475 hci_dev_lock(hdev);
Johan Hedberg14c0b602011-12-15 00:47:37 +02001476 update_eir(hdev);
Johan Hedberg7d785252011-12-15 00:47:39 +02001477 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02001478
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001479 err = update_class(hdev);
1480
1481 if (err == 0)
Johan Hedbergaee9b212012-02-18 15:07:59 +02001482 err = cmd_complete(sk, index, MGMT_OP_SET_DEV_CLASS, 0,
Johan Hedberg8ec37032012-02-22 22:02:50 +02001483 hdev->dev_class, 3);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001484
Johan Hedbergb5235a62012-02-21 14:32:24 +02001485unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001486 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001487 hci_dev_put(hdev);
1488
1489 return err;
1490}
1491
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001492static int load_link_keys(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001493{
1494 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001495 struct mgmt_cp_load_link_keys *cp = data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001496 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001497 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001498
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001499 if (len < sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001500 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1501 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001502
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001503 key_count = get_unaligned_le16(&cp->key_count);
1504
Johan Hedberg86742e12011-11-07 23:13:38 +02001505 expected_len = sizeof(*cp) + key_count *
1506 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001507 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001508 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001509 len, expected_len);
Johan Hedbergca69b792011-11-11 18:10:00 +02001510 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1511 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001512 }
1513
Szymon Janc4e51eae2011-02-25 19:05:48 +01001514 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001515 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001516 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1517 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001518
Szymon Janc4e51eae2011-02-25 19:05:48 +01001519 BT_DBG("hci%u debug_keys %u key_count %u", index, cp->debug_keys,
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001520 key_count);
1521
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001522 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001523
1524 hci_link_keys_clear(hdev);
1525
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001526 set_bit(HCI_LINK_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001527
1528 if (cp->debug_keys)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001529 set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001530 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001531 clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001532
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001533 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001534 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001535
Johan Hedbergd753fdc2012-02-17 14:06:34 +02001536 hci_add_link_key(hdev, NULL, 0, &key->addr.bdaddr, key->val,
1537 key->type, key->pin_len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001538 }
1539
Johan Hedbergaee9b212012-02-18 15:07:59 +02001540 cmd_complete(sk, index, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02001541
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001542 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001543 hci_dev_put(hdev);
1544
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001545 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001546}
1547
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001548static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
1549 u8 addr_type, struct sock *skip_sk)
1550{
1551 struct mgmt_ev_device_unpaired ev;
1552
1553 bacpy(&ev.addr.bdaddr, bdaddr);
1554 ev.addr.type = addr_type;
1555
1556 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
1557 skip_sk);
1558}
1559
Johan Hedberg124f6e32012-02-09 13:50:12 +02001560static int unpair_device(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001561{
1562 struct hci_dev *hdev;
Johan Hedberg124f6e32012-02-09 13:50:12 +02001563 struct mgmt_cp_unpair_device *cp = data;
1564 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001565 struct hci_cp_disconnect dc;
1566 struct pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001567 struct hci_conn *conn;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001568 int err;
1569
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001570 if (len != sizeof(*cp))
Johan Hedberg124f6e32012-02-09 13:50:12 +02001571 return cmd_status(sk, index, MGMT_OP_UNPAIR_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02001572 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001573
Szymon Janc4e51eae2011-02-25 19:05:48 +01001574 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001575 if (!hdev)
Johan Hedberg124f6e32012-02-09 13:50:12 +02001576 return cmd_status(sk, index, MGMT_OP_UNPAIR_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02001577 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001578
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001579 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001580
Johan Hedberga8a1d192011-11-10 15:54:38 +02001581 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02001582 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1583 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001584
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001585 if (!hdev_is_powered(hdev)) {
1586 err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE,
1587 MGMT_STATUS_NOT_POWERED,
1588 &rp, sizeof(rp));
1589 goto unlock;
1590 }
1591
Johan Hedberg124f6e32012-02-09 13:50:12 +02001592 if (cp->addr.type == MGMT_ADDR_BREDR)
1593 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
1594 else
1595 err = hci_remove_ltk(hdev, &cp->addr.bdaddr);
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03001596
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001597 if (err < 0) {
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001598 err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE,
1599 MGMT_STATUS_NOT_PAIRED,
1600 &rp, sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001601 goto unlock;
1602 }
1603
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001604 if (cp->disconnect) {
1605 if (cp->addr.type == MGMT_ADDR_BREDR)
1606 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
1607 &cp->addr.bdaddr);
1608 else
1609 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
1610 &cp->addr.bdaddr);
1611 } else {
1612 conn = NULL;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001613 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001614
Johan Hedberga8a1d192011-11-10 15:54:38 +02001615 if (!conn) {
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001616 err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE, 0,
Johan Hedbergaee9b212012-02-18 15:07:59 +02001617 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001618 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001619 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001620 }
1621
Johan Hedberg124f6e32012-02-09 13:50:12 +02001622 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
1623 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02001624 if (!cmd) {
1625 err = -ENOMEM;
1626 goto unlock;
1627 }
1628
1629 put_unaligned_le16(conn->handle, &dc.handle);
1630 dc.reason = 0x13; /* Remote User Terminated Connection */
1631 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1632 if (err < 0)
1633 mgmt_pending_remove(cmd);
1634
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001635unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001636 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001637 hci_dev_put(hdev);
1638
1639 return err;
1640}
1641
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001642static int disconnect(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02001643{
1644 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001645 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001646 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03001647 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001648 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001649 int err;
1650
1651 BT_DBG("");
1652
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001653 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001654 return cmd_status(sk, index, MGMT_OP_DISCONNECT,
1655 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001656
Szymon Janc4e51eae2011-02-25 19:05:48 +01001657 hdev = hci_dev_get(index);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001658 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001659 return cmd_status(sk, index, MGMT_OP_DISCONNECT,
1660 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001661
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001662 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001663
1664 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001665 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1666 MGMT_STATUS_NOT_POWERED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001667 goto failed;
1668 }
1669
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001670 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001671 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1672 MGMT_STATUS_BUSY);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001673 goto failed;
1674 }
1675
Johan Hedberg88c3df12012-02-09 14:27:38 +02001676 if (cp->addr.type == MGMT_ADDR_BREDR)
1677 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
1678 else
1679 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03001680
Johan Hedberg8962ee72011-01-20 12:40:27 +02001681 if (!conn) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001682 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1683 MGMT_STATUS_NOT_CONNECTED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001684 goto failed;
1685 }
1686
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001687 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001688 if (!cmd) {
1689 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001690 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001691 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001692
1693 put_unaligned_le16(conn->handle, &dc.handle);
1694 dc.reason = 0x13; /* Remote User Terminated Connection */
1695
1696 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1697 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001698 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001699
1700failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001701 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001702 hci_dev_put(hdev);
1703
1704 return err;
1705}
1706
Johan Hedberg48264f02011-11-09 13:58:58 +02001707static u8 link_to_mgmt(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02001708{
1709 switch (link_type) {
1710 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02001711 switch (addr_type) {
1712 case ADDR_LE_DEV_PUBLIC:
1713 return MGMT_ADDR_LE_PUBLIC;
1714 case ADDR_LE_DEV_RANDOM:
1715 return MGMT_ADDR_LE_RANDOM;
1716 default:
1717 return MGMT_ADDR_INVALID;
1718 }
Johan Hedberg4c659c32011-11-07 23:13:39 +02001719 case ACL_LINK:
1720 return MGMT_ADDR_BREDR;
1721 default:
1722 return MGMT_ADDR_INVALID;
1723 }
1724}
1725
Szymon Janc8ce62842011-03-01 16:55:32 +01001726static int get_connections(struct sock *sk, u16 index)
Johan Hedberg2784eb42011-01-21 13:56:35 +02001727{
Johan Hedberg2784eb42011-01-21 13:56:35 +02001728 struct mgmt_rp_get_connections *rp;
1729 struct hci_dev *hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001730 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02001731 size_t rp_len;
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001732 int err;
1733 u16 i;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001734
1735 BT_DBG("");
1736
Szymon Janc4e51eae2011-02-25 19:05:48 +01001737 hdev = hci_dev_get(index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001738 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001739 return cmd_status(sk, index, MGMT_OP_GET_CONNECTIONS,
1740 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001741
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001742 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001743
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001744 if (!hdev_is_powered(hdev)) {
1745 err = cmd_status(sk, index, MGMT_OP_GET_CONNECTIONS,
1746 MGMT_STATUS_NOT_POWERED);
1747 goto unlock;
1748 }
1749
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001750 i = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02001751 list_for_each_entry(c, &hdev->conn_hash.list, list) {
1752 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001753 i++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001754 }
1755
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001756 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberga38528f2011-01-22 06:46:43 +02001757 rp = kmalloc(rp_len, GFP_ATOMIC);
1758 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02001759 err = -ENOMEM;
1760 goto unlock;
1761 }
1762
Johan Hedberg2784eb42011-01-21 13:56:35 +02001763 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001764 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02001765 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
1766 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001767 bacpy(&rp->addr[i].bdaddr, &c->dst);
Johan Hedberg48264f02011-11-09 13:58:58 +02001768 rp->addr[i].type = link_to_mgmt(c->type, c->dst_type);
Johan Hedberg4c659c32011-11-07 23:13:39 +02001769 if (rp->addr[i].type == MGMT_ADDR_INVALID)
1770 continue;
1771 i++;
1772 }
1773
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001774 put_unaligned_le16(i, &rp->conn_count);
1775
Johan Hedberg4c659c32011-11-07 23:13:39 +02001776 /* Recalculate length in case of filtered SCO connections, etc */
1777 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02001778
Johan Hedbergaee9b212012-02-18 15:07:59 +02001779 err = cmd_complete(sk, index, MGMT_OP_GET_CONNECTIONS, 0, rp, rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001780
Johan Hedberga38528f2011-01-22 06:46:43 +02001781 kfree(rp);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001782
1783unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001784 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001785 hci_dev_put(hdev);
1786 return err;
1787}
1788
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001789static int send_pin_code_neg_reply(struct sock *sk, u16 index,
1790 struct hci_dev *hdev, struct mgmt_cp_pin_code_neg_reply *cp)
1791{
1792 struct pending_cmd *cmd;
1793 int err;
1794
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001795 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001796 sizeof(*cp));
1797 if (!cmd)
1798 return -ENOMEM;
1799
Johan Hedbergd8457692012-02-17 14:24:57 +02001800 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
1801 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001802 if (err < 0)
1803 mgmt_pending_remove(cmd);
1804
1805 return err;
1806}
1807
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001808static int pin_code_reply(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001809{
1810 struct hci_dev *hdev;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001811 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001812 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001813 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03001814 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001815 int err;
1816
1817 BT_DBG("");
1818
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001819 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001820 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1821 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001822
Szymon Janc4e51eae2011-02-25 19:05:48 +01001823 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001824 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001825 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1826 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001827
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001828 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001829
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001830 if (!hdev_is_powered(hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001831 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1832 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001833 goto failed;
1834 }
1835
Johan Hedbergd8457692012-02-17 14:24:57 +02001836 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001837 if (!conn) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001838 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1839 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001840 goto failed;
1841 }
1842
1843 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02001844 struct mgmt_cp_pin_code_neg_reply ncp;
1845
1846 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001847
1848 BT_ERR("PIN code is not 16 bytes long");
1849
1850 err = send_pin_code_neg_reply(sk, index, hdev, &ncp);
1851 if (err >= 0)
1852 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001853 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001854
1855 goto failed;
1856 }
1857
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001858 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data,
1859 len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001860 if (!cmd) {
1861 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001862 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001863 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02001864
Johan Hedbergd8457692012-02-17 14:24:57 +02001865 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001866 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02001867 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02001868
1869 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
1870 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001871 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001872
1873failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001874 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001875 hci_dev_put(hdev);
1876
1877 return err;
1878}
1879
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001880static int pin_code_neg_reply(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001881{
1882 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001883 struct mgmt_cp_pin_code_neg_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001884 int err;
1885
1886 BT_DBG("");
1887
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001888 if (len != sizeof(*cp))
1889 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001890 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001891
Szymon Janc4e51eae2011-02-25 19:05:48 +01001892 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001893 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001894 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001895 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001896
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001897 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001898
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001899 if (!hdev_is_powered(hdev)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001900 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001901 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001902 goto failed;
1903 }
1904
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001905 err = send_pin_code_neg_reply(sk, index, hdev, cp);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001906
1907failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001908 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001909 hci_dev_put(hdev);
1910
1911 return err;
1912}
1913
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001914static int set_io_capability(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001915{
1916 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001917 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001918
1919 BT_DBG("");
1920
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001921 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001922 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY,
1923 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001924
Szymon Janc4e51eae2011-02-25 19:05:48 +01001925 hdev = hci_dev_get(index);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001926 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001927 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY,
1928 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001929
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001930 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001931
1932 hdev->io_capability = cp->io_capability;
1933
1934 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Szymon Jancb8534e02011-03-01 16:55:34 +01001935 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001936
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001937 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001938 hci_dev_put(hdev);
1939
Johan Hedbergaee9b212012-02-18 15:07:59 +02001940 return cmd_complete(sk, index, MGMT_OP_SET_IO_CAPABILITY, 0, NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001941}
1942
Johan Hedberge9a416b2011-02-19 12:05:56 -03001943static inline struct pending_cmd *find_pairing(struct hci_conn *conn)
1944{
1945 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001946 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001947
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001948 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03001949 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
1950 continue;
1951
Johan Hedberge9a416b2011-02-19 12:05:56 -03001952 if (cmd->user_data != conn)
1953 continue;
1954
1955 return cmd;
1956 }
1957
1958 return NULL;
1959}
1960
1961static void pairing_complete(struct pending_cmd *cmd, u8 status)
1962{
1963 struct mgmt_rp_pair_device rp;
1964 struct hci_conn *conn = cmd->user_data;
1965
Johan Hedbergba4e5642011-11-11 00:07:34 +02001966 bacpy(&rp.addr.bdaddr, &conn->dst);
1967 rp.addr.type = link_to_mgmt(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001968
Johan Hedbergaee9b212012-02-18 15:07:59 +02001969 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, status,
1970 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001971
1972 /* So we don't get further callbacks for this connection */
1973 conn->connect_cfm_cb = NULL;
1974 conn->security_cfm_cb = NULL;
1975 conn->disconn_cfm_cb = NULL;
1976
1977 hci_conn_put(conn);
1978
Johan Hedberga664b5b2011-02-19 12:06:02 -03001979 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001980}
1981
1982static void pairing_complete_cb(struct hci_conn *conn, u8 status)
1983{
1984 struct pending_cmd *cmd;
1985
1986 BT_DBG("status %u", status);
1987
Johan Hedberg56e5cb82011-11-08 20:40:16 +02001988 cmd = find_pairing(conn);
1989 if (!cmd)
1990 BT_DBG("Unable to find a pending command");
1991 else
Johan Hedberge2113262012-02-18 15:20:03 +02001992 pairing_complete(cmd, mgmt_status(status));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001993}
1994
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001995static int pair_device(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001996{
1997 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001998 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02001999 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002000 struct pending_cmd *cmd;
2001 u8 sec_level, auth_type;
2002 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002003 int err;
2004
2005 BT_DBG("");
2006
Szymon Jancbdce7ba2011-02-25 19:05:49 +01002007 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02002008 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE,
2009 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01002010
Szymon Janc4e51eae2011-02-25 19:05:48 +01002011 hdev = hci_dev_get(index);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002012 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002013 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE,
2014 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002015
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002016 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002017
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002018 if (!hdev_is_powered(hdev)) {
2019 err = cmd_status(sk, index, MGMT_OP_PAIR_DEVICE,
2020 MGMT_STATUS_NOT_POWERED);
2021 goto unlock;
2022 }
2023
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002024 sec_level = BT_SECURITY_MEDIUM;
2025 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002026 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002027 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03002028 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002029
Johan Hedbergba4e5642011-11-11 00:07:34 +02002030 if (cp->addr.type == MGMT_ADDR_BREDR)
2031 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr, sec_level,
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002032 auth_type);
2033 else
Johan Hedbergba4e5642011-11-11 00:07:34 +02002034 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr, sec_level,
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002035 auth_type);
2036
Johan Hedberg1425acb2011-11-11 00:07:35 +02002037 memset(&rp, 0, sizeof(rp));
2038 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2039 rp.addr.type = cp->addr.type;
2040
Ville Tervo30e76272011-02-22 16:10:53 -03002041 if (IS_ERR(conn)) {
Johan Hedberge2113262012-02-18 15:20:03 +02002042 err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE,
2043 MGMT_STATUS_CONNECT_FAILED,
2044 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002045 goto unlock;
2046 }
2047
2048 if (conn->connect_cfm_cb) {
2049 hci_conn_put(conn);
Johan Hedberge2113262012-02-18 15:20:03 +02002050 err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE,
2051 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002052 goto unlock;
2053 }
2054
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002055 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002056 if (!cmd) {
2057 err = -ENOMEM;
2058 hci_conn_put(conn);
2059 goto unlock;
2060 }
2061
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002062 /* For LE, just connecting isn't a proof that the pairing finished */
Johan Hedbergba4e5642011-11-11 00:07:34 +02002063 if (cp->addr.type == MGMT_ADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002064 conn->connect_cfm_cb = pairing_complete_cb;
2065
Johan Hedberge9a416b2011-02-19 12:05:56 -03002066 conn->security_cfm_cb = pairing_complete_cb;
2067 conn->disconn_cfm_cb = pairing_complete_cb;
2068 conn->io_capability = cp->io_cap;
2069 cmd->user_data = conn;
2070
2071 if (conn->state == BT_CONNECTED &&
2072 hci_conn_security(conn, sec_level, auth_type))
2073 pairing_complete(cmd, 0);
2074
2075 err = 0;
2076
2077unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002078 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002079 hci_dev_put(hdev);
2080
2081 return err;
2082}
2083
Johan Hedberg28424702012-02-02 04:02:29 +02002084static int cancel_pair_device(struct sock *sk, u16 index,
2085 unsigned char *data, u16 len)
2086{
2087 struct mgmt_addr_info *addr = (void *) data;
2088 struct hci_dev *hdev;
2089 struct pending_cmd *cmd;
2090 struct hci_conn *conn;
2091 int err;
2092
2093 BT_DBG("");
2094
2095 if (len != sizeof(*addr))
2096 return cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
2097 MGMT_STATUS_INVALID_PARAMS);
2098
2099 hdev = hci_dev_get(index);
2100 if (!hdev)
2101 return cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
2102 MGMT_STATUS_INVALID_PARAMS);
2103
2104 hci_dev_lock(hdev);
2105
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002106 if (!hdev_is_powered(hdev)) {
2107 err = cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
2108 MGMT_STATUS_NOT_POWERED);
2109 goto unlock;
2110 }
2111
Johan Hedberg28424702012-02-02 04:02:29 +02002112 cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
2113 if (!cmd) {
2114 err = cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
2115 MGMT_STATUS_INVALID_PARAMS);
2116 goto unlock;
2117 }
2118
2119 conn = cmd->user_data;
2120
2121 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
2122 err = cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
2123 MGMT_STATUS_INVALID_PARAMS);
2124 goto unlock;
2125 }
2126
2127 pairing_complete(cmd, MGMT_STATUS_CANCELLED);
2128
Johan Hedbergaee9b212012-02-18 15:07:59 +02002129 err = cmd_complete(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE, 0, addr,
Johan Hedberg28424702012-02-02 04:02:29 +02002130 sizeof(*addr));
2131unlock:
2132 hci_dev_unlock(hdev);
2133 hci_dev_put(hdev);
2134
2135 return err;
2136}
2137
Brian Gix0df4c182011-11-16 13:53:13 -08002138static int user_pairing_resp(struct sock *sk, u16 index, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02002139 u8 type, u16 mgmt_op, u16 hci_op,
2140 __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03002141{
Johan Hedberga5c29682011-02-19 12:05:57 -03002142 struct pending_cmd *cmd;
2143 struct hci_dev *hdev;
Brian Gix0df4c182011-11-16 13:53:13 -08002144 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03002145 int err;
2146
Szymon Janc4e51eae2011-02-25 19:05:48 +01002147 hdev = hci_dev_get(index);
Johan Hedberga5c29682011-02-19 12:05:57 -03002148 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002149 return cmd_status(sk, index, mgmt_op,
2150 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga5c29682011-02-19 12:05:57 -03002151
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002152 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02002153
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002154 if (!hdev_is_powered(hdev)) {
Brian Gix0df4c182011-11-16 13:53:13 -08002155 err = cmd_status(sk, index, mgmt_op, MGMT_STATUS_NOT_POWERED);
2156 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002157 }
2158
Johan Hedberg272d90d2012-02-09 15:26:12 +02002159 if (type == MGMT_ADDR_BREDR)
2160 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, bdaddr);
2161 else
Brian Gix47c15e22011-11-16 13:53:14 -08002162 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, bdaddr);
Brian Gix47c15e22011-11-16 13:53:14 -08002163
Johan Hedberg272d90d2012-02-09 15:26:12 +02002164 if (!conn) {
2165 err = cmd_status(sk, index, mgmt_op,
2166 MGMT_STATUS_NOT_CONNECTED);
2167 goto done;
2168 }
2169
2170 if (type == MGMT_ADDR_LE_PUBLIC || type == MGMT_ADDR_LE_RANDOM) {
Brian Gix47c15e22011-11-16 13:53:14 -08002171 /* Continue with pairing via SMP */
Brian Gix5fe57d92011-12-21 16:12:13 -08002172 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix47c15e22011-11-16 13:53:14 -08002173
Brian Gix5fe57d92011-12-21 16:12:13 -08002174 if (!err)
2175 err = cmd_status(sk, index, mgmt_op,
2176 MGMT_STATUS_SUCCESS);
2177 else
2178 err = cmd_status(sk, index, mgmt_op,
2179 MGMT_STATUS_FAILED);
2180
Brian Gix47c15e22011-11-16 13:53:14 -08002181 goto done;
2182 }
2183
Brian Gix0df4c182011-11-16 13:53:13 -08002184 cmd = mgmt_pending_add(sk, mgmt_op, hdev, bdaddr, sizeof(*bdaddr));
Johan Hedberga5c29682011-02-19 12:05:57 -03002185 if (!cmd) {
2186 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08002187 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002188 }
2189
Brian Gix0df4c182011-11-16 13:53:13 -08002190 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08002191 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
2192 struct hci_cp_user_passkey_reply cp;
2193
2194 bacpy(&cp.bdaddr, bdaddr);
2195 cp.passkey = passkey;
2196 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
2197 } else
2198 err = hci_send_cmd(hdev, hci_op, sizeof(*bdaddr), bdaddr);
2199
Johan Hedberga664b5b2011-02-19 12:06:02 -03002200 if (err < 0)
2201 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002202
Brian Gix0df4c182011-11-16 13:53:13 -08002203done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002204 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002205 hci_dev_put(hdev);
2206
2207 return err;
2208}
2209
Brian Gix0df4c182011-11-16 13:53:13 -08002210static int user_confirm_reply(struct sock *sk, u16 index, void *data, u16 len)
2211{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002212 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002213
2214 BT_DBG("");
2215
2216 if (len != sizeof(*cp))
2217 return cmd_status(sk, index, MGMT_OP_USER_CONFIRM_REPLY,
2218 MGMT_STATUS_INVALID_PARAMS);
2219
Johan Hedberg272d90d2012-02-09 15:26:12 +02002220 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
2221 MGMT_OP_USER_CONFIRM_REPLY,
2222 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002223}
2224
2225static int user_confirm_neg_reply(struct sock *sk, u16 index, void *data,
2226 u16 len)
2227{
Johan Hedbergc9c26592011-12-15 00:47:41 +02002228 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002229
2230 BT_DBG("");
2231
2232 if (len != sizeof(*cp))
2233 return cmd_status(sk, index, MGMT_OP_USER_CONFIRM_NEG_REPLY,
2234 MGMT_STATUS_INVALID_PARAMS);
2235
Johan Hedberg272d90d2012-02-09 15:26:12 +02002236 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
2237 MGMT_OP_USER_CONFIRM_NEG_REPLY,
2238 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002239}
2240
Brian Gix604086b2011-11-23 08:28:33 -08002241static int user_passkey_reply(struct sock *sk, u16 index, void *data, u16 len)
2242{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002243 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002244
2245 BT_DBG("");
2246
2247 if (len != sizeof(*cp))
2248 return cmd_status(sk, index, MGMT_OP_USER_PASSKEY_REPLY,
2249 EINVAL);
2250
Johan Hedberg272d90d2012-02-09 15:26:12 +02002251 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
2252 MGMT_OP_USER_PASSKEY_REPLY,
2253 HCI_OP_USER_PASSKEY_REPLY,
2254 cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08002255}
2256
2257static int user_passkey_neg_reply(struct sock *sk, u16 index, void *data,
2258 u16 len)
2259{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002260 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002261
2262 BT_DBG("");
2263
2264 if (len != sizeof(*cp))
2265 return cmd_status(sk, index, MGMT_OP_USER_PASSKEY_NEG_REPLY,
2266 EINVAL);
2267
Johan Hedberg272d90d2012-02-09 15:26:12 +02002268 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
2269 MGMT_OP_USER_PASSKEY_NEG_REPLY,
2270 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08002271}
2272
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002273static int set_local_name(struct sock *sk, u16 index, void *data,
Johan Hedbergb312b1612011-03-16 14:29:37 +02002274 u16 len)
2275{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002276 struct mgmt_cp_set_local_name *mgmt_cp = data;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002277 struct hci_cp_write_local_name hci_cp;
2278 struct hci_dev *hdev;
2279 struct pending_cmd *cmd;
2280 int err;
2281
2282 BT_DBG("");
2283
2284 if (len != sizeof(*mgmt_cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02002285 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME,
2286 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002287
2288 hdev = hci_dev_get(index);
2289 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002290 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME,
2291 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002292
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002293 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002294
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002295 memcpy(hdev->short_name, mgmt_cp->short_name,
2296 sizeof(hdev->short_name));
2297
Johan Hedbergb5235a62012-02-21 14:32:24 +02002298 if (!hdev_is_powered(hdev)) {
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002299 memcpy(hdev->dev_name, mgmt_cp->name, sizeof(hdev->dev_name));
2300
2301 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
2302 data, len);
2303 if (err < 0)
2304 goto failed;
2305
2306 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data, len,
2307 sk);
2308
Johan Hedbergb5235a62012-02-21 14:32:24 +02002309 goto failed;
2310 }
2311
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002312 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002313 if (!cmd) {
2314 err = -ENOMEM;
2315 goto failed;
2316 }
2317
2318 memcpy(hci_cp.name, mgmt_cp->name, sizeof(hci_cp.name));
2319 err = hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(hci_cp),
2320 &hci_cp);
2321 if (err < 0)
2322 mgmt_pending_remove(cmd);
2323
2324failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002325 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002326 hci_dev_put(hdev);
2327
2328 return err;
2329}
2330
Szymon Jancc35938b2011-03-22 13:12:21 +01002331static int read_local_oob_data(struct sock *sk, u16 index)
2332{
2333 struct hci_dev *hdev;
2334 struct pending_cmd *cmd;
2335 int err;
2336
2337 BT_DBG("hci%u", index);
2338
2339 hdev = hci_dev_get(index);
2340 if (!hdev)
2341 return cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002342 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancc35938b2011-03-22 13:12:21 +01002343
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002344 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002345
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002346 if (!hdev_is_powered(hdev)) {
Szymon Jancc35938b2011-03-22 13:12:21 +01002347 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002348 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002349 goto unlock;
2350 }
2351
2352 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
2353 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002354 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002355 goto unlock;
2356 }
2357
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002358 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02002359 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2360 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01002361 goto unlock;
2362 }
2363
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002364 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01002365 if (!cmd) {
2366 err = -ENOMEM;
2367 goto unlock;
2368 }
2369
2370 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
2371 if (err < 0)
2372 mgmt_pending_remove(cmd);
2373
2374unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002375 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002376 hci_dev_put(hdev);
2377
2378 return err;
2379}
2380
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002381static int add_remote_oob_data(struct sock *sk, u16 index, void *data,
2382 u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002383{
2384 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002385 struct mgmt_cp_add_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002386 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002387 int err;
2388
2389 BT_DBG("hci%u ", index);
2390
2391 if (len != sizeof(*cp))
2392 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002393 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01002394
2395 hdev = hci_dev_get(index);
2396 if (!hdev)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002397 return cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
2398 MGMT_STATUS_INVALID_PARAMS,
2399 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002400
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002401 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002402
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002403 if (!hdev_is_powered(hdev)) {
2404 err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
2405 MGMT_STATUS_NOT_POWERED,
2406 &cp->addr, sizeof(cp->addr));
2407 goto unlock;
2408 }
2409
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002410 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, cp->hash,
Szymon Janc2763eda2011-03-22 13:12:22 +01002411 cp->randomizer);
2412 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002413 status = MGMT_STATUS_FAILED;
Szymon Janc2763eda2011-03-22 13:12:22 +01002414 else
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002415 status = 0;
2416
2417 err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, status,
2418 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002419
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002420unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002421 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002422 hci_dev_put(hdev);
2423
2424 return err;
2425}
2426
2427static int remove_remote_oob_data(struct sock *sk, u16 index,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002428 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002429{
2430 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002431 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002432 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002433 int err;
2434
2435 BT_DBG("hci%u ", index);
2436
2437 if (len != sizeof(*cp))
2438 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002439 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01002440
2441 hdev = hci_dev_get(index);
2442 if (!hdev)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002443 return cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2444 MGMT_STATUS_INVALID_PARAMS,
2445 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002446
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002447 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002448
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002449 if (!hdev_is_powered(hdev)) {
2450 err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2451 MGMT_STATUS_NOT_POWERED,
2452 &cp->addr, sizeof(cp->addr));
2453 goto unlock;
2454 }
2455
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002456 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr);
Szymon Janc2763eda2011-03-22 13:12:22 +01002457 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002458 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01002459 else
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002460 status = 0;
2461
2462 err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA, status,
2463 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002464
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002465unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002466 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002467 hci_dev_put(hdev);
2468
2469 return err;
2470}
2471
Andre Guedes5e0452c2012-02-17 20:39:38 -03002472static int discovery(struct hci_dev *hdev)
2473{
2474 int err;
2475
2476 if (lmp_host_le_capable(hdev)) {
2477 if (lmp_bredr_capable(hdev)) {
2478 err = hci_le_scan(hdev, LE_SCAN_TYPE,
2479 LE_SCAN_INT, LE_SCAN_WIN,
2480 LE_SCAN_TIMEOUT_BREDR_LE);
2481 } else {
2482 hdev->discovery.type = DISCOV_TYPE_LE;
2483 err = hci_le_scan(hdev, LE_SCAN_TYPE,
2484 LE_SCAN_INT, LE_SCAN_WIN,
2485 LE_SCAN_TIMEOUT_LE_ONLY);
2486 }
2487 } else {
2488 hdev->discovery.type = DISCOV_TYPE_BREDR;
2489 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
2490 }
2491
2492 return err;
2493}
2494
2495int mgmt_interleaved_discovery(struct hci_dev *hdev)
2496{
2497 int err;
2498
2499 BT_DBG("%s", hdev->name);
2500
2501 hci_dev_lock(hdev);
2502
2503 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR_LE);
2504 if (err < 0)
2505 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2506
2507 hci_dev_unlock(hdev);
2508
2509 return err;
2510}
2511
Johan Hedberg450dfda2011-11-12 11:58:22 +02002512static int start_discovery(struct sock *sk, u16 index,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002513 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002514{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002515 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002516 struct pending_cmd *cmd;
2517 struct hci_dev *hdev;
2518 int err;
2519
2520 BT_DBG("hci%u", index);
2521
Johan Hedberg450dfda2011-11-12 11:58:22 +02002522 if (len != sizeof(*cp))
2523 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2524 MGMT_STATUS_INVALID_PARAMS);
2525
Johan Hedberg14a53662011-04-27 10:29:56 -04002526 hdev = hci_dev_get(index);
2527 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002528 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2529 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg14a53662011-04-27 10:29:56 -04002530
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002531 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002532
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002533 if (!hdev_is_powered(hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02002534 err = cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2535 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02002536 goto failed;
2537 }
2538
Johan Hedbergff9ef572012-01-04 14:23:45 +02002539 if (hdev->discovery.state != DISCOVERY_STOPPED) {
2540 err = cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2541 MGMT_STATUS_BUSY);
2542 goto failed;
2543 }
2544
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002545 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002546 if (!cmd) {
2547 err = -ENOMEM;
2548 goto failed;
2549 }
2550
Andre Guedes4aab14e2012-02-17 20:39:36 -03002551 hdev->discovery.type = cp->type;
2552
2553 switch (hdev->discovery.type) {
Andre Guedesf39799f2012-02-17 20:39:35 -03002554 case DISCOV_TYPE_BREDR:
Andre Guedes3fd24152012-02-03 17:48:01 -03002555 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
Andre Guedesf39799f2012-02-17 20:39:35 -03002556 break;
2557
2558 case DISCOV_TYPE_LE:
Andre Guedes3fd24152012-02-03 17:48:01 -03002559 err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT,
2560 LE_SCAN_WIN, LE_SCAN_TIMEOUT_LE_ONLY);
Andre Guedesf39799f2012-02-17 20:39:35 -03002561 break;
2562
Andre Guedes5e0452c2012-02-17 20:39:38 -03002563 case DISCOV_TYPE_INTERLEAVED:
2564 err = discovery(hdev);
2565 break;
2566
Andre Guedesf39799f2012-02-17 20:39:35 -03002567 default:
Andre Guedes3fd24152012-02-03 17:48:01 -03002568 err = -EINVAL;
Andre Guedesf39799f2012-02-17 20:39:35 -03002569 }
Andre Guedes3fd24152012-02-03 17:48:01 -03002570
Johan Hedberg14a53662011-04-27 10:29:56 -04002571 if (err < 0)
2572 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002573 else
2574 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002575
2576failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002577 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002578 hci_dev_put(hdev);
2579
2580 return err;
2581}
2582
Johan Hedbergd9306502012-02-20 23:25:18 +02002583static int stop_discovery(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002584{
Johan Hedbergd9306502012-02-20 23:25:18 +02002585 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002586 struct hci_dev *hdev;
2587 struct pending_cmd *cmd;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002588 struct hci_cp_remote_name_req_cancel cp;
2589 struct inquiry_entry *e;
Johan Hedberg14a53662011-04-27 10:29:56 -04002590 int err;
2591
2592 BT_DBG("hci%u", index);
2593
Johan Hedbergd9306502012-02-20 23:25:18 +02002594 if (len != sizeof(*mgmt_cp))
2595 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY,
2596 MGMT_STATUS_INVALID_PARAMS);
2597
Johan Hedberg14a53662011-04-27 10:29:56 -04002598 hdev = hci_dev_get(index);
2599 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002600 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY,
2601 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg14a53662011-04-27 10:29:56 -04002602
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002603 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002604
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002605 if (!hci_discovery_active(hdev)) {
Johan Hedbergd9306502012-02-20 23:25:18 +02002606 err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY,
2607 MGMT_STATUS_REJECTED,
2608 &mgmt_cp->type, sizeof(mgmt_cp->type));
2609 goto unlock;
2610 }
2611
2612 if (hdev->discovery.type != mgmt_cp->type) {
2613 err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY,
2614 MGMT_STATUS_INVALID_PARAMS,
2615 &mgmt_cp->type, sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002616 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02002617 }
2618
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002619 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002620 if (!cmd) {
2621 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002622 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04002623 }
2624
Andre Guedes343f9352012-02-17 20:39:37 -03002625 if (hdev->discovery.state == DISCOVERY_FINDING) {
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002626 err = hci_cancel_inquiry(hdev);
2627 if (err < 0)
2628 mgmt_pending_remove(cmd);
2629 else
2630 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
2631 goto unlock;
2632 }
2633
2634 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY, NAME_PENDING);
2635 if (!e) {
2636 mgmt_pending_remove(cmd);
Johan Hedbergaee9b212012-02-18 15:07:59 +02002637 err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY, 0,
Johan Hedbergd9306502012-02-20 23:25:18 +02002638 &mgmt_cp->type, sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002639 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2640 goto unlock;
2641 }
2642
2643 bacpy(&cp.bdaddr, &e->data.bdaddr);
2644 err = hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ_CANCEL,
2645 sizeof(cp), &cp);
Johan Hedberg14a53662011-04-27 10:29:56 -04002646 if (err < 0)
2647 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002648 else
2649 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002650
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002651unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002652 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002653 hci_dev_put(hdev);
2654
2655 return err;
2656}
2657
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002658static int confirm_name(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02002659{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002660 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002661 struct inquiry_entry *e;
2662 struct hci_dev *hdev;
2663 int err;
2664
2665 BT_DBG("hci%u", index);
2666
2667 if (len != sizeof(*cp))
2668 return cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2669 MGMT_STATUS_INVALID_PARAMS);
2670
2671 hdev = hci_dev_get(index);
2672 if (!hdev)
2673 return cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2674 MGMT_STATUS_INVALID_PARAMS);
2675
2676 hci_dev_lock(hdev);
2677
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002678 if (!hci_discovery_active(hdev)) {
2679 err = cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2680 MGMT_STATUS_FAILED);
2681 goto failed;
2682 }
2683
Johan Hedberga198e7b2012-02-17 14:27:06 +02002684 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002685 if (!e) {
Marcel Holtmanne5f0e152012-02-22 11:59:01 +01002686 err = cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
Johan Hedberg561aafb2012-01-04 13:31:59 +02002687 MGMT_STATUS_INVALID_PARAMS);
2688 goto failed;
2689 }
2690
2691 if (cp->name_known) {
2692 e->name_state = NAME_KNOWN;
2693 list_del(&e->list);
2694 } else {
2695 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e202012-01-09 00:53:02 +02002696 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002697 }
2698
2699 err = 0;
2700
2701failed:
2702 hci_dev_unlock(hdev);
2703
2704 return err;
2705}
2706
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002707static int block_device(struct sock *sk, u16 index, void *data, u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002708{
2709 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002710 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002711 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03002712 int err;
2713
2714 BT_DBG("hci%u", index);
2715
Antti Julku7fbec222011-06-15 12:01:15 +03002716 if (len != sizeof(*cp))
2717 return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002718 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002719
2720 hdev = hci_dev_get(index);
2721 if (!hdev)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002722 return cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE,
2723 MGMT_STATUS_INVALID_PARAMS,
2724 &cp->addr, sizeof(cp->addr));
Antti Julku7fbec222011-06-15 12:01:15 +03002725
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002726 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002727
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002728 err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002729 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002730 status = MGMT_STATUS_FAILED;
Antti Julku7fbec222011-06-15 12:01:15 +03002731 else
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002732 status = 0;
2733
2734 err = cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE, status,
2735 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03002736
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002737 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002738 hci_dev_put(hdev);
2739
2740 return err;
2741}
2742
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002743static int unblock_device(struct sock *sk, u16 index, void *data, u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002744{
2745 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002746 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002747 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03002748 int err;
2749
2750 BT_DBG("hci%u", index);
2751
Antti Julku7fbec222011-06-15 12:01:15 +03002752 if (len != sizeof(*cp))
2753 return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002754 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002755
2756 hdev = hci_dev_get(index);
2757 if (!hdev)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002758 return cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE,
2759 MGMT_STATUS_INVALID_PARAMS,
2760 &cp->addr, sizeof(cp->addr));
Antti Julku7fbec222011-06-15 12:01:15 +03002761
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002762 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002763
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002764 err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002765 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002766 status = MGMT_STATUS_INVALID_PARAMS;
Antti Julku7fbec222011-06-15 12:01:15 +03002767 else
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002768 status = 0;
2769
2770 err = cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE, status,
2771 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03002772
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002773 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002774 hci_dev_put(hdev);
2775
2776 return err;
2777}
2778
Antti Julkuf6422ec2011-06-22 13:11:56 +03002779static int set_fast_connectable(struct sock *sk, u16 index,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002780 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03002781{
2782 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002783 struct mgmt_mode *cp = data;
Antti Julkuf6422ec2011-06-22 13:11:56 +03002784 struct hci_cp_write_page_scan_activity acp;
2785 u8 type;
2786 int err;
2787
2788 BT_DBG("hci%u", index);
2789
2790 if (len != sizeof(*cp))
2791 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002792 MGMT_STATUS_INVALID_PARAMS);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002793
2794 hdev = hci_dev_get(index);
2795 if (!hdev)
2796 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002797 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg5400c042012-02-21 16:40:33 +02002798 if (!hdev_is_powered(hdev))
2799 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
2800 MGMT_STATUS_NOT_POWERED);
2801
2802 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
2803 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
2804 MGMT_STATUS_REJECTED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002805
2806 hci_dev_lock(hdev);
2807
Johan Hedbergf7c6869ce2011-12-15 00:47:36 +02002808 if (cp->val) {
Antti Julkuf6422ec2011-06-22 13:11:56 +03002809 type = PAGE_SCAN_TYPE_INTERLACED;
2810 acp.interval = 0x0024; /* 22.5 msec page scan interval */
2811 } else {
2812 type = PAGE_SCAN_TYPE_STANDARD; /* default */
2813 acp.interval = 0x0800; /* default 1.28 sec page scan */
2814 }
2815
2816 acp.window = 0x0012; /* default 11.25 msec page scan window */
2817
2818 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
2819 sizeof(acp), &acp);
2820 if (err < 0) {
2821 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002822 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002823 goto done;
2824 }
2825
2826 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
2827 if (err < 0) {
2828 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002829 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002830 goto done;
2831 }
2832
Johan Hedbergaee9b212012-02-18 15:07:59 +02002833 err = cmd_complete(sk, index, MGMT_OP_SET_FAST_CONNECTABLE, 0,
2834 NULL, 0);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002835done:
2836 hci_dev_unlock(hdev);
2837 hci_dev_put(hdev);
2838
2839 return err;
2840}
2841
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002842static int load_long_term_keys(struct sock *sk, u16 index,
2843 void *cp_data, u16 len)
2844{
2845 struct hci_dev *hdev;
2846 struct mgmt_cp_load_long_term_keys *cp = cp_data;
2847 u16 key_count, expected_len;
2848 int i;
2849
2850 if (len < sizeof(*cp))
2851 return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS,
2852 EINVAL);
2853
2854 key_count = get_unaligned_le16(&cp->key_count);
2855
2856 expected_len = sizeof(*cp) + key_count *
2857 sizeof(struct mgmt_ltk_info);
2858 if (expected_len != len) {
2859 BT_ERR("load_keys: expected %u bytes, got %u bytes",
2860 len, expected_len);
2861 return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS,
2862 EINVAL);
2863 }
2864
2865 hdev = hci_dev_get(index);
2866 if (!hdev)
2867 return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS,
2868 ENODEV);
2869
2870 BT_DBG("hci%u key_count %u", index, key_count);
2871
2872 hci_dev_lock(hdev);
2873
2874 hci_smp_ltks_clear(hdev);
2875
2876 for (i = 0; i < key_count; i++) {
2877 struct mgmt_ltk_info *key = &cp->keys[i];
2878 u8 type;
2879
2880 if (key->master)
2881 type = HCI_SMP_LTK;
2882 else
2883 type = HCI_SMP_LTK_SLAVE;
2884
2885 hci_add_ltk(hdev, &key->addr.bdaddr, key->addr.type,
2886 type, 0, key->authenticated, key->val,
2887 key->enc_size, key->ediv, key->rand);
2888 }
2889
2890 hci_dev_unlock(hdev);
2891 hci_dev_put(hdev);
2892
2893 return 0;
2894}
2895
Johan Hedberg03811012010-12-08 00:21:06 +02002896int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
2897{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002898 void *buf;
2899 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02002900 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002901 u16 opcode, index, len;
Johan Hedberg03811012010-12-08 00:21:06 +02002902 int err;
2903
2904 BT_DBG("got %zu bytes", msglen);
2905
2906 if (msglen < sizeof(*hdr))
2907 return -EINVAL;
2908
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03002909 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02002910 if (!buf)
2911 return -ENOMEM;
2912
2913 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
2914 err = -EFAULT;
2915 goto done;
2916 }
2917
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002918 hdr = buf;
Johan Hedberg03811012010-12-08 00:21:06 +02002919 opcode = get_unaligned_le16(&hdr->opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002920 index = get_unaligned_le16(&hdr->index);
Johan Hedberg03811012010-12-08 00:21:06 +02002921 len = get_unaligned_le16(&hdr->len);
2922
2923 if (len != msglen - sizeof(*hdr)) {
2924 err = -EINVAL;
2925 goto done;
2926 }
2927
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002928 cp = buf + sizeof(*hdr);
2929
Johan Hedberg03811012010-12-08 00:21:06 +02002930 switch (opcode) {
Johan Hedberg02d98122010-12-13 21:07:04 +02002931 case MGMT_OP_READ_VERSION:
2932 err = read_version(sk);
2933 break;
Johan Hedberge70bb2e2012-02-13 16:59:33 +02002934 case MGMT_OP_READ_COMMANDS:
2935 err = read_commands(sk);
2936 break;
Johan Hedbergfaba42e2010-12-13 21:07:05 +02002937 case MGMT_OP_READ_INDEX_LIST:
2938 err = read_index_list(sk);
2939 break;
Johan Hedbergf7b64e692010-12-13 21:07:06 +02002940 case MGMT_OP_READ_INFO:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002941 err = read_controller_info(sk, index);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02002942 break;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002943 case MGMT_OP_SET_POWERED:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002944 err = set_powered(sk, index, cp, len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002945 break;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002946 case MGMT_OP_SET_DISCOVERABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002947 err = set_discoverable(sk, index, cp, len);
Johan Hedberg73f22f62010-12-29 16:00:25 +02002948 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002949 case MGMT_OP_SET_CONNECTABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002950 err = set_connectable(sk, index, cp, len);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002951 break;
Johan Hedbergf7c6869ce2011-12-15 00:47:36 +02002952 case MGMT_OP_SET_FAST_CONNECTABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002953 err = set_fast_connectable(sk, index, cp, len);
Johan Hedbergf7c6869ce2011-12-15 00:47:36 +02002954 break;
Johan Hedbergc542a062011-01-26 13:11:03 +02002955 case MGMT_OP_SET_PAIRABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002956 err = set_pairable(sk, index, cp, len);
Johan Hedbergc542a062011-01-26 13:11:03 +02002957 break;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02002958 case MGMT_OP_SET_LINK_SECURITY:
2959 err = set_link_security(sk, index, cp, len);
2960 break;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02002961 case MGMT_OP_SET_SSP:
2962 err = set_ssp(sk, index, cp, len);
2963 break;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02002964 case MGMT_OP_SET_HS:
2965 err = set_hs(sk, index, cp, len);
2966 break;
Johan Hedberg06199cf2012-02-22 16:37:11 +02002967 case MGMT_OP_SET_LE:
2968 err = set_le(sk, index, cp, len);
2969 break;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002970 case MGMT_OP_ADD_UUID:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002971 err = add_uuid(sk, index, cp, len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002972 break;
2973 case MGMT_OP_REMOVE_UUID:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002974 err = remove_uuid(sk, index, cp, len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002975 break;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002976 case MGMT_OP_SET_DEV_CLASS:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002977 err = set_dev_class(sk, index, cp, len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002978 break;
Johan Hedberg86742e12011-11-07 23:13:38 +02002979 case MGMT_OP_LOAD_LINK_KEYS:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002980 err = load_link_keys(sk, index, cp, len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002981 break;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002982 case MGMT_OP_DISCONNECT:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002983 err = disconnect(sk, index, cp, len);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002984 break;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002985 case MGMT_OP_GET_CONNECTIONS:
Szymon Janc8ce62842011-03-01 16:55:32 +01002986 err = get_connections(sk, index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002987 break;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002988 case MGMT_OP_PIN_CODE_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002989 err = pin_code_reply(sk, index, cp, len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002990 break;
2991 case MGMT_OP_PIN_CODE_NEG_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002992 err = pin_code_neg_reply(sk, index, cp, len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002993 break;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002994 case MGMT_OP_SET_IO_CAPABILITY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002995 err = set_io_capability(sk, index, cp, len);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002996 break;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002997 case MGMT_OP_PAIR_DEVICE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002998 err = pair_device(sk, index, cp, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002999 break;
Johan Hedberg28424702012-02-02 04:02:29 +02003000 case MGMT_OP_CANCEL_PAIR_DEVICE:
3001 err = cancel_pair_device(sk, index, buf + sizeof(*hdr), len);
3002 break;
Johan Hedberg124f6e32012-02-09 13:50:12 +02003003 case MGMT_OP_UNPAIR_DEVICE:
3004 err = unpair_device(sk, index, cp, len);
3005 break;
Johan Hedberga5c29682011-02-19 12:05:57 -03003006 case MGMT_OP_USER_CONFIRM_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003007 err = user_confirm_reply(sk, index, cp, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03003008 break;
3009 case MGMT_OP_USER_CONFIRM_NEG_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003010 err = user_confirm_neg_reply(sk, index, cp, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03003011 break;
Brian Gix604086b2011-11-23 08:28:33 -08003012 case MGMT_OP_USER_PASSKEY_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003013 err = user_passkey_reply(sk, index, cp, len);
Brian Gix604086b2011-11-23 08:28:33 -08003014 break;
3015 case MGMT_OP_USER_PASSKEY_NEG_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003016 err = user_passkey_neg_reply(sk, index, cp, len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003017 break;
Johan Hedbergb312b1612011-03-16 14:29:37 +02003018 case MGMT_OP_SET_LOCAL_NAME:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003019 err = set_local_name(sk, index, cp, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003020 break;
Szymon Jancc35938b2011-03-22 13:12:21 +01003021 case MGMT_OP_READ_LOCAL_OOB_DATA:
3022 err = read_local_oob_data(sk, index);
3023 break;
Szymon Janc2763eda2011-03-22 13:12:22 +01003024 case MGMT_OP_ADD_REMOTE_OOB_DATA:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003025 err = add_remote_oob_data(sk, index, cp, len);
Szymon Janc2763eda2011-03-22 13:12:22 +01003026 break;
3027 case MGMT_OP_REMOVE_REMOTE_OOB_DATA:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003028 err = remove_remote_oob_data(sk, index, cp, len);
Szymon Janc2763eda2011-03-22 13:12:22 +01003029 break;
Johan Hedberg14a53662011-04-27 10:29:56 -04003030 case MGMT_OP_START_DISCOVERY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003031 err = start_discovery(sk, index, cp, len);
Johan Hedberg14a53662011-04-27 10:29:56 -04003032 break;
3033 case MGMT_OP_STOP_DISCOVERY:
Johan Hedbergd9306502012-02-20 23:25:18 +02003034 err = stop_discovery(sk, index, cp, len);
Johan Hedberg14a53662011-04-27 10:29:56 -04003035 break;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003036 case MGMT_OP_CONFIRM_NAME:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003037 err = confirm_name(sk, index, cp, len);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003038 break;
Antti Julku7fbec222011-06-15 12:01:15 +03003039 case MGMT_OP_BLOCK_DEVICE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003040 err = block_device(sk, index, cp, len);
Antti Julku7fbec222011-06-15 12:01:15 +03003041 break;
3042 case MGMT_OP_UNBLOCK_DEVICE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003043 err = unblock_device(sk, index, cp, len);
Antti Julku7fbec222011-06-15 12:01:15 +03003044 break;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003045 case MGMT_OP_LOAD_LONG_TERM_KEYS:
3046 err = load_long_term_keys(sk, index, cp, len);
3047 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003048 default:
Johan Hedberg72a734e2010-12-30 00:38:22 +02003049 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02003050 err = cmd_status(sk, index, opcode,
3051 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003052 break;
3053 }
Johan Hedberg72a734e2010-12-30 00:38:22 +02003054
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003055 if (err < 0)
Johan Hedberg72a734e2010-12-30 00:38:22 +02003056 goto done;
3057
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003058 err = msglen;
3059
3060done:
3061 kfree(buf);
3062 return err;
3063}
3064
Johan Hedbergb24752f2011-11-03 14:40:33 +02003065static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
3066{
3067 u8 *status = data;
3068
3069 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
3070 mgmt_pending_remove(cmd);
3071}
3072
Johan Hedberg744cf192011-11-08 20:40:14 +02003073int mgmt_index_added(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +02003074{
Johan Hedberg744cf192011-11-08 20:40:14 +02003075 return mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02003076}
3077
Johan Hedberg744cf192011-11-08 20:40:14 +02003078int mgmt_index_removed(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +02003079{
Johan Hedbergb24752f2011-11-03 14:40:33 +02003080 u8 status = ENODEV;
3081
Johan Hedberg744cf192011-11-08 20:40:14 +02003082 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02003083
Johan Hedberg744cf192011-11-08 20:40:14 +02003084 return mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02003085}
3086
3087struct cmd_lookup {
Johan Hedberg03811012010-12-08 00:21:06 +02003088 struct sock *sk;
Johan Hedberg69ab39e2011-12-15 00:47:35 +02003089 struct hci_dev *hdev;
Johan Hedberg03811012010-12-08 00:21:06 +02003090};
3091
Johan Hedberg69ab39e2011-12-15 00:47:35 +02003092static void settings_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberg03811012010-12-08 00:21:06 +02003093{
Johan Hedberg03811012010-12-08 00:21:06 +02003094 struct cmd_lookup *match = data;
3095
Johan Hedberg69ab39e2011-12-15 00:47:35 +02003096 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02003097
3098 list_del(&cmd->list);
3099
3100 if (match->sk == NULL) {
3101 match->sk = cmd->sk;
3102 sock_hold(match->sk);
3103 }
3104
3105 mgmt_pending_free(cmd);
3106}
3107
Johan Hedberg744cf192011-11-08 20:40:14 +02003108int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg03811012010-12-08 00:21:06 +02003109{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02003110 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003111 int err;
Johan Hedberg03811012010-12-08 00:21:06 +02003112
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003113 if (!test_bit(HCI_MGMT, &hdev->dev_flags))
3114 return 0;
3115
Johan Hedberg69ab39e2011-12-15 00:47:35 +02003116 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
Johan Hedberg03811012010-12-08 00:21:06 +02003117
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003118 if (powered) {
3119 u8 scan = 0;
3120
3121 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3122 scan |= SCAN_PAGE;
3123 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3124 scan |= SCAN_INQUIRY;
3125
3126 if (scan)
3127 hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
Johan Hedberg504c8dc2012-02-23 13:30:41 +02003128
3129 update_class(hdev);
3130 update_eir(hdev);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003131 } else {
Johan Hedbergb24752f2011-11-03 14:40:33 +02003132 u8 status = ENETDOWN;
Johan Hedberg744cf192011-11-08 20:40:14 +02003133 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02003134 }
3135
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003136 err = new_settings(hdev, match.sk);
Johan Hedberg03811012010-12-08 00:21:06 +02003137
3138 if (match.sk)
3139 sock_put(match.sk);
3140
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003141 return err;
Johan Hedberg03811012010-12-08 00:21:06 +02003142}
3143
Johan Hedberg744cf192011-11-08 20:40:14 +02003144int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg03811012010-12-08 00:21:06 +02003145{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02003146 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003147 bool changed = false;
3148 int err = 0;
Johan Hedberg03811012010-12-08 00:21:06 +02003149
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003150 if (discoverable) {
3151 if (!test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3152 changed = true;
3153 } else {
3154 if (test_and_clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3155 changed = true;
3156 }
Johan Hedberg03811012010-12-08 00:21:06 +02003157
Johan Hedberged9b5f22012-02-21 20:47:06 +02003158 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp,
3159 &match);
3160
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003161 if (changed)
3162 err = new_settings(hdev, match.sk);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003163
Johan Hedberg03811012010-12-08 00:21:06 +02003164 if (match.sk)
3165 sock_put(match.sk);
3166
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003167 return err;
Johan Hedberg03811012010-12-08 00:21:06 +02003168}
3169
Johan Hedberg744cf192011-11-08 20:40:14 +02003170int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg03811012010-12-08 00:21:06 +02003171{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02003172 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003173 bool changed = false;
3174 int err = 0;
Johan Hedberg03811012010-12-08 00:21:06 +02003175
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003176 if (connectable) {
3177 if (!test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3178 changed = true;
3179 } else {
3180 if (test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3181 changed = true;
3182 }
Johan Hedberg03811012010-12-08 00:21:06 +02003183
Johan Hedberged9b5f22012-02-21 20:47:06 +02003184 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev, settings_rsp,
3185 &match);
3186
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003187 if (changed)
3188 err = new_settings(hdev, match.sk);
Johan Hedberg03811012010-12-08 00:21:06 +02003189
3190 if (match.sk)
3191 sock_put(match.sk);
3192
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003193 return err;
Johan Hedberg03811012010-12-08 00:21:06 +02003194}
3195
Johan Hedberg744cf192011-11-08 20:40:14 +02003196int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003197{
Johan Hedbergca69b792011-11-11 18:10:00 +02003198 u8 mgmt_err = mgmt_status(status);
3199
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003200 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02003201 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Johan Hedbergca69b792011-11-11 18:10:00 +02003202 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003203
3204 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02003205 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Johan Hedbergca69b792011-11-11 18:10:00 +02003206 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003207
3208 return 0;
3209}
3210
Johan Hedberg744cf192011-11-08 20:40:14 +02003211int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
3212 u8 persistent)
Johan Hedberg03811012010-12-08 00:21:06 +02003213{
Johan Hedberg86742e12011-11-07 23:13:38 +02003214 struct mgmt_ev_new_link_key ev;
Johan Hedberg03811012010-12-08 00:21:06 +02003215
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003216 memset(&ev, 0, sizeof(ev));
Johan Hedberg03811012010-12-08 00:21:06 +02003217
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003218 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02003219 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
3220 ev.key.addr.type = MGMT_ADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003221 ev.key.type = key->type;
3222 memcpy(ev.key.val, key->val, 16);
3223 ev.key.pin_len = key->pin_len;
Johan Hedberg03811012010-12-08 00:21:06 +02003224
Johan Hedberg744cf192011-11-08 20:40:14 +02003225 return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02003226}
Johan Hedbergf7520542011-01-20 12:34:39 +02003227
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003228int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
3229{
3230 struct mgmt_ev_new_long_term_key ev;
3231
3232 memset(&ev, 0, sizeof(ev));
3233
3234 ev.store_hint = persistent;
3235 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
3236 ev.key.addr.type = key->bdaddr_type;
3237 ev.key.authenticated = key->authenticated;
3238 ev.key.enc_size = key->enc_size;
3239 ev.key.ediv = key->ediv;
3240
3241 if (key->type == HCI_SMP_LTK)
3242 ev.key.master = 1;
3243
3244 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
3245 memcpy(ev.key.val, key->val, sizeof(key->val));
3246
3247 return mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev,
3248 &ev, sizeof(ev), NULL);
3249}
3250
Johan Hedbergafc747a2012-01-15 18:11:07 +02003251int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Johan Hedbergb644ba32012-01-17 21:48:47 +02003252 u8 addr_type, u8 *name, u8 name_len,
3253 u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02003254{
Johan Hedbergb644ba32012-01-17 21:48:47 +02003255 char buf[512];
3256 struct mgmt_ev_device_connected *ev = (void *) buf;
3257 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02003258
Johan Hedbergb644ba32012-01-17 21:48:47 +02003259 bacpy(&ev->addr.bdaddr, bdaddr);
3260 ev->addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02003261
Johan Hedbergb644ba32012-01-17 21:48:47 +02003262 if (name_len > 0)
3263 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
3264 name, name_len);
3265
3266 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
3267 eir_len = eir_append_data(&ev->eir[eir_len], eir_len,
3268 EIR_CLASS_OF_DEV, dev_class, 3);
3269
3270 put_unaligned_le16(eir_len, &ev->eir_len);
3271
3272 return mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
3273 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02003274}
3275
Johan Hedberg8962ee72011-01-20 12:40:27 +02003276static void disconnect_rsp(struct pending_cmd *cmd, void *data)
3277{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01003278 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003279 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02003280 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003281
Johan Hedberg88c3df12012-02-09 14:27:38 +02003282 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3283 rp.addr.type = cp->addr.type;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003284
Johan Hedbergaee9b212012-02-18 15:07:59 +02003285 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, 0, &rp,
3286 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003287
3288 *sk = cmd->sk;
3289 sock_hold(*sk);
3290
Johan Hedberga664b5b2011-02-19 12:06:02 -03003291 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003292}
3293
Johan Hedberg124f6e32012-02-09 13:50:12 +02003294static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02003295{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003296 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02003297 struct mgmt_cp_unpair_device *cp = cmd->param;
3298 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02003299
3300 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02003301 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3302 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02003303
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003304 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
3305
Johan Hedbergaee9b212012-02-18 15:07:59 +02003306 cmd_complete(cmd->sk, cmd->index, cmd->opcode, 0, &rp, sizeof(rp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02003307
3308 mgmt_pending_remove(cmd);
3309}
3310
Johan Hedbergafc747a2012-01-15 18:11:07 +02003311int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
3312 u8 link_type, u8 addr_type)
Johan Hedbergf7520542011-01-20 12:34:39 +02003313{
Johan Hedberg4c659c32011-11-07 23:13:39 +02003314 struct mgmt_addr_info ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003315 struct sock *sk = NULL;
3316 int err;
3317
Johan Hedberg744cf192011-11-08 20:40:14 +02003318 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02003319
Johan Hedbergf7520542011-01-20 12:34:39 +02003320 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02003321 ev.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02003322
Johan Hedbergafc747a2012-01-15 18:11:07 +02003323 err = mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev),
3324 sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003325
3326 if (sk)
3327 sock_put(sk);
3328
Johan Hedberg124f6e32012-02-09 13:50:12 +02003329 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003330 hdev);
Johan Hedberga8a1d192011-11-10 15:54:38 +02003331
Johan Hedberg8962ee72011-01-20 12:40:27 +02003332 return err;
3333}
3334
Johan Hedberg88c3df12012-02-09 14:27:38 +02003335int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
3336 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02003337{
Johan Hedberg88c3df12012-02-09 14:27:38 +02003338 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003339 struct pending_cmd *cmd;
3340 int err;
3341
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003342 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003343 if (!cmd)
3344 return -ENOENT;
3345
Johan Hedberg88c3df12012-02-09 14:27:38 +02003346 bacpy(&rp.addr.bdaddr, bdaddr);
3347 rp.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02003348
Johan Hedberg88c3df12012-02-09 14:27:38 +02003349 err = cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
Johan Hedbergaee9b212012-02-18 15:07:59 +02003350 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003351
Johan Hedberga664b5b2011-02-19 12:06:02 -03003352 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003353
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003354 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
3355 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003356 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02003357}
Johan Hedberg17d5c042011-01-22 06:09:08 +02003358
Johan Hedberg48264f02011-11-09 13:58:58 +02003359int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
3360 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02003361{
3362 struct mgmt_ev_connect_failed ev;
3363
Johan Hedberg4c659c32011-11-07 23:13:39 +02003364 bacpy(&ev.addr.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02003365 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003366 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003367
Johan Hedberg744cf192011-11-08 20:40:14 +02003368 return mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003369}
Johan Hedberg980e1a52011-01-22 06:10:07 +02003370
Johan Hedberg744cf192011-11-08 20:40:14 +02003371int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003372{
3373 struct mgmt_ev_pin_code_request ev;
3374
Johan Hedbergd8457692012-02-17 14:24:57 +02003375 bacpy(&ev.addr.bdaddr, bdaddr);
3376 ev.addr.type = MGMT_ADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02003377 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003378
Johan Hedberg744cf192011-11-08 20:40:14 +02003379 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01003380 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003381}
3382
Johan Hedberg744cf192011-11-08 20:40:14 +02003383int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3384 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003385{
3386 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003387 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003388 int err;
3389
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003390 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003391 if (!cmd)
3392 return -ENOENT;
3393
Johan Hedbergd8457692012-02-17 14:24:57 +02003394 bacpy(&rp.addr.bdaddr, bdaddr);
3395 rp.addr.type = MGMT_ADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003396
Johan Hedbergaee9b212012-02-18 15:07:59 +02003397 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
3398 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003399
Johan Hedberga664b5b2011-02-19 12:06:02 -03003400 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003401
3402 return err;
3403}
3404
Johan Hedberg744cf192011-11-08 20:40:14 +02003405int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3406 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003407{
3408 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003409 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003410 int err;
3411
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003412 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003413 if (!cmd)
3414 return -ENOENT;
3415
Johan Hedbergd8457692012-02-17 14:24:57 +02003416 bacpy(&rp.addr.bdaddr, bdaddr);
3417 rp.addr.type = MGMT_ADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003418
Johan Hedbergaee9b212012-02-18 15:07:59 +02003419 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
3420 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003421
Johan Hedberga664b5b2011-02-19 12:06:02 -03003422 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003423
3424 return err;
3425}
Johan Hedberga5c29682011-02-19 12:05:57 -03003426
Johan Hedberg744cf192011-11-08 20:40:14 +02003427int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003428 u8 link_type, u8 addr_type, __le32 value,
3429 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03003430{
3431 struct mgmt_ev_user_confirm_request ev;
3432
Johan Hedberg744cf192011-11-08 20:40:14 +02003433 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03003434
Johan Hedberg272d90d2012-02-09 15:26:12 +02003435 bacpy(&ev.addr.bdaddr, bdaddr);
3436 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07003437 ev.confirm_hint = confirm_hint;
Johan Hedberga5c29682011-02-19 12:05:57 -03003438 put_unaligned_le32(value, &ev.value);
3439
Johan Hedberg744cf192011-11-08 20:40:14 +02003440 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01003441 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03003442}
3443
Johan Hedberg272d90d2012-02-09 15:26:12 +02003444int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
3445 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08003446{
3447 struct mgmt_ev_user_passkey_request ev;
3448
3449 BT_DBG("%s", hdev->name);
3450
Johan Hedberg272d90d2012-02-09 15:26:12 +02003451 bacpy(&ev.addr.bdaddr, bdaddr);
3452 ev.addr.type = link_to_mgmt(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08003453
3454 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
3455 NULL);
3456}
3457
Brian Gix0df4c182011-11-16 13:53:13 -08003458static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003459 u8 link_type, u8 addr_type, u8 status,
3460 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03003461{
3462 struct pending_cmd *cmd;
3463 struct mgmt_rp_user_confirm_reply rp;
3464 int err;
3465
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003466 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03003467 if (!cmd)
3468 return -ENOENT;
3469
Johan Hedberg272d90d2012-02-09 15:26:12 +02003470 bacpy(&rp.addr.bdaddr, bdaddr);
3471 rp.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergaee9b212012-02-18 15:07:59 +02003472 err = cmd_complete(cmd->sk, hdev->id, opcode, mgmt_status(status),
3473 &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03003474
Johan Hedberga664b5b2011-02-19 12:06:02 -03003475 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03003476
3477 return err;
3478}
3479
Johan Hedberg744cf192011-11-08 20:40:14 +02003480int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003481 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003482{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003483 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3484 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003485}
3486
Johan Hedberg272d90d2012-02-09 15:26:12 +02003487int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3488 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003489{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003490 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3491 status, MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003492}
Johan Hedberg2a611692011-02-19 12:06:00 -03003493
Brian Gix604086b2011-11-23 08:28:33 -08003494int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003495 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003496{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003497 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3498 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003499}
3500
Johan Hedberg272d90d2012-02-09 15:26:12 +02003501int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3502 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003503{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003504 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3505 status, MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003506}
3507
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003508int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
3509 u8 addr_type, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03003510{
3511 struct mgmt_ev_auth_failed ev;
3512
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003513 bacpy(&ev.addr.bdaddr, bdaddr);
3514 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003515 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03003516
Johan Hedberg744cf192011-11-08 20:40:14 +02003517 return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03003518}
Johan Hedbergb312b1612011-03-16 14:29:37 +02003519
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003520int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
3521{
3522 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg47990ea2012-02-22 11:58:37 +02003523 bool changed = false;
3524 int err = 0;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003525
3526 if (status) {
3527 u8 mgmt_err = mgmt_status(status);
3528 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
3529 cmd_status_rsp, &mgmt_err);
3530 return 0;
3531 }
3532
Johan Hedberg47990ea2012-02-22 11:58:37 +02003533 if (test_bit(HCI_AUTH, &hdev->flags)) {
3534 if (!test_and_set_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
3535 changed = true;
3536 } else {
3537 if (test_and_clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
3538 changed = true;
3539 }
3540
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003541 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
3542 &match);
3543
Johan Hedberg47990ea2012-02-22 11:58:37 +02003544 if (changed)
3545 err = new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003546
3547 if (match.sk)
3548 sock_put(match.sk);
3549
3550 return err;
3551}
3552
Johan Hedbergcacaf522012-02-21 00:52:42 +02003553static int clear_eir(struct hci_dev *hdev)
3554{
3555 struct hci_cp_write_eir cp;
3556
3557 if (!(hdev->features[6] & LMP_EXT_INQ))
3558 return 0;
3559
Johan Hedbergc80da272012-02-22 15:38:48 +02003560 memset(hdev->eir, 0, sizeof(hdev->eir));
3561
Johan Hedbergcacaf522012-02-21 00:52:42 +02003562 memset(&cp, 0, sizeof(cp));
3563
3564 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
3565}
3566
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003567int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003568{
3569 struct cmd_lookup match = { NULL, hdev };
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003570 bool changed = false;
3571 int err = 0;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003572
3573 if (status) {
3574 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003575
3576 if (enable && test_and_clear_bit(HCI_SSP_ENABLED,
3577 &hdev->dev_flags))
3578 err = new_settings(hdev, NULL);
3579
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003580 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev,
3581 cmd_status_rsp, &mgmt_err);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003582
3583 return err;
3584 }
3585
3586 if (enable) {
3587 if (!test_and_set_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3588 changed = true;
3589 } else {
3590 if (test_and_clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3591 changed = true;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003592 }
3593
3594 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
3595
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003596 if (changed)
3597 err = new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003598
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02003599 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003600 sock_put(match.sk);
3601
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02003602 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3603 update_eir(hdev);
3604 else
3605 clear_eir(hdev);
Johan Hedbergcacaf522012-02-21 00:52:42 +02003606
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003607 return err;
3608}
3609
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003610int mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
3611 u8 status)
3612{
3613 int err;
3614
3615 err = mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class, 3, NULL);
3616
3617 return err;
3618}
3619
Johan Hedberg744cf192011-11-08 20:40:14 +02003620int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02003621{
3622 struct pending_cmd *cmd;
3623 struct mgmt_cp_set_local_name ev;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003624 bool changed = false;
3625 int err = 0;
3626
3627 if (memcmp(name, hdev->dev_name, sizeof(hdev->dev_name)) != 0) {
3628 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
3629 changed = true;
3630 }
Johan Hedbergb312b1612011-03-16 14:29:37 +02003631
3632 memset(&ev, 0, sizeof(ev));
3633 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003634 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003635
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003636 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003637 if (!cmd)
3638 goto send_event;
3639
Johan Hedberg7bdaae42012-02-22 21:39:58 +02003640 /* Always assume that either the short or the complete name has
3641 * changed if there was a pending mgmt command */
3642 changed = true;
3643
Johan Hedbergb312b1612011-03-16 14:29:37 +02003644 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02003645 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
Johan Hedbergca69b792011-11-11 18:10:00 +02003646 mgmt_status(status));
Johan Hedbergb312b1612011-03-16 14:29:37 +02003647 goto failed;
3648 }
3649
Johan Hedbergaee9b212012-02-18 15:07:59 +02003650 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0, &ev,
Johan Hedbergb312b1612011-03-16 14:29:37 +02003651 sizeof(ev));
3652 if (err < 0)
3653 goto failed;
3654
3655send_event:
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003656 if (changed)
3657 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev,
3658 sizeof(ev), cmd ? cmd->sk : NULL);
3659
Johan Hedbergf51d5b22012-02-22 18:17:32 +02003660 update_eir(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003661
3662failed:
3663 if (cmd)
3664 mgmt_pending_remove(cmd);
3665 return err;
3666}
Szymon Jancc35938b2011-03-22 13:12:21 +01003667
Johan Hedberg744cf192011-11-08 20:40:14 +02003668int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
3669 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01003670{
3671 struct pending_cmd *cmd;
3672 int err;
3673
Johan Hedberg744cf192011-11-08 20:40:14 +02003674 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01003675
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003676 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003677 if (!cmd)
3678 return -ENOENT;
3679
3680 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02003681 err = cmd_status(cmd->sk, hdev->id,
Johan Hedbergca69b792011-11-11 18:10:00 +02003682 MGMT_OP_READ_LOCAL_OOB_DATA,
3683 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01003684 } else {
3685 struct mgmt_rp_read_local_oob_data rp;
3686
3687 memcpy(rp.hash, hash, sizeof(rp.hash));
3688 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
3689
Johan Hedberg744cf192011-11-08 20:40:14 +02003690 err = cmd_complete(cmd->sk, hdev->id,
3691 MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergaee9b212012-02-18 15:07:59 +02003692 0, &rp, sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01003693 }
3694
3695 mgmt_pending_remove(cmd);
3696
3697 return err;
3698}
Johan Hedberge17acd42011-03-30 23:57:16 +03003699
Johan Hedberg06199cf2012-02-22 16:37:11 +02003700int mgmt_le_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
3701{
3702 struct cmd_lookup match = { NULL, hdev };
3703 bool changed = false;
3704 int err = 0;
3705
3706 if (status) {
3707 u8 mgmt_err = mgmt_status(status);
3708
3709 if (enable && test_and_clear_bit(HCI_LE_ENABLED,
3710 &hdev->dev_flags))
3711 err = new_settings(hdev, NULL);
3712
3713 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev,
3714 cmd_status_rsp, &mgmt_err);
3715
3716 return err;
3717 }
3718
3719 if (enable) {
3720 if (!test_and_set_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3721 changed = true;
3722 } else {
3723 if (test_and_clear_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3724 changed = true;
3725 }
3726
3727 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
3728
3729 if (changed)
3730 err = new_settings(hdev, match.sk);
3731
3732 if (match.sk)
3733 sock_put(match.sk);
3734
3735 return err;
3736}
3737
Johan Hedberg48264f02011-11-09 13:58:58 +02003738int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Johan Hedberg561aafb2012-01-04 13:31:59 +02003739 u8 addr_type, u8 *dev_class, s8 rssi,
Johan Hedberg388fc8f2012-02-23 00:38:59 +02003740 u8 cfm_name, u8 ssp, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03003741{
Johan Hedberge319d2e2012-01-15 19:51:59 +02003742 char buf[512];
3743 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02003744 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03003745
Johan Hedberg1dc06092012-01-15 21:01:23 +02003746 /* Leave 5 bytes for a potential CoD field */
3747 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Andre Guedes7d262f82012-01-10 18:20:49 -03003748 return -EINVAL;
3749
Johan Hedberg1dc06092012-01-15 21:01:23 +02003750 memset(buf, 0, sizeof(buf));
3751
Johan Hedberge319d2e2012-01-15 19:51:59 +02003752 bacpy(&ev->addr.bdaddr, bdaddr);
3753 ev->addr.type = link_to_mgmt(link_type, addr_type);
3754 ev->rssi = rssi;
Johan Hedberg9a395a82012-02-23 00:00:32 +02003755 if (cfm_name)
3756 ev->flags[0] |= MGMT_DEV_FOUND_CONFIRM_NAME;
Johan Hedberg388fc8f2012-02-23 00:38:59 +02003757 if (!ssp)
3758 ev->flags[0] |= MGMT_DEV_FOUND_LEGACY_PAIRING;
Johan Hedberge17acd42011-03-30 23:57:16 +03003759
Johan Hedberg1dc06092012-01-15 21:01:23 +02003760 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02003761 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03003762
Johan Hedberg1dc06092012-01-15 21:01:23 +02003763 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
3764 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
3765 dev_class, 3);
3766
3767 put_unaligned_le16(eir_len, &ev->eir_len);
3768
3769 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03003770
Johan Hedberge319d2e2012-01-15 19:51:59 +02003771 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03003772}
Johan Hedberga88a9652011-03-30 13:18:12 +03003773
Johan Hedbergb644ba32012-01-17 21:48:47 +02003774int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
3775 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03003776{
Johan Hedbergb644ba32012-01-17 21:48:47 +02003777 struct mgmt_ev_device_found *ev;
3778 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
3779 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03003780
Johan Hedbergb644ba32012-01-17 21:48:47 +02003781 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03003782
Johan Hedbergb644ba32012-01-17 21:48:47 +02003783 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03003784
Johan Hedbergb644ba32012-01-17 21:48:47 +02003785 bacpy(&ev->addr.bdaddr, bdaddr);
3786 ev->addr.type = link_to_mgmt(link_type, addr_type);
3787 ev->rssi = rssi;
3788
3789 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
3790 name_len);
3791
3792 put_unaligned_le16(eir_len, &ev->eir_len);
3793
Johan Hedberg053c7e02012-02-04 00:06:00 +02003794 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev,
3795 sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03003796}
Johan Hedberg314b2382011-04-27 10:29:57 -04003797
Andre Guedes7a135102011-11-09 17:14:25 -03003798int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
Johan Hedberg164a6e72011-11-01 17:06:44 +02003799{
3800 struct pending_cmd *cmd;
Johan Hedbergf808e162012-02-19 12:52:07 +02003801 u8 type;
Johan Hedberg164a6e72011-11-01 17:06:44 +02003802 int err;
3803
Andre Guedes203159d2012-02-13 15:41:01 -03003804 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3805
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003806 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003807 if (!cmd)
3808 return -ENOENT;
3809
Johan Hedbergf808e162012-02-19 12:52:07 +02003810 type = hdev->discovery.type;
3811
3812 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
3813 &type, sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02003814 mgmt_pending_remove(cmd);
3815
3816 return err;
3817}
3818
Andre Guedese6d465c2011-11-09 17:14:26 -03003819int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
3820{
3821 struct pending_cmd *cmd;
3822 int err;
3823
3824 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
3825 if (!cmd)
3826 return -ENOENT;
3827
Johan Hedbergd9306502012-02-20 23:25:18 +02003828 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
3829 &hdev->discovery.type,
3830 sizeof(hdev->discovery.type));
Johan Hedberg03811012010-12-08 00:21:06 +02003831 mgmt_pending_remove(cmd);
3832
3833 return err;
3834}
Johan Hedberg314b2382011-04-27 10:29:57 -04003835
Johan Hedberg744cf192011-11-08 20:40:14 +02003836int mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04003837{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02003838 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02003839 struct pending_cmd *cmd;
3840
Andre Guedes343fb142011-11-22 17:14:19 -03003841 BT_DBG("%s discovering %u", hdev->name, discovering);
3842
Johan Hedberg164a6e72011-11-01 17:06:44 +02003843 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003844 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003845 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003846 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003847
3848 if (cmd != NULL) {
Johan Hedbergf808e162012-02-19 12:52:07 +02003849 u8 type = hdev->discovery.type;
3850
Johan Hedbergd9306502012-02-20 23:25:18 +02003851 cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0,
Johan Hedbergf808e162012-02-19 12:52:07 +02003852 &type, sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02003853 mgmt_pending_remove(cmd);
3854 }
3855
Johan Hedbergf963e8e2012-02-20 23:30:44 +02003856 memset(&ev, 0, sizeof(ev));
3857 ev.type = hdev->discovery.type;
3858 ev.discovering = discovering;
3859
3860 return mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04003861}
Antti Julku5e762442011-08-25 16:48:02 +03003862
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003863int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003864{
3865 struct pending_cmd *cmd;
3866 struct mgmt_ev_device_blocked ev;
3867
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003868 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003869
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003870 bacpy(&ev.addr.bdaddr, bdaddr);
3871 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003872
Johan Hedberg744cf192011-11-08 20:40:14 +02003873 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
3874 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003875}
3876
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003877int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003878{
3879 struct pending_cmd *cmd;
3880 struct mgmt_ev_device_unblocked ev;
3881
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003882 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003883
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003884 bacpy(&ev.addr.bdaddr, bdaddr);
3885 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003886
Johan Hedberg744cf192011-11-08 20:40:14 +02003887 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
3888 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003889}
Marcel Holtmannd7b7e792012-02-20 21:47:49 +01003890
3891module_param(enable_hs, bool, 0644);
3892MODULE_PARM_DESC(enable_hs, "Enable High Speed support");
3893
3894module_param(enable_le, bool, 0644);
3895MODULE_PARM_DESC(enable_le, "Enable Low Energy support");