blob: 7c7bc2a213931c38ebfc6e82a176a9ce14b7ce77 [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 Hedberg84bde9d2012-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 Hedberg7770c4a2012-02-22 22:06:38 +0200535 if (!test_bit(HCI_UP, &hdev->flags))
536 return 0;
537
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300538 if (!(hdev->features[6] & LMP_EXT_INQ))
539 return 0;
540
Johan Hedberg84bde9d2012-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 Hedberg7770c4a2012-02-22 22:06:38 +0200576 if (!test_bit(HCI_UP, &hdev->flags))
577 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 }
620
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200621 if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200622 schedule_delayed_work(&hdev->service_cache,
623 msecs_to_jiffies(SERVICE_CACHE_TIMEOUT));
624}
625
Johan Hedberg03811012010-12-08 00:21:06 +0200626static int read_controller_info(struct sock *sk, u16 index)
627{
628 struct mgmt_rp_read_info rp;
629 struct hci_dev *hdev;
630
631 BT_DBG("sock %p hci%u", sk, index);
632
633 hdev = hci_dev_get(index);
634 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200635 return cmd_status(sk, index, MGMT_OP_READ_INFO,
636 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200637
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300638 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200639
Johan Hedberg7d785252011-12-15 00:47:39 +0200640 if (test_and_clear_bit(HCI_PI_MGMT_INIT, &hci_pi(sk)->flags))
641 mgmt_init_hdev(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200642
643 memset(&rp, 0, sizeof(rp));
644
Johan Hedberg03811012010-12-08 00:21:06 +0200645 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200646
647 rp.version = hdev->hci_ver;
648
Johan Hedberg03811012010-12-08 00:21:06 +0200649 put_unaligned_le16(hdev->manufacturer, &rp.manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200650
651 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
652 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
653
654 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedberg03811012010-12-08 00:21:06 +0200655
656 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
Johan Hedberg27fcc362012-02-22 21:46:22 +0200657 memcpy(rp.short_name, hdev->short_name, sizeof(hdev->short_name));
Johan Hedberg03811012010-12-08 00:21:06 +0200658
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300659 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200660 hci_dev_put(hdev);
661
Johan Hedbergaee9b212012-02-18 15:07:59 +0200662 return cmd_complete(sk, index, MGMT_OP_READ_INFO, 0, &rp, sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +0200663}
664
665static void mgmt_pending_free(struct pending_cmd *cmd)
666{
667 sock_put(cmd->sk);
668 kfree(cmd->param);
669 kfree(cmd);
670}
671
672static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
673 struct hci_dev *hdev,
674 void *data, u16 len)
675{
676 struct pending_cmd *cmd;
677
678 cmd = kmalloc(sizeof(*cmd), GFP_ATOMIC);
679 if (!cmd)
680 return NULL;
681
682 cmd->opcode = opcode;
683 cmd->index = hdev->id;
684
685 cmd->param = kmalloc(len, GFP_ATOMIC);
686 if (!cmd->param) {
687 kfree(cmd);
688 return NULL;
689 }
690
691 if (data)
692 memcpy(cmd->param, data, len);
693
694 cmd->sk = sk;
695 sock_hold(sk);
696
697 list_add(&cmd->list, &hdev->mgmt_pending);
698
699 return cmd;
700}
701
702static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
703 void (*cb)(struct pending_cmd *cmd, void *data),
704 void *data)
705{
706 struct list_head *p, *n;
707
708 list_for_each_safe(p, n, &hdev->mgmt_pending) {
709 struct pending_cmd *cmd;
710
711 cmd = list_entry(p, struct pending_cmd, list);
712
713 if (opcode > 0 && cmd->opcode != opcode)
714 continue;
715
716 cb(cmd, data);
717 }
718}
719
720static struct pending_cmd *mgmt_pending_find(u16 opcode, struct hci_dev *hdev)
721{
722 struct pending_cmd *cmd;
723
724 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
725 if (cmd->opcode == opcode)
726 return cmd;
727 }
728
729 return NULL;
730}
731
732static void mgmt_pending_remove(struct pending_cmd *cmd)
733{
734 list_del(&cmd->list);
735 mgmt_pending_free(cmd);
736}
737
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200738static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +0200739{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200740 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +0200741
Johan Hedbergaee9b212012-02-18 15:07:59 +0200742 return cmd_complete(sk, hdev->id, opcode, 0, &settings,
743 sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +0200744}
745
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300746static int set_powered(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200747{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300748 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200749 struct hci_dev *hdev;
750 struct pending_cmd *cmd;
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200751 int err;
Johan Hedberg03811012010-12-08 00:21:06 +0200752
Johan Hedberg03811012010-12-08 00:21:06 +0200753 BT_DBG("request for hci%u", index);
754
755 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200756 return cmd_status(sk, index, MGMT_OP_SET_POWERED,
757 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200758
759 hdev = hci_dev_get(index);
760 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200761 return cmd_status(sk, index, MGMT_OP_SET_POWERED,
762 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200763
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300764 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200765
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100766 if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) {
767 cancel_delayed_work(&hdev->power_off);
768
769 if (cp->val) {
770 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
771 mgmt_powered(hdev, 1);
772 goto failed;
773 }
774 }
775
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200776 if (!!cp->val == hdev_is_powered(hdev)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200777 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200778 goto failed;
779 }
780
781 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200782 err = cmd_status(sk, index, MGMT_OP_SET_POWERED,
783 MGMT_STATUS_BUSY);
Johan Hedberg03811012010-12-08 00:21:06 +0200784 goto failed;
785 }
786
787 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
788 if (!cmd) {
789 err = -ENOMEM;
790 goto failed;
791 }
792
793 if (cp->val)
Gustavo F. Padovan7f971042011-12-18 12:40:32 -0200794 schedule_work(&hdev->power_on);
Johan Hedberg03811012010-12-08 00:21:06 +0200795 else
Gustavo F. Padovan80b7ab32011-12-17 14:52:27 -0200796 schedule_work(&hdev->power_off.work);
Johan Hedberg03811012010-12-08 00:21:06 +0200797
798 err = 0;
799
800failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300801 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200802 hci_dev_put(hdev);
803 return err;
804}
805
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200806static int mgmt_event(u16 event, struct hci_dev *hdev, void *data,
807 u16 data_len, struct sock *skip_sk)
808{
809 struct sk_buff *skb;
810 struct mgmt_hdr *hdr;
811
812 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_ATOMIC);
813 if (!skb)
814 return -ENOMEM;
815
816 hdr = (void *) skb_put(skb, sizeof(*hdr));
817 hdr->opcode = cpu_to_le16(event);
818 if (hdev)
819 hdr->index = cpu_to_le16(hdev->id);
820 else
821 hdr->index = cpu_to_le16(MGMT_INDEX_NONE);
822 hdr->len = cpu_to_le16(data_len);
823
824 if (data)
825 memcpy(skb_put(skb, data_len), data, data_len);
826
Marcel Holtmann97e0bde2012-02-22 13:49:28 +0100827 /* Time stamp */
828 __net_timestamp(skb);
829
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200830 hci_send_to_control(skb, skip_sk);
831 kfree_skb(skb);
832
833 return 0;
834}
835
836static int new_settings(struct hci_dev *hdev, struct sock *skip)
837{
838 __le32 ev;
839
840 ev = cpu_to_le32(get_current_settings(hdev));
841
842 return mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), skip);
843}
844
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300845static int set_discoverable(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200846{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300847 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberge41d8b42010-12-13 21:07:03 +0200848 struct hci_dev *hdev;
Johan Hedberg03811012010-12-08 00:21:06 +0200849 struct pending_cmd *cmd;
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200850 u16 timeout;
Johan Hedberg03811012010-12-08 00:21:06 +0200851 u8 scan;
852 int err;
853
Johan Hedberg03811012010-12-08 00:21:06 +0200854 BT_DBG("request for hci%u", index);
855
856 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200857 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
858 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200859
Marcel Holtmann24c54a92012-02-22 18:06:34 +0100860 timeout = get_unaligned_le16(&cp->timeout);
861 if (!cp->val && timeout > 0)
862 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
863 MGMT_STATUS_INVALID_PARAMS);
864
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200865 hdev = hci_dev_get(index);
866 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200867 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
868 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200869
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300870 hci_dev_lock(hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200871
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200872 if (!hdev_is_powered(hdev) && timeout > 0) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200873 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
874 MGMT_STATUS_NOT_POWERED);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200875 goto failed;
876 }
877
878 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
879 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200880 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
881 MGMT_STATUS_BUSY);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200882 goto failed;
883 }
884
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200885 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) {
886 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
887 MGMT_STATUS_REJECTED);
888 goto failed;
889 }
890
891 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200892 bool changed = false;
893
894 if (!!cp->val != test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
895 change_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
896 changed = true;
897 }
898
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200899 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200900 if (err < 0)
901 goto failed;
902
903 if (changed)
904 err = new_settings(hdev, sk);
905
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200906 goto failed;
907 }
908
909 if (!!cp->val == test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
Marcel Holtmann955638e2012-02-22 18:21:00 +0100910 if (hdev->discov_timeout > 0) {
911 cancel_delayed_work(&hdev->discov_off);
912 hdev->discov_timeout = 0;
913 }
914
915 if (cp->val && timeout > 0) {
916 hdev->discov_timeout = timeout;
917 queue_delayed_work(hdev->workqueue, &hdev->discov_off,
918 msecs_to_jiffies(hdev->discov_timeout * 1000));
919 }
920
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200921 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200922 goto failed;
923 }
924
925 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
926 if (!cmd) {
927 err = -ENOMEM;
928 goto failed;
929 }
930
931 scan = SCAN_PAGE;
932
933 if (cp->val)
934 scan |= SCAN_INQUIRY;
935 else
936 cancel_delayed_work(&hdev->discov_off);
937
938 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
939 if (err < 0)
940 mgmt_pending_remove(cmd);
941
Johan Hedberg03811012010-12-08 00:21:06 +0200942 if (cp->val)
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200943 hdev->discov_timeout = timeout;
Johan Hedberg03811012010-12-08 00:21:06 +0200944
945failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300946 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200947 hci_dev_put(hdev);
948
949 return err;
950}
951
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300952static int set_connectable(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200953{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300954 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200955 struct hci_dev *hdev;
956 struct pending_cmd *cmd;
957 u8 scan;
958 int err;
959
Johan Hedberge41d8b42010-12-13 21:07:03 +0200960 BT_DBG("request for hci%u", index);
961
Johan Hedberg03811012010-12-08 00:21:06 +0200962 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200963 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
964 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200965
966 hdev = hci_dev_get(index);
967 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200968 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
969 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200970
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300971 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200972
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200973 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200974 bool changed = false;
975
976 if (!!cp->val != test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
977 changed = true;
978
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +0200979 if (cp->val) {
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200980 set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +0200981 } else {
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200982 clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
983 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
984 }
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200985
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200986 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200987 if (err < 0)
988 goto failed;
989
990 if (changed)
991 err = new_settings(hdev, sk);
992
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200993 goto failed;
994 }
995
996 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
997 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200998 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
999 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001000 goto failed;
1001 }
1002
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001003 if (!!cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001004 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001005 goto failed;
1006 }
1007
1008 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
1009 if (!cmd) {
1010 err = -ENOMEM;
1011 goto failed;
1012 }
1013
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001014 if (cp->val) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001015 scan = SCAN_PAGE;
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001016 } else {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001017 scan = 0;
1018
Johan Hedbergdf2c6c52012-02-21 19:15:49 +02001019 if (test_bit(HCI_ISCAN, &hdev->flags) &&
1020 hdev->discov_timeout > 0)
1021 cancel_delayed_work(&hdev->discov_off);
1022 }
1023
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001024 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1025 if (err < 0)
1026 mgmt_pending_remove(cmd);
1027
1028failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001029 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001030 hci_dev_put(hdev);
1031
1032 return err;
1033}
1034
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001035static int set_pairable(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001036{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001037 struct mgmt_mode *cp = data;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001038 struct hci_dev *hdev;
1039 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001040
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001041 BT_DBG("request for hci%u", index);
1042
1043 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001044 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE,
1045 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001046
1047 hdev = hci_dev_get(index);
1048 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001049 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE,
1050 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001051
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001052 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001053
1054 if (cp->val)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001055 set_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001056 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001057 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001058
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001059 err = send_settings_rsp(sk, MGMT_OP_SET_PAIRABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001060 if (err < 0)
1061 goto failed;
1062
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001063 err = new_settings(hdev, sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001064
1065failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001066 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001067 hci_dev_put(hdev);
1068
1069 return err;
1070}
Johan Hedberg72a734e2010-12-30 00:38:22 +02001071
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001072static int set_link_security(struct sock *sk, u16 index, void *data, u16 len)
1073{
1074 struct mgmt_mode *cp = data;
1075 struct pending_cmd *cmd;
1076 struct hci_dev *hdev;
1077 uint8_t val;
1078 int err;
1079
1080 BT_DBG("request for hci%u", index);
1081
1082 if (len != sizeof(*cp))
1083 return cmd_status(sk, index, MGMT_OP_SET_LINK_SECURITY,
1084 MGMT_STATUS_INVALID_PARAMS);
1085
1086 hdev = hci_dev_get(index);
1087 if (!hdev)
1088 return cmd_status(sk, index, MGMT_OP_SET_LINK_SECURITY,
1089 MGMT_STATUS_INVALID_PARAMS);
1090
1091 hci_dev_lock(hdev);
1092
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001093 if (!hdev_is_powered(hdev)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001094 bool changed = false;
1095
1096 if (!!cp->val != test_bit(HCI_LINK_SECURITY,
1097 &hdev->dev_flags)) {
1098 change_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
1099 changed = true;
1100 }
1101
1102 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1103 if (err < 0)
1104 goto failed;
1105
1106 if (changed)
1107 err = new_settings(hdev, sk);
1108
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001109 goto failed;
1110 }
1111
1112 if (mgmt_pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
1113 err = cmd_status(sk, index, MGMT_OP_SET_LINK_SECURITY,
1114 MGMT_STATUS_BUSY);
1115 goto failed;
1116 }
1117
1118 val = !!cp->val;
1119
1120 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1121 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1122 goto failed;
1123 }
1124
1125 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1126 if (!cmd) {
1127 err = -ENOMEM;
1128 goto failed;
1129 }
1130
1131 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1132 if (err < 0) {
1133 mgmt_pending_remove(cmd);
1134 goto failed;
1135 }
1136
1137failed:
1138 hci_dev_unlock(hdev);
1139 hci_dev_put(hdev);
1140
1141 return err;
1142}
1143
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001144static int set_ssp(struct sock *sk, u16 index, void *data, u16 len)
1145{
1146 struct mgmt_mode *cp = data;
1147 struct pending_cmd *cmd;
1148 struct hci_dev *hdev;
1149 uint8_t val;
1150 int err;
1151
1152 BT_DBG("request for hci%u", index);
1153
1154 if (len != sizeof(*cp))
1155 return cmd_status(sk, index, MGMT_OP_SET_SSP,
1156 MGMT_STATUS_INVALID_PARAMS);
1157
1158 hdev = hci_dev_get(index);
1159 if (!hdev)
1160 return cmd_status(sk, index, MGMT_OP_SET_SSP,
1161 MGMT_STATUS_INVALID_PARAMS);
1162
1163 hci_dev_lock(hdev);
1164
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001165 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
1166 err = cmd_status(sk, index, MGMT_OP_SET_SSP,
1167 MGMT_STATUS_NOT_SUPPORTED);
1168 goto failed;
1169 }
1170
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001171 val = !!cp->val;
1172
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001173 if (!hdev_is_powered(hdev)) {
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001174 bool changed = false;
1175
1176 if (val != test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) {
1177 change_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
1178 changed = true;
1179 }
1180
1181 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1182 if (err < 0)
1183 goto failed;
1184
1185 if (changed)
1186 err = new_settings(hdev, sk);
1187
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001188 goto failed;
1189 }
1190
1191 if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev)) {
1192 err = cmd_status(sk, index, MGMT_OP_SET_SSP, MGMT_STATUS_BUSY);
1193 goto failed;
1194 }
1195
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001196 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) == val) {
1197 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1198 goto failed;
1199 }
1200
1201 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1202 if (!cmd) {
1203 err = -ENOMEM;
1204 goto failed;
1205 }
1206
1207 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, sizeof(val), &val);
1208 if (err < 0) {
1209 mgmt_pending_remove(cmd);
1210 goto failed;
1211 }
1212
1213failed:
1214 hci_dev_unlock(hdev);
1215 hci_dev_put(hdev);
1216
1217 return err;
1218}
1219
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001220static int set_hs(struct sock *sk, u16 index, void *data, u16 len)
1221{
1222 struct mgmt_mode *cp = data;
1223 struct hci_dev *hdev;
1224 int err;
1225
1226 BT_DBG("request for hci%u", index);
1227
1228 if (len != sizeof(*cp))
1229 return cmd_status(sk, index, MGMT_OP_SET_HS,
1230 MGMT_STATUS_INVALID_PARAMS);
1231
1232 hdev = hci_dev_get(index);
1233 if (!hdev)
1234 return cmd_status(sk, index, MGMT_OP_SET_HS,
1235 MGMT_STATUS_INVALID_PARAMS);
1236
1237 if (!enable_hs) {
1238 err = cmd_status(sk, index, MGMT_OP_SET_HS,
1239 MGMT_STATUS_NOT_SUPPORTED);
1240 goto failed;
1241 }
1242
1243 if (cp->val)
1244 set_bit(HCI_HS_ENABLED, &hdev->dev_flags);
1245 else
1246 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
1247
1248 err = send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
1249
1250failed:
1251 hci_dev_put(hdev);
1252 return err;
1253}
1254
Johan Hedberg06199cf2012-02-22 16:37:11 +02001255static int set_le(struct sock *sk, u16 index, void *data, u16 len)
1256{
1257 struct mgmt_mode *cp = data;
1258 struct hci_cp_write_le_host_supported hci_cp;
1259 struct pending_cmd *cmd;
1260 struct hci_dev *hdev;
1261 int err;
1262 u8 val;
1263
1264 BT_DBG("request for hci%u", index);
1265
1266 if (len != sizeof(*cp))
1267 return cmd_status(sk, index, MGMT_OP_SET_LE,
1268 MGMT_STATUS_INVALID_PARAMS);
1269
1270 hdev = hci_dev_get(index);
1271 if (!hdev)
1272 return cmd_status(sk, index, MGMT_OP_SET_LE,
1273 MGMT_STATUS_INVALID_PARAMS);
1274
1275 if (!enable_le || !(hdev->features[4] & LMP_LE)) {
1276 err = cmd_status(sk, index, MGMT_OP_SET_LE,
1277 MGMT_STATUS_NOT_SUPPORTED);
1278 goto failed;
1279 }
1280
1281 val = !!cp->val;
1282
1283 if (!hdev_is_powered(hdev)) {
1284 bool changed = false;
1285
1286 if (val != test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
1287 change_bit(HCI_LE_ENABLED, &hdev->dev_flags);
1288 changed = true;
1289 }
1290
1291 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1292 if (err < 0)
1293 goto failed;
1294
1295 if (changed)
1296 err = new_settings(hdev, sk);
1297
1298 goto failed;
1299 }
1300
1301 if (mgmt_pending_find(MGMT_OP_SET_LE, hdev)) {
1302 err = cmd_status(sk, index, MGMT_OP_SET_LE, MGMT_STATUS_BUSY);
1303 goto failed;
1304 }
1305
1306 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
1307 if (!cmd) {
1308 err = -ENOMEM;
1309 goto failed;
1310 }
1311
1312 memset(&hci_cp, 0, sizeof(hci_cp));
1313
1314 if (val) {
1315 hci_cp.le = val;
1316 hci_cp.simul = !!(hdev->features[6] & LMP_SIMUL_LE_BR);
1317 }
1318
1319 err = hci_send_cmd(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED,
1320 sizeof(hci_cp), &hci_cp);
1321 if (err < 0) {
1322 mgmt_pending_remove(cmd);
1323 goto failed;
1324 }
1325
1326failed:
1327 hci_dev_put(hdev);
1328 return err;
1329}
1330
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001331static int add_uuid(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001332{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001333 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001334 struct hci_dev *hdev;
1335 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001336 int err;
1337
Szymon Janc4e51eae2011-02-25 19:05:48 +01001338 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001339
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001340 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001341 return cmd_status(sk, index, MGMT_OP_ADD_UUID,
1342 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001343
Szymon Janc4e51eae2011-02-25 19:05:48 +01001344 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001345 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001346 return cmd_status(sk, index, MGMT_OP_ADD_UUID,
1347 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001348
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001349 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001350
1351 uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC);
1352 if (!uuid) {
1353 err = -ENOMEM;
1354 goto failed;
1355 }
1356
1357 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001358 uuid->svc_hint = cp->svc_hint;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001359
1360 list_add(&uuid->list, &hdev->uuids);
1361
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001362 err = update_class(hdev);
1363 if (err < 0)
1364 goto failed;
1365
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001366 err = update_eir(hdev);
1367 if (err < 0)
1368 goto failed;
1369
Johan Hedbergaee9b212012-02-18 15:07:59 +02001370 err = cmd_complete(sk, index, MGMT_OP_ADD_UUID, 0, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001371
1372failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001373 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001374 hci_dev_put(hdev);
1375
1376 return err;
1377}
1378
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001379static int remove_uuid(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001380{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001381 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001382 struct list_head *p, *n;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001383 struct hci_dev *hdev;
1384 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 +02001385 int err, found;
1386
Szymon Janc4e51eae2011-02-25 19:05:48 +01001387 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001388
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001389 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001390 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
1391 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001392
Szymon Janc4e51eae2011-02-25 19:05:48 +01001393 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001394 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001395 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
1396 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001397
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001398 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001399
1400 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
1401 err = hci_uuids_clear(hdev);
1402 goto unlock;
1403 }
1404
1405 found = 0;
1406
1407 list_for_each_safe(p, n, &hdev->uuids) {
1408 struct bt_uuid *match = list_entry(p, struct bt_uuid, list);
1409
1410 if (memcmp(match->uuid, cp->uuid, 16) != 0)
1411 continue;
1412
1413 list_del(&match->list);
1414 found++;
1415 }
1416
1417 if (found == 0) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001418 err = cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
1419 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001420 goto unlock;
1421 }
1422
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001423 err = update_class(hdev);
1424 if (err < 0)
1425 goto unlock;
1426
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001427 err = update_eir(hdev);
1428 if (err < 0)
1429 goto unlock;
1430
Johan Hedbergaee9b212012-02-18 15:07:59 +02001431 err = cmd_complete(sk, index, MGMT_OP_REMOVE_UUID, 0, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001432
1433unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001434 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001435 hci_dev_put(hdev);
1436
1437 return err;
1438}
1439
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001440static int set_dev_class(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001441{
1442 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001443 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001444 int err;
1445
Szymon Janc4e51eae2011-02-25 19:05:48 +01001446 BT_DBG("request for hci%u", index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001447
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001448 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001449 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS,
1450 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001451
Szymon Janc4e51eae2011-02-25 19:05:48 +01001452 hdev = hci_dev_get(index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001453 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001454 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS,
1455 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001456
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001457 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001458
1459 hdev->major_class = cp->major;
1460 hdev->minor_class = cp->minor;
1461
Johan Hedberg932f5ff2012-02-22 22:11:32 +02001462 if (!hdev_is_powered(hdev)) {
1463 err = cmd_complete(sk, index, MGMT_OP_SET_DEV_CLASS, 0,
1464 hdev->dev_class, 3);
1465 goto unlock;
1466 }
1467
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001468 if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02001469 hci_dev_unlock(hdev);
1470 cancel_delayed_work_sync(&hdev->service_cache);
1471 hci_dev_lock(hdev);
Johan Hedberg14c0b602011-12-15 00:47:37 +02001472 update_eir(hdev);
Johan Hedberg7d785252011-12-15 00:47:39 +02001473 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02001474
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001475 err = update_class(hdev);
1476
1477 if (err == 0)
Johan Hedbergaee9b212012-02-18 15:07:59 +02001478 err = cmd_complete(sk, index, MGMT_OP_SET_DEV_CLASS, 0,
Johan Hedberg8ec37032012-02-22 22:02:50 +02001479 hdev->dev_class, 3);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001480
Johan Hedbergb5235a62012-02-21 14:32:24 +02001481unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001482 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001483 hci_dev_put(hdev);
1484
1485 return err;
1486}
1487
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001488static int load_link_keys(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001489{
1490 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001491 struct mgmt_cp_load_link_keys *cp = data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001492 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001493 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001494
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001495 if (len < sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001496 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1497 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001498
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001499 key_count = get_unaligned_le16(&cp->key_count);
1500
Johan Hedberg86742e12011-11-07 23:13:38 +02001501 expected_len = sizeof(*cp) + key_count *
1502 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001503 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001504 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001505 len, expected_len);
Johan Hedbergca69b792011-11-11 18:10:00 +02001506 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1507 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001508 }
1509
Szymon Janc4e51eae2011-02-25 19:05:48 +01001510 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001511 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001512 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1513 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001514
Szymon Janc4e51eae2011-02-25 19:05:48 +01001515 BT_DBG("hci%u debug_keys %u key_count %u", index, cp->debug_keys,
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001516 key_count);
1517
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001518 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001519
1520 hci_link_keys_clear(hdev);
1521
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001522 set_bit(HCI_LINK_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001523
1524 if (cp->debug_keys)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001525 set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001526 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001527 clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001528
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001529 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001530 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001531
Johan Hedbergd753fdc2012-02-17 14:06:34 +02001532 hci_add_link_key(hdev, NULL, 0, &key->addr.bdaddr, key->val,
1533 key->type, key->pin_len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001534 }
1535
Johan Hedbergaee9b212012-02-18 15:07:59 +02001536 cmd_complete(sk, index, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02001537
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001538 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001539 hci_dev_put(hdev);
1540
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001541 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001542}
1543
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001544static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
1545 u8 addr_type, struct sock *skip_sk)
1546{
1547 struct mgmt_ev_device_unpaired ev;
1548
1549 bacpy(&ev.addr.bdaddr, bdaddr);
1550 ev.addr.type = addr_type;
1551
1552 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
1553 skip_sk);
1554}
1555
Johan Hedberg124f6e32012-02-09 13:50:12 +02001556static int unpair_device(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001557{
1558 struct hci_dev *hdev;
Johan Hedberg124f6e32012-02-09 13:50:12 +02001559 struct mgmt_cp_unpair_device *cp = data;
1560 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001561 struct hci_cp_disconnect dc;
1562 struct pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001563 struct hci_conn *conn;
Johan Hedbergaee9b212012-02-18 15:07:59 +02001564 u8 status = 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001565 int err;
1566
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001567 if (len != sizeof(*cp))
Johan Hedberg124f6e32012-02-09 13:50:12 +02001568 return cmd_status(sk, index, MGMT_OP_UNPAIR_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02001569 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001570
Szymon Janc4e51eae2011-02-25 19:05:48 +01001571 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001572 if (!hdev)
Johan Hedberg124f6e32012-02-09 13:50:12 +02001573 return cmd_status(sk, index, MGMT_OP_UNPAIR_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02001574 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001575
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001576 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001577
Johan Hedberga8a1d192011-11-10 15:54:38 +02001578 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02001579 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1580 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001581
Johan Hedberg124f6e32012-02-09 13:50:12 +02001582 if (cp->addr.type == MGMT_ADDR_BREDR)
1583 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
1584 else
1585 err = hci_remove_ltk(hdev, &cp->addr.bdaddr);
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03001586
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001587 if (err < 0) {
Johan Hedbergaee9b212012-02-18 15:07:59 +02001588 status = MGMT_STATUS_NOT_PAIRED;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001589 goto unlock;
1590 }
1591
Johan Hedberga8a1d192011-11-10 15:54:38 +02001592 if (!test_bit(HCI_UP, &hdev->flags) || !cp->disconnect) {
Johan Hedbergaee9b212012-02-18 15:07:59 +02001593 err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE, status,
1594 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001595 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001596 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001597 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001598
Johan Hedberg124f6e32012-02-09 13:50:12 +02001599 if (cp->addr.type == MGMT_ADDR_BREDR)
1600 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
1601 &cp->addr.bdaddr);
1602 else
1603 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
1604 &cp->addr.bdaddr);
1605
Johan Hedberga8a1d192011-11-10 15:54:38 +02001606 if (!conn) {
Johan Hedbergaee9b212012-02-18 15:07:59 +02001607 err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE, status,
1608 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001609 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001610 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001611 }
1612
Johan Hedberg124f6e32012-02-09 13:50:12 +02001613 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
1614 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02001615 if (!cmd) {
1616 err = -ENOMEM;
1617 goto unlock;
1618 }
1619
1620 put_unaligned_le16(conn->handle, &dc.handle);
1621 dc.reason = 0x13; /* Remote User Terminated Connection */
1622 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1623 if (err < 0)
1624 mgmt_pending_remove(cmd);
1625
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001626unlock:
Johan Hedbergca69b792011-11-11 18:10:00 +02001627 if (err < 0)
Johan Hedbergaee9b212012-02-18 15:07:59 +02001628 err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE, status,
1629 &rp, sizeof(rp));
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001630 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001631 hci_dev_put(hdev);
1632
1633 return err;
1634}
1635
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001636static int disconnect(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02001637{
1638 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001639 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001640 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03001641 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001642 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001643 int err;
1644
1645 BT_DBG("");
1646
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001647 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001648 return cmd_status(sk, index, MGMT_OP_DISCONNECT,
1649 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001650
Szymon Janc4e51eae2011-02-25 19:05:48 +01001651 hdev = hci_dev_get(index);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001652 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001653 return cmd_status(sk, index, MGMT_OP_DISCONNECT,
1654 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001655
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001656 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001657
1658 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001659 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1660 MGMT_STATUS_NOT_POWERED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001661 goto failed;
1662 }
1663
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001664 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001665 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1666 MGMT_STATUS_BUSY);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001667 goto failed;
1668 }
1669
Johan Hedberg88c3df12012-02-09 14:27:38 +02001670 if (cp->addr.type == MGMT_ADDR_BREDR)
1671 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
1672 else
1673 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03001674
Johan Hedberg8962ee72011-01-20 12:40:27 +02001675 if (!conn) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001676 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1677 MGMT_STATUS_NOT_CONNECTED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001678 goto failed;
1679 }
1680
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001681 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001682 if (!cmd) {
1683 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001684 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001685 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001686
1687 put_unaligned_le16(conn->handle, &dc.handle);
1688 dc.reason = 0x13; /* Remote User Terminated Connection */
1689
1690 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1691 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001692 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001693
1694failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001695 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001696 hci_dev_put(hdev);
1697
1698 return err;
1699}
1700
Johan Hedberg48264f02011-11-09 13:58:58 +02001701static u8 link_to_mgmt(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02001702{
1703 switch (link_type) {
1704 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02001705 switch (addr_type) {
1706 case ADDR_LE_DEV_PUBLIC:
1707 return MGMT_ADDR_LE_PUBLIC;
1708 case ADDR_LE_DEV_RANDOM:
1709 return MGMT_ADDR_LE_RANDOM;
1710 default:
1711 return MGMT_ADDR_INVALID;
1712 }
Johan Hedberg4c659c32011-11-07 23:13:39 +02001713 case ACL_LINK:
1714 return MGMT_ADDR_BREDR;
1715 default:
1716 return MGMT_ADDR_INVALID;
1717 }
1718}
1719
Szymon Janc8ce62842011-03-01 16:55:32 +01001720static int get_connections(struct sock *sk, u16 index)
Johan Hedberg2784eb42011-01-21 13:56:35 +02001721{
Johan Hedberg2784eb42011-01-21 13:56:35 +02001722 struct mgmt_rp_get_connections *rp;
1723 struct hci_dev *hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001724 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02001725 size_t rp_len;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001726 u16 count;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001727 int i, err;
1728
1729 BT_DBG("");
1730
Szymon Janc4e51eae2011-02-25 19:05:48 +01001731 hdev = hci_dev_get(index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001732 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001733 return cmd_status(sk, index, MGMT_OP_GET_CONNECTIONS,
1734 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001735
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001736 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001737
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001738 if (!hdev_is_powered(hdev)) {
1739 err = cmd_status(sk, index, MGMT_OP_GET_CONNECTIONS,
1740 MGMT_STATUS_NOT_POWERED);
1741 goto unlock;
1742 }
1743
Johan Hedberg2784eb42011-01-21 13:56:35 +02001744 count = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02001745 list_for_each_entry(c, &hdev->conn_hash.list, list) {
1746 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
1747 count++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001748 }
1749
Johan Hedberg4c659c32011-11-07 23:13:39 +02001750 rp_len = sizeof(*rp) + (count * sizeof(struct mgmt_addr_info));
Johan Hedberga38528f2011-01-22 06:46:43 +02001751 rp = kmalloc(rp_len, GFP_ATOMIC);
1752 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02001753 err = -ENOMEM;
1754 goto unlock;
1755 }
1756
Johan Hedberg2784eb42011-01-21 13:56:35 +02001757 put_unaligned_le16(count, &rp->conn_count);
1758
Johan Hedberg2784eb42011-01-21 13:56:35 +02001759 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001760 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02001761 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
1762 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001763 bacpy(&rp->addr[i].bdaddr, &c->dst);
Johan Hedberg48264f02011-11-09 13:58:58 +02001764 rp->addr[i].type = link_to_mgmt(c->type, c->dst_type);
Johan Hedberg4c659c32011-11-07 23:13:39 +02001765 if (rp->addr[i].type == MGMT_ADDR_INVALID)
1766 continue;
1767 i++;
1768 }
1769
1770 /* Recalculate length in case of filtered SCO connections, etc */
1771 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02001772
Johan Hedbergaee9b212012-02-18 15:07:59 +02001773 err = cmd_complete(sk, index, MGMT_OP_GET_CONNECTIONS, 0, rp, rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001774
Johan Hedberga38528f2011-01-22 06:46:43 +02001775 kfree(rp);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001776
1777unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001778 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001779 hci_dev_put(hdev);
1780 return err;
1781}
1782
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001783static int send_pin_code_neg_reply(struct sock *sk, u16 index,
1784 struct hci_dev *hdev, struct mgmt_cp_pin_code_neg_reply *cp)
1785{
1786 struct pending_cmd *cmd;
1787 int err;
1788
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001789 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001790 sizeof(*cp));
1791 if (!cmd)
1792 return -ENOMEM;
1793
Johan Hedbergd8457692012-02-17 14:24:57 +02001794 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
1795 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001796 if (err < 0)
1797 mgmt_pending_remove(cmd);
1798
1799 return err;
1800}
1801
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001802static int pin_code_reply(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001803{
1804 struct hci_dev *hdev;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001805 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001806 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001807 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03001808 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001809 int err;
1810
1811 BT_DBG("");
1812
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001813 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001814 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1815 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001816
Szymon Janc4e51eae2011-02-25 19:05:48 +01001817 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001818 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001819 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1820 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001821
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001822 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001823
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001824 if (!hdev_is_powered(hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001825 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1826 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001827 goto failed;
1828 }
1829
Johan Hedbergd8457692012-02-17 14:24:57 +02001830 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001831 if (!conn) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001832 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1833 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001834 goto failed;
1835 }
1836
1837 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02001838 struct mgmt_cp_pin_code_neg_reply ncp;
1839
1840 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001841
1842 BT_ERR("PIN code is not 16 bytes long");
1843
1844 err = send_pin_code_neg_reply(sk, index, hdev, &ncp);
1845 if (err >= 0)
1846 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001847 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001848
1849 goto failed;
1850 }
1851
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001852 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data,
1853 len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001854 if (!cmd) {
1855 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001856 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001857 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02001858
Johan Hedbergd8457692012-02-17 14:24:57 +02001859 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001860 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02001861 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02001862
1863 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
1864 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001865 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001866
1867failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001868 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001869 hci_dev_put(hdev);
1870
1871 return err;
1872}
1873
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001874static int pin_code_neg_reply(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001875{
1876 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001877 struct mgmt_cp_pin_code_neg_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001878 int err;
1879
1880 BT_DBG("");
1881
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001882 if (len != sizeof(*cp))
1883 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001884 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001885
Szymon Janc4e51eae2011-02-25 19:05:48 +01001886 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001887 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001888 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001889 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001890
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001891 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001892
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001893 if (!hdev_is_powered(hdev)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001894 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001895 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001896 goto failed;
1897 }
1898
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001899 err = send_pin_code_neg_reply(sk, index, hdev, cp);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001900
1901failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001902 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001903 hci_dev_put(hdev);
1904
1905 return err;
1906}
1907
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001908static int set_io_capability(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001909{
1910 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001911 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001912
1913 BT_DBG("");
1914
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001915 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001916 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY,
1917 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001918
Szymon Janc4e51eae2011-02-25 19:05:48 +01001919 hdev = hci_dev_get(index);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001920 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001921 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY,
1922 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001923
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001924 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001925
1926 hdev->io_capability = cp->io_capability;
1927
1928 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Szymon Jancb8534e02011-03-01 16:55:34 +01001929 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001930
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001931 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001932 hci_dev_put(hdev);
1933
Johan Hedbergaee9b212012-02-18 15:07:59 +02001934 return cmd_complete(sk, index, MGMT_OP_SET_IO_CAPABILITY, 0, NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001935}
1936
Johan Hedberge9a416b2011-02-19 12:05:56 -03001937static inline struct pending_cmd *find_pairing(struct hci_conn *conn)
1938{
1939 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001940 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001941
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001942 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03001943 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
1944 continue;
1945
Johan Hedberge9a416b2011-02-19 12:05:56 -03001946 if (cmd->user_data != conn)
1947 continue;
1948
1949 return cmd;
1950 }
1951
1952 return NULL;
1953}
1954
1955static void pairing_complete(struct pending_cmd *cmd, u8 status)
1956{
1957 struct mgmt_rp_pair_device rp;
1958 struct hci_conn *conn = cmd->user_data;
1959
Johan Hedbergba4e5642011-11-11 00:07:34 +02001960 bacpy(&rp.addr.bdaddr, &conn->dst);
1961 rp.addr.type = link_to_mgmt(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001962
Johan Hedbergaee9b212012-02-18 15:07:59 +02001963 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, status,
1964 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001965
1966 /* So we don't get further callbacks for this connection */
1967 conn->connect_cfm_cb = NULL;
1968 conn->security_cfm_cb = NULL;
1969 conn->disconn_cfm_cb = NULL;
1970
1971 hci_conn_put(conn);
1972
Johan Hedberga664b5b2011-02-19 12:06:02 -03001973 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001974}
1975
1976static void pairing_complete_cb(struct hci_conn *conn, u8 status)
1977{
1978 struct pending_cmd *cmd;
1979
1980 BT_DBG("status %u", status);
1981
Johan Hedberg56e5cb82011-11-08 20:40:16 +02001982 cmd = find_pairing(conn);
1983 if (!cmd)
1984 BT_DBG("Unable to find a pending command");
1985 else
Johan Hedberge2113262012-02-18 15:20:03 +02001986 pairing_complete(cmd, mgmt_status(status));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001987}
1988
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001989static int pair_device(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001990{
1991 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001992 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02001993 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001994 struct pending_cmd *cmd;
1995 u8 sec_level, auth_type;
1996 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001997 int err;
1998
1999 BT_DBG("");
2000
Szymon Jancbdce7ba2011-02-25 19:05:49 +01002001 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02002002 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE,
2003 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01002004
Szymon Janc4e51eae2011-02-25 19:05:48 +01002005 hdev = hci_dev_get(index);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002006 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002007 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE,
2008 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002009
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002010 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002011
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002012 if (!hdev_is_powered(hdev)) {
2013 err = cmd_status(sk, index, MGMT_OP_PAIR_DEVICE,
2014 MGMT_STATUS_NOT_POWERED);
2015 goto unlock;
2016 }
2017
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002018 sec_level = BT_SECURITY_MEDIUM;
2019 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002020 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002021 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03002022 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002023
Johan Hedbergba4e5642011-11-11 00:07:34 +02002024 if (cp->addr.type == MGMT_ADDR_BREDR)
2025 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr, sec_level,
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002026 auth_type);
2027 else
Johan Hedbergba4e5642011-11-11 00:07:34 +02002028 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr, sec_level,
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002029 auth_type);
2030
Johan Hedberg1425acb2011-11-11 00:07:35 +02002031 memset(&rp, 0, sizeof(rp));
2032 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2033 rp.addr.type = cp->addr.type;
2034
Ville Tervo30e76272011-02-22 16:10:53 -03002035 if (IS_ERR(conn)) {
Johan Hedberge2113262012-02-18 15:20:03 +02002036 err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE,
2037 MGMT_STATUS_CONNECT_FAILED,
2038 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002039 goto unlock;
2040 }
2041
2042 if (conn->connect_cfm_cb) {
2043 hci_conn_put(conn);
Johan Hedberge2113262012-02-18 15:20:03 +02002044 err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE,
2045 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002046 goto unlock;
2047 }
2048
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002049 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002050 if (!cmd) {
2051 err = -ENOMEM;
2052 hci_conn_put(conn);
2053 goto unlock;
2054 }
2055
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002056 /* For LE, just connecting isn't a proof that the pairing finished */
Johan Hedbergba4e5642011-11-11 00:07:34 +02002057 if (cp->addr.type == MGMT_ADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002058 conn->connect_cfm_cb = pairing_complete_cb;
2059
Johan Hedberge9a416b2011-02-19 12:05:56 -03002060 conn->security_cfm_cb = pairing_complete_cb;
2061 conn->disconn_cfm_cb = pairing_complete_cb;
2062 conn->io_capability = cp->io_cap;
2063 cmd->user_data = conn;
2064
2065 if (conn->state == BT_CONNECTED &&
2066 hci_conn_security(conn, sec_level, auth_type))
2067 pairing_complete(cmd, 0);
2068
2069 err = 0;
2070
2071unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002072 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002073 hci_dev_put(hdev);
2074
2075 return err;
2076}
2077
Johan Hedberg28424702012-02-02 04:02:29 +02002078static int cancel_pair_device(struct sock *sk, u16 index,
2079 unsigned char *data, u16 len)
2080{
2081 struct mgmt_addr_info *addr = (void *) data;
2082 struct hci_dev *hdev;
2083 struct pending_cmd *cmd;
2084 struct hci_conn *conn;
2085 int err;
2086
2087 BT_DBG("");
2088
2089 if (len != sizeof(*addr))
2090 return cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
2091 MGMT_STATUS_INVALID_PARAMS);
2092
2093 hdev = hci_dev_get(index);
2094 if (!hdev)
2095 return cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
2096 MGMT_STATUS_INVALID_PARAMS);
2097
2098 hci_dev_lock(hdev);
2099
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002100 if (!hdev_is_powered(hdev)) {
2101 err = cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
2102 MGMT_STATUS_NOT_POWERED);
2103 goto unlock;
2104 }
2105
Johan Hedberg28424702012-02-02 04:02:29 +02002106 cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
2107 if (!cmd) {
2108 err = cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
2109 MGMT_STATUS_INVALID_PARAMS);
2110 goto unlock;
2111 }
2112
2113 conn = cmd->user_data;
2114
2115 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
2116 err = cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
2117 MGMT_STATUS_INVALID_PARAMS);
2118 goto unlock;
2119 }
2120
2121 pairing_complete(cmd, MGMT_STATUS_CANCELLED);
2122
Johan Hedbergaee9b212012-02-18 15:07:59 +02002123 err = cmd_complete(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE, 0, addr,
Johan Hedberg28424702012-02-02 04:02:29 +02002124 sizeof(*addr));
2125unlock:
2126 hci_dev_unlock(hdev);
2127 hci_dev_put(hdev);
2128
2129 return err;
2130}
2131
Brian Gix0df4c182011-11-16 13:53:13 -08002132static int user_pairing_resp(struct sock *sk, u16 index, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02002133 u8 type, u16 mgmt_op, u16 hci_op,
2134 __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03002135{
Johan Hedberga5c29682011-02-19 12:05:57 -03002136 struct pending_cmd *cmd;
2137 struct hci_dev *hdev;
Brian Gix0df4c182011-11-16 13:53:13 -08002138 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03002139 int err;
2140
Szymon Janc4e51eae2011-02-25 19:05:48 +01002141 hdev = hci_dev_get(index);
Johan Hedberga5c29682011-02-19 12:05:57 -03002142 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002143 return cmd_status(sk, index, mgmt_op,
2144 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga5c29682011-02-19 12:05:57 -03002145
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002146 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02002147
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002148 if (!hdev_is_powered(hdev)) {
Brian Gix0df4c182011-11-16 13:53:13 -08002149 err = cmd_status(sk, index, mgmt_op, MGMT_STATUS_NOT_POWERED);
2150 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002151 }
2152
Johan Hedberg272d90d2012-02-09 15:26:12 +02002153 if (type == MGMT_ADDR_BREDR)
2154 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, bdaddr);
2155 else
Brian Gix47c15e22011-11-16 13:53:14 -08002156 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, bdaddr);
Brian Gix47c15e22011-11-16 13:53:14 -08002157
Johan Hedberg272d90d2012-02-09 15:26:12 +02002158 if (!conn) {
2159 err = cmd_status(sk, index, mgmt_op,
2160 MGMT_STATUS_NOT_CONNECTED);
2161 goto done;
2162 }
2163
2164 if (type == MGMT_ADDR_LE_PUBLIC || type == MGMT_ADDR_LE_RANDOM) {
Brian Gix47c15e22011-11-16 13:53:14 -08002165 /* Continue with pairing via SMP */
Brian Gix5fe57d92011-12-21 16:12:13 -08002166 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix47c15e22011-11-16 13:53:14 -08002167
Brian Gix5fe57d92011-12-21 16:12:13 -08002168 if (!err)
2169 err = cmd_status(sk, index, mgmt_op,
2170 MGMT_STATUS_SUCCESS);
2171 else
2172 err = cmd_status(sk, index, mgmt_op,
2173 MGMT_STATUS_FAILED);
2174
Brian Gix47c15e22011-11-16 13:53:14 -08002175 goto done;
2176 }
2177
Brian Gix0df4c182011-11-16 13:53:13 -08002178 cmd = mgmt_pending_add(sk, mgmt_op, hdev, bdaddr, sizeof(*bdaddr));
Johan Hedberga5c29682011-02-19 12:05:57 -03002179 if (!cmd) {
2180 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08002181 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002182 }
2183
Brian Gix0df4c182011-11-16 13:53:13 -08002184 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08002185 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
2186 struct hci_cp_user_passkey_reply cp;
2187
2188 bacpy(&cp.bdaddr, bdaddr);
2189 cp.passkey = passkey;
2190 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
2191 } else
2192 err = hci_send_cmd(hdev, hci_op, sizeof(*bdaddr), bdaddr);
2193
Johan Hedberga664b5b2011-02-19 12:06:02 -03002194 if (err < 0)
2195 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002196
Brian Gix0df4c182011-11-16 13:53:13 -08002197done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002198 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002199 hci_dev_put(hdev);
2200
2201 return err;
2202}
2203
Brian Gix0df4c182011-11-16 13:53:13 -08002204static int user_confirm_reply(struct sock *sk, u16 index, void *data, u16 len)
2205{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002206 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002207
2208 BT_DBG("");
2209
2210 if (len != sizeof(*cp))
2211 return cmd_status(sk, index, MGMT_OP_USER_CONFIRM_REPLY,
2212 MGMT_STATUS_INVALID_PARAMS);
2213
Johan Hedberg272d90d2012-02-09 15:26:12 +02002214 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
2215 MGMT_OP_USER_CONFIRM_REPLY,
2216 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002217}
2218
2219static int user_confirm_neg_reply(struct sock *sk, u16 index, void *data,
2220 u16 len)
2221{
Johan Hedbergc9c26592011-12-15 00:47:41 +02002222 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002223
2224 BT_DBG("");
2225
2226 if (len != sizeof(*cp))
2227 return cmd_status(sk, index, MGMT_OP_USER_CONFIRM_NEG_REPLY,
2228 MGMT_STATUS_INVALID_PARAMS);
2229
Johan Hedberg272d90d2012-02-09 15:26:12 +02002230 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
2231 MGMT_OP_USER_CONFIRM_NEG_REPLY,
2232 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002233}
2234
Brian Gix604086b2011-11-23 08:28:33 -08002235static int user_passkey_reply(struct sock *sk, u16 index, void *data, u16 len)
2236{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002237 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002238
2239 BT_DBG("");
2240
2241 if (len != sizeof(*cp))
2242 return cmd_status(sk, index, MGMT_OP_USER_PASSKEY_REPLY,
2243 EINVAL);
2244
Johan Hedberg272d90d2012-02-09 15:26:12 +02002245 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
2246 MGMT_OP_USER_PASSKEY_REPLY,
2247 HCI_OP_USER_PASSKEY_REPLY,
2248 cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08002249}
2250
2251static int user_passkey_neg_reply(struct sock *sk, u16 index, void *data,
2252 u16 len)
2253{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002254 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002255
2256 BT_DBG("");
2257
2258 if (len != sizeof(*cp))
2259 return cmd_status(sk, index, MGMT_OP_USER_PASSKEY_NEG_REPLY,
2260 EINVAL);
2261
Johan Hedberg272d90d2012-02-09 15:26:12 +02002262 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
2263 MGMT_OP_USER_PASSKEY_NEG_REPLY,
2264 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08002265}
2266
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002267static int set_local_name(struct sock *sk, u16 index, void *data,
Johan Hedbergb312b1612011-03-16 14:29:37 +02002268 u16 len)
2269{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002270 struct mgmt_cp_set_local_name *mgmt_cp = data;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002271 struct hci_cp_write_local_name hci_cp;
2272 struct hci_dev *hdev;
2273 struct pending_cmd *cmd;
2274 int err;
2275
2276 BT_DBG("");
2277
2278 if (len != sizeof(*mgmt_cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02002279 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME,
2280 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002281
2282 hdev = hci_dev_get(index);
2283 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002284 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME,
2285 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002286
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002287 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002288
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002289 memcpy(hdev->short_name, mgmt_cp->short_name,
2290 sizeof(hdev->short_name));
2291
Johan Hedbergb5235a62012-02-21 14:32:24 +02002292 if (!hdev_is_powered(hdev)) {
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002293 memcpy(hdev->dev_name, mgmt_cp->name, sizeof(hdev->dev_name));
2294
2295 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
2296 data, len);
2297 if (err < 0)
2298 goto failed;
2299
2300 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data, len,
2301 sk);
2302
Johan Hedbergb5235a62012-02-21 14:32:24 +02002303 goto failed;
2304 }
2305
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002306 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002307 if (!cmd) {
2308 err = -ENOMEM;
2309 goto failed;
2310 }
2311
2312 memcpy(hci_cp.name, mgmt_cp->name, sizeof(hci_cp.name));
2313 err = hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(hci_cp),
2314 &hci_cp);
2315 if (err < 0)
2316 mgmt_pending_remove(cmd);
2317
2318failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002319 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002320 hci_dev_put(hdev);
2321
2322 return err;
2323}
2324
Szymon Jancc35938b2011-03-22 13:12:21 +01002325static int read_local_oob_data(struct sock *sk, u16 index)
2326{
2327 struct hci_dev *hdev;
2328 struct pending_cmd *cmd;
2329 int err;
2330
2331 BT_DBG("hci%u", index);
2332
2333 hdev = hci_dev_get(index);
2334 if (!hdev)
2335 return cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002336 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancc35938b2011-03-22 13:12:21 +01002337
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002338 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002339
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002340 if (!hdev_is_powered(hdev)) {
Szymon Jancc35938b2011-03-22 13:12:21 +01002341 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002342 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002343 goto unlock;
2344 }
2345
2346 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
2347 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002348 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002349 goto unlock;
2350 }
2351
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002352 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02002353 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2354 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01002355 goto unlock;
2356 }
2357
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002358 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01002359 if (!cmd) {
2360 err = -ENOMEM;
2361 goto unlock;
2362 }
2363
2364 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
2365 if (err < 0)
2366 mgmt_pending_remove(cmd);
2367
2368unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002369 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002370 hci_dev_put(hdev);
2371
2372 return err;
2373}
2374
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002375static int add_remote_oob_data(struct sock *sk, u16 index, void *data,
2376 u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002377{
2378 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002379 struct mgmt_cp_add_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002380 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002381 int err;
2382
2383 BT_DBG("hci%u ", index);
2384
2385 if (len != sizeof(*cp))
2386 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002387 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01002388
2389 hdev = hci_dev_get(index);
2390 if (!hdev)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002391 return cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
2392 MGMT_STATUS_INVALID_PARAMS,
2393 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002394
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002395 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002396
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002397 if (!hdev_is_powered(hdev)) {
2398 err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
2399 MGMT_STATUS_NOT_POWERED,
2400 &cp->addr, sizeof(cp->addr));
2401 goto unlock;
2402 }
2403
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002404 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, cp->hash,
Szymon Janc2763eda2011-03-22 13:12:22 +01002405 cp->randomizer);
2406 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002407 status = MGMT_STATUS_FAILED;
Szymon Janc2763eda2011-03-22 13:12:22 +01002408 else
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002409 status = 0;
2410
2411 err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, status,
2412 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002413
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002414unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002415 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002416 hci_dev_put(hdev);
2417
2418 return err;
2419}
2420
2421static int remove_remote_oob_data(struct sock *sk, u16 index,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002422 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002423{
2424 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002425 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002426 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002427 int err;
2428
2429 BT_DBG("hci%u ", index);
2430
2431 if (len != sizeof(*cp))
2432 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002433 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01002434
2435 hdev = hci_dev_get(index);
2436 if (!hdev)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002437 return cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2438 MGMT_STATUS_INVALID_PARAMS,
2439 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002440
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002441 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002442
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002443 if (!hdev_is_powered(hdev)) {
2444 err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2445 MGMT_STATUS_NOT_POWERED,
2446 &cp->addr, sizeof(cp->addr));
2447 goto unlock;
2448 }
2449
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002450 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr);
Szymon Janc2763eda2011-03-22 13:12:22 +01002451 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002452 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01002453 else
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002454 status = 0;
2455
2456 err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA, status,
2457 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002458
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002459unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002460 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002461 hci_dev_put(hdev);
2462
2463 return err;
2464}
2465
Andre Guedes5e0452c2012-02-17 20:39:38 -03002466static int discovery(struct hci_dev *hdev)
2467{
2468 int err;
2469
2470 if (lmp_host_le_capable(hdev)) {
2471 if (lmp_bredr_capable(hdev)) {
2472 err = hci_le_scan(hdev, LE_SCAN_TYPE,
2473 LE_SCAN_INT, LE_SCAN_WIN,
2474 LE_SCAN_TIMEOUT_BREDR_LE);
2475 } else {
2476 hdev->discovery.type = DISCOV_TYPE_LE;
2477 err = hci_le_scan(hdev, LE_SCAN_TYPE,
2478 LE_SCAN_INT, LE_SCAN_WIN,
2479 LE_SCAN_TIMEOUT_LE_ONLY);
2480 }
2481 } else {
2482 hdev->discovery.type = DISCOV_TYPE_BREDR;
2483 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
2484 }
2485
2486 return err;
2487}
2488
2489int mgmt_interleaved_discovery(struct hci_dev *hdev)
2490{
2491 int err;
2492
2493 BT_DBG("%s", hdev->name);
2494
2495 hci_dev_lock(hdev);
2496
2497 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR_LE);
2498 if (err < 0)
2499 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2500
2501 hci_dev_unlock(hdev);
2502
2503 return err;
2504}
2505
Johan Hedberg450dfda2011-11-12 11:58:22 +02002506static int start_discovery(struct sock *sk, u16 index,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002507 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002508{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002509 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002510 struct pending_cmd *cmd;
2511 struct hci_dev *hdev;
2512 int err;
2513
2514 BT_DBG("hci%u", index);
2515
Johan Hedberg450dfda2011-11-12 11:58:22 +02002516 if (len != sizeof(*cp))
2517 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2518 MGMT_STATUS_INVALID_PARAMS);
2519
Johan Hedberg14a53662011-04-27 10:29:56 -04002520 hdev = hci_dev_get(index);
2521 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002522 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2523 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg14a53662011-04-27 10:29:56 -04002524
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002525 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002526
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002527 if (!hdev_is_powered(hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02002528 err = cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2529 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02002530 goto failed;
2531 }
2532
Johan Hedbergff9ef572012-01-04 14:23:45 +02002533 if (hdev->discovery.state != DISCOVERY_STOPPED) {
2534 err = cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2535 MGMT_STATUS_BUSY);
2536 goto failed;
2537 }
2538
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002539 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002540 if (!cmd) {
2541 err = -ENOMEM;
2542 goto failed;
2543 }
2544
Andre Guedes4aab14e2012-02-17 20:39:36 -03002545 hdev->discovery.type = cp->type;
2546
2547 switch (hdev->discovery.type) {
Andre Guedesf39799f2012-02-17 20:39:35 -03002548 case DISCOV_TYPE_BREDR:
Andre Guedes3fd24152012-02-03 17:48:01 -03002549 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
Andre Guedesf39799f2012-02-17 20:39:35 -03002550 break;
2551
2552 case DISCOV_TYPE_LE:
Andre Guedes3fd24152012-02-03 17:48:01 -03002553 err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT,
2554 LE_SCAN_WIN, LE_SCAN_TIMEOUT_LE_ONLY);
Andre Guedesf39799f2012-02-17 20:39:35 -03002555 break;
2556
Andre Guedes5e0452c2012-02-17 20:39:38 -03002557 case DISCOV_TYPE_INTERLEAVED:
2558 err = discovery(hdev);
2559 break;
2560
Andre Guedesf39799f2012-02-17 20:39:35 -03002561 default:
Andre Guedes3fd24152012-02-03 17:48:01 -03002562 err = -EINVAL;
Andre Guedesf39799f2012-02-17 20:39:35 -03002563 }
Andre Guedes3fd24152012-02-03 17:48:01 -03002564
Johan Hedberg14a53662011-04-27 10:29:56 -04002565 if (err < 0)
2566 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002567 else
2568 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002569
2570failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002571 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002572 hci_dev_put(hdev);
2573
2574 return err;
2575}
2576
Johan Hedbergd9306502012-02-20 23:25:18 +02002577static int stop_discovery(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002578{
Johan Hedbergd9306502012-02-20 23:25:18 +02002579 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002580 struct hci_dev *hdev;
2581 struct pending_cmd *cmd;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002582 struct hci_cp_remote_name_req_cancel cp;
2583 struct inquiry_entry *e;
Johan Hedberg14a53662011-04-27 10:29:56 -04002584 int err;
2585
2586 BT_DBG("hci%u", index);
2587
Johan Hedbergd9306502012-02-20 23:25:18 +02002588 if (len != sizeof(*mgmt_cp))
2589 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY,
2590 MGMT_STATUS_INVALID_PARAMS);
2591
Johan Hedberg14a53662011-04-27 10:29:56 -04002592 hdev = hci_dev_get(index);
2593 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002594 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY,
2595 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg14a53662011-04-27 10:29:56 -04002596
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002597 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002598
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002599 if (!hci_discovery_active(hdev)) {
Johan Hedbergd9306502012-02-20 23:25:18 +02002600 err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY,
2601 MGMT_STATUS_REJECTED,
2602 &mgmt_cp->type, sizeof(mgmt_cp->type));
2603 goto unlock;
2604 }
2605
2606 if (hdev->discovery.type != mgmt_cp->type) {
2607 err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY,
2608 MGMT_STATUS_INVALID_PARAMS,
2609 &mgmt_cp->type, sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002610 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02002611 }
2612
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002613 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002614 if (!cmd) {
2615 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002616 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04002617 }
2618
Andre Guedes343f9352012-02-17 20:39:37 -03002619 if (hdev->discovery.state == DISCOVERY_FINDING) {
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002620 err = hci_cancel_inquiry(hdev);
2621 if (err < 0)
2622 mgmt_pending_remove(cmd);
2623 else
2624 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
2625 goto unlock;
2626 }
2627
2628 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY, NAME_PENDING);
2629 if (!e) {
2630 mgmt_pending_remove(cmd);
Johan Hedbergaee9b212012-02-18 15:07:59 +02002631 err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY, 0,
Johan Hedbergd9306502012-02-20 23:25:18 +02002632 &mgmt_cp->type, sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002633 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2634 goto unlock;
2635 }
2636
2637 bacpy(&cp.bdaddr, &e->data.bdaddr);
2638 err = hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ_CANCEL,
2639 sizeof(cp), &cp);
Johan Hedberg14a53662011-04-27 10:29:56 -04002640 if (err < 0)
2641 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002642 else
2643 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002644
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002645unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002646 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002647 hci_dev_put(hdev);
2648
2649 return err;
2650}
2651
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002652static int confirm_name(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02002653{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002654 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002655 struct inquiry_entry *e;
2656 struct hci_dev *hdev;
2657 int err;
2658
2659 BT_DBG("hci%u", index);
2660
2661 if (len != sizeof(*cp))
2662 return cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2663 MGMT_STATUS_INVALID_PARAMS);
2664
2665 hdev = hci_dev_get(index);
2666 if (!hdev)
2667 return cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2668 MGMT_STATUS_INVALID_PARAMS);
2669
2670 hci_dev_lock(hdev);
2671
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002672 if (!hci_discovery_active(hdev)) {
2673 err = cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2674 MGMT_STATUS_FAILED);
2675 goto failed;
2676 }
2677
Johan Hedberga198e7b2012-02-17 14:27:06 +02002678 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002679 if (!e) {
Marcel Holtmanne5f0e152012-02-22 11:59:01 +01002680 err = cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
Johan Hedberg561aafb2012-01-04 13:31:59 +02002681 MGMT_STATUS_INVALID_PARAMS);
2682 goto failed;
2683 }
2684
2685 if (cp->name_known) {
2686 e->name_state = NAME_KNOWN;
2687 list_del(&e->list);
2688 } else {
2689 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e20a2012-01-09 00:53:02 +02002690 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002691 }
2692
2693 err = 0;
2694
2695failed:
2696 hci_dev_unlock(hdev);
2697
2698 return err;
2699}
2700
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002701static int block_device(struct sock *sk, u16 index, void *data, u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002702{
2703 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002704 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002705 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03002706 int err;
2707
2708 BT_DBG("hci%u", index);
2709
Antti Julku7fbec222011-06-15 12:01:15 +03002710 if (len != sizeof(*cp))
2711 return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002712 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002713
2714 hdev = hci_dev_get(index);
2715 if (!hdev)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002716 return cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE,
2717 MGMT_STATUS_INVALID_PARAMS,
2718 &cp->addr, sizeof(cp->addr));
Antti Julku7fbec222011-06-15 12:01:15 +03002719
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002720 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002721
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002722 err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002723 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002724 status = MGMT_STATUS_FAILED;
Antti Julku7fbec222011-06-15 12:01:15 +03002725 else
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002726 status = 0;
2727
2728 err = cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE, status,
2729 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03002730
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002731 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002732 hci_dev_put(hdev);
2733
2734 return err;
2735}
2736
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002737static int unblock_device(struct sock *sk, u16 index, void *data, u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002738{
2739 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002740 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002741 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03002742 int err;
2743
2744 BT_DBG("hci%u", index);
2745
Antti Julku7fbec222011-06-15 12:01:15 +03002746 if (len != sizeof(*cp))
2747 return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002748 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002749
2750 hdev = hci_dev_get(index);
2751 if (!hdev)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002752 return cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE,
2753 MGMT_STATUS_INVALID_PARAMS,
2754 &cp->addr, sizeof(cp->addr));
Antti Julku7fbec222011-06-15 12:01:15 +03002755
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002756 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002757
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002758 err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002759 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002760 status = MGMT_STATUS_INVALID_PARAMS;
Antti Julku7fbec222011-06-15 12:01:15 +03002761 else
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002762 status = 0;
2763
2764 err = cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE, status,
2765 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03002766
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002767 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002768 hci_dev_put(hdev);
2769
2770 return err;
2771}
2772
Antti Julkuf6422ec2011-06-22 13:11:56 +03002773static int set_fast_connectable(struct sock *sk, u16 index,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002774 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03002775{
2776 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002777 struct mgmt_mode *cp = data;
Antti Julkuf6422ec2011-06-22 13:11:56 +03002778 struct hci_cp_write_page_scan_activity acp;
2779 u8 type;
2780 int err;
2781
2782 BT_DBG("hci%u", index);
2783
2784 if (len != sizeof(*cp))
2785 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002786 MGMT_STATUS_INVALID_PARAMS);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002787
2788 hdev = hci_dev_get(index);
2789 if (!hdev)
2790 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002791 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg5400c042012-02-21 16:40:33 +02002792 if (!hdev_is_powered(hdev))
2793 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
2794 MGMT_STATUS_NOT_POWERED);
2795
2796 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
2797 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
2798 MGMT_STATUS_REJECTED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002799
2800 hci_dev_lock(hdev);
2801
Johan Hedbergf7c6869ce2011-12-15 00:47:36 +02002802 if (cp->val) {
Antti Julkuf6422ec2011-06-22 13:11:56 +03002803 type = PAGE_SCAN_TYPE_INTERLACED;
2804 acp.interval = 0x0024; /* 22.5 msec page scan interval */
2805 } else {
2806 type = PAGE_SCAN_TYPE_STANDARD; /* default */
2807 acp.interval = 0x0800; /* default 1.28 sec page scan */
2808 }
2809
2810 acp.window = 0x0012; /* default 11.25 msec page scan window */
2811
2812 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
2813 sizeof(acp), &acp);
2814 if (err < 0) {
2815 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002816 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002817 goto done;
2818 }
2819
2820 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
2821 if (err < 0) {
2822 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002823 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002824 goto done;
2825 }
2826
Johan Hedbergaee9b212012-02-18 15:07:59 +02002827 err = cmd_complete(sk, index, MGMT_OP_SET_FAST_CONNECTABLE, 0,
2828 NULL, 0);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002829done:
2830 hci_dev_unlock(hdev);
2831 hci_dev_put(hdev);
2832
2833 return err;
2834}
2835
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002836static int load_long_term_keys(struct sock *sk, u16 index,
2837 void *cp_data, u16 len)
2838{
2839 struct hci_dev *hdev;
2840 struct mgmt_cp_load_long_term_keys *cp = cp_data;
2841 u16 key_count, expected_len;
2842 int i;
2843
2844 if (len < sizeof(*cp))
2845 return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS,
2846 EINVAL);
2847
2848 key_count = get_unaligned_le16(&cp->key_count);
2849
2850 expected_len = sizeof(*cp) + key_count *
2851 sizeof(struct mgmt_ltk_info);
2852 if (expected_len != len) {
2853 BT_ERR("load_keys: expected %u bytes, got %u bytes",
2854 len, expected_len);
2855 return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS,
2856 EINVAL);
2857 }
2858
2859 hdev = hci_dev_get(index);
2860 if (!hdev)
2861 return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS,
2862 ENODEV);
2863
2864 BT_DBG("hci%u key_count %u", index, key_count);
2865
2866 hci_dev_lock(hdev);
2867
2868 hci_smp_ltks_clear(hdev);
2869
2870 for (i = 0; i < key_count; i++) {
2871 struct mgmt_ltk_info *key = &cp->keys[i];
2872 u8 type;
2873
2874 if (key->master)
2875 type = HCI_SMP_LTK;
2876 else
2877 type = HCI_SMP_LTK_SLAVE;
2878
2879 hci_add_ltk(hdev, &key->addr.bdaddr, key->addr.type,
2880 type, 0, key->authenticated, key->val,
2881 key->enc_size, key->ediv, key->rand);
2882 }
2883
2884 hci_dev_unlock(hdev);
2885 hci_dev_put(hdev);
2886
2887 return 0;
2888}
2889
Johan Hedberg03811012010-12-08 00:21:06 +02002890int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
2891{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002892 void *buf;
2893 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02002894 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002895 u16 opcode, index, len;
Johan Hedberg03811012010-12-08 00:21:06 +02002896 int err;
2897
2898 BT_DBG("got %zu bytes", msglen);
2899
2900 if (msglen < sizeof(*hdr))
2901 return -EINVAL;
2902
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03002903 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02002904 if (!buf)
2905 return -ENOMEM;
2906
2907 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
2908 err = -EFAULT;
2909 goto done;
2910 }
2911
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002912 hdr = buf;
Johan Hedberg03811012010-12-08 00:21:06 +02002913 opcode = get_unaligned_le16(&hdr->opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002914 index = get_unaligned_le16(&hdr->index);
Johan Hedberg03811012010-12-08 00:21:06 +02002915 len = get_unaligned_le16(&hdr->len);
2916
2917 if (len != msglen - sizeof(*hdr)) {
2918 err = -EINVAL;
2919 goto done;
2920 }
2921
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002922 cp = buf + sizeof(*hdr);
2923
Johan Hedberg03811012010-12-08 00:21:06 +02002924 switch (opcode) {
Johan Hedberg02d98122010-12-13 21:07:04 +02002925 case MGMT_OP_READ_VERSION:
2926 err = read_version(sk);
2927 break;
Johan Hedberge70bb2e2012-02-13 16:59:33 +02002928 case MGMT_OP_READ_COMMANDS:
2929 err = read_commands(sk);
2930 break;
Johan Hedbergfaba42e2010-12-13 21:07:05 +02002931 case MGMT_OP_READ_INDEX_LIST:
2932 err = read_index_list(sk);
2933 break;
Johan Hedbergf7b64e692010-12-13 21:07:06 +02002934 case MGMT_OP_READ_INFO:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002935 err = read_controller_info(sk, index);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02002936 break;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002937 case MGMT_OP_SET_POWERED:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002938 err = set_powered(sk, index, cp, len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002939 break;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002940 case MGMT_OP_SET_DISCOVERABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002941 err = set_discoverable(sk, index, cp, len);
Johan Hedberg73f22f62010-12-29 16:00:25 +02002942 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002943 case MGMT_OP_SET_CONNECTABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002944 err = set_connectable(sk, index, cp, len);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002945 break;
Johan Hedbergf7c6869ce2011-12-15 00:47:36 +02002946 case MGMT_OP_SET_FAST_CONNECTABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002947 err = set_fast_connectable(sk, index, cp, len);
Johan Hedbergf7c6869ce2011-12-15 00:47:36 +02002948 break;
Johan Hedbergc542a062011-01-26 13:11:03 +02002949 case MGMT_OP_SET_PAIRABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002950 err = set_pairable(sk, index, cp, len);
Johan Hedbergc542a062011-01-26 13:11:03 +02002951 break;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02002952 case MGMT_OP_SET_LINK_SECURITY:
2953 err = set_link_security(sk, index, cp, len);
2954 break;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02002955 case MGMT_OP_SET_SSP:
2956 err = set_ssp(sk, index, cp, len);
2957 break;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02002958 case MGMT_OP_SET_HS:
2959 err = set_hs(sk, index, cp, len);
2960 break;
Johan Hedberg06199cf2012-02-22 16:37:11 +02002961 case MGMT_OP_SET_LE:
2962 err = set_le(sk, index, cp, len);
2963 break;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002964 case MGMT_OP_ADD_UUID:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002965 err = add_uuid(sk, index, cp, len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002966 break;
2967 case MGMT_OP_REMOVE_UUID:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002968 err = remove_uuid(sk, index, cp, len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002969 break;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002970 case MGMT_OP_SET_DEV_CLASS:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002971 err = set_dev_class(sk, index, cp, len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002972 break;
Johan Hedberg86742e12011-11-07 23:13:38 +02002973 case MGMT_OP_LOAD_LINK_KEYS:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002974 err = load_link_keys(sk, index, cp, len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002975 break;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002976 case MGMT_OP_DISCONNECT:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002977 err = disconnect(sk, index, cp, len);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002978 break;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002979 case MGMT_OP_GET_CONNECTIONS:
Szymon Janc8ce62842011-03-01 16:55:32 +01002980 err = get_connections(sk, index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002981 break;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002982 case MGMT_OP_PIN_CODE_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002983 err = pin_code_reply(sk, index, cp, len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002984 break;
2985 case MGMT_OP_PIN_CODE_NEG_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002986 err = pin_code_neg_reply(sk, index, cp, len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002987 break;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002988 case MGMT_OP_SET_IO_CAPABILITY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002989 err = set_io_capability(sk, index, cp, len);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002990 break;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002991 case MGMT_OP_PAIR_DEVICE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002992 err = pair_device(sk, index, cp, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002993 break;
Johan Hedberg28424702012-02-02 04:02:29 +02002994 case MGMT_OP_CANCEL_PAIR_DEVICE:
2995 err = cancel_pair_device(sk, index, buf + sizeof(*hdr), len);
2996 break;
Johan Hedberg124f6e32012-02-09 13:50:12 +02002997 case MGMT_OP_UNPAIR_DEVICE:
2998 err = unpair_device(sk, index, cp, len);
2999 break;
Johan Hedberga5c29682011-02-19 12:05:57 -03003000 case MGMT_OP_USER_CONFIRM_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003001 err = user_confirm_reply(sk, index, cp, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03003002 break;
3003 case MGMT_OP_USER_CONFIRM_NEG_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003004 err = user_confirm_neg_reply(sk, index, cp, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03003005 break;
Brian Gix604086b2011-11-23 08:28:33 -08003006 case MGMT_OP_USER_PASSKEY_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003007 err = user_passkey_reply(sk, index, cp, len);
Brian Gix604086b2011-11-23 08:28:33 -08003008 break;
3009 case MGMT_OP_USER_PASSKEY_NEG_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003010 err = user_passkey_neg_reply(sk, index, cp, len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003011 break;
Johan Hedbergb312b1612011-03-16 14:29:37 +02003012 case MGMT_OP_SET_LOCAL_NAME:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003013 err = set_local_name(sk, index, cp, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003014 break;
Szymon Jancc35938b2011-03-22 13:12:21 +01003015 case MGMT_OP_READ_LOCAL_OOB_DATA:
3016 err = read_local_oob_data(sk, index);
3017 break;
Szymon Janc2763eda2011-03-22 13:12:22 +01003018 case MGMT_OP_ADD_REMOTE_OOB_DATA:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003019 err = add_remote_oob_data(sk, index, cp, len);
Szymon Janc2763eda2011-03-22 13:12:22 +01003020 break;
3021 case MGMT_OP_REMOVE_REMOTE_OOB_DATA:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003022 err = remove_remote_oob_data(sk, index, cp, len);
Szymon Janc2763eda2011-03-22 13:12:22 +01003023 break;
Johan Hedberg14a53662011-04-27 10:29:56 -04003024 case MGMT_OP_START_DISCOVERY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003025 err = start_discovery(sk, index, cp, len);
Johan Hedberg14a53662011-04-27 10:29:56 -04003026 break;
3027 case MGMT_OP_STOP_DISCOVERY:
Johan Hedbergd9306502012-02-20 23:25:18 +02003028 err = stop_discovery(sk, index, cp, len);
Johan Hedberg14a53662011-04-27 10:29:56 -04003029 break;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003030 case MGMT_OP_CONFIRM_NAME:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003031 err = confirm_name(sk, index, cp, len);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003032 break;
Antti Julku7fbec222011-06-15 12:01:15 +03003033 case MGMT_OP_BLOCK_DEVICE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003034 err = block_device(sk, index, cp, len);
Antti Julku7fbec222011-06-15 12:01:15 +03003035 break;
3036 case MGMT_OP_UNBLOCK_DEVICE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003037 err = unblock_device(sk, index, cp, len);
Antti Julku7fbec222011-06-15 12:01:15 +03003038 break;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003039 case MGMT_OP_LOAD_LONG_TERM_KEYS:
3040 err = load_long_term_keys(sk, index, cp, len);
3041 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003042 default:
Johan Hedberg72a734e2010-12-30 00:38:22 +02003043 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02003044 err = cmd_status(sk, index, opcode,
3045 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003046 break;
3047 }
Johan Hedberg72a734e2010-12-30 00:38:22 +02003048
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003049 if (err < 0)
Johan Hedberg72a734e2010-12-30 00:38:22 +02003050 goto done;
3051
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003052 err = msglen;
3053
3054done:
3055 kfree(buf);
3056 return err;
3057}
3058
Johan Hedbergb24752f2011-11-03 14:40:33 +02003059static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
3060{
3061 u8 *status = data;
3062
3063 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
3064 mgmt_pending_remove(cmd);
3065}
3066
Johan Hedberg744cf192011-11-08 20:40:14 +02003067int mgmt_index_added(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +02003068{
Johan Hedberg744cf192011-11-08 20:40:14 +02003069 return mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02003070}
3071
Johan Hedberg744cf192011-11-08 20:40:14 +02003072int mgmt_index_removed(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +02003073{
Johan Hedbergb24752f2011-11-03 14:40:33 +02003074 u8 status = ENODEV;
3075
Johan Hedberg744cf192011-11-08 20:40:14 +02003076 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02003077
Johan Hedberg744cf192011-11-08 20:40:14 +02003078 return mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02003079}
3080
3081struct cmd_lookup {
Johan Hedberg03811012010-12-08 00:21:06 +02003082 struct sock *sk;
Johan Hedberg69ab39e2011-12-15 00:47:35 +02003083 struct hci_dev *hdev;
Johan Hedberg03811012010-12-08 00:21:06 +02003084};
3085
Johan Hedberg69ab39e2011-12-15 00:47:35 +02003086static void settings_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberg03811012010-12-08 00:21:06 +02003087{
Johan Hedberg03811012010-12-08 00:21:06 +02003088 struct cmd_lookup *match = data;
3089
Johan Hedberg69ab39e2011-12-15 00:47:35 +02003090 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02003091
3092 list_del(&cmd->list);
3093
3094 if (match->sk == NULL) {
3095 match->sk = cmd->sk;
3096 sock_hold(match->sk);
3097 }
3098
3099 mgmt_pending_free(cmd);
3100}
3101
Johan Hedberg744cf192011-11-08 20:40:14 +02003102int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg03811012010-12-08 00:21:06 +02003103{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02003104 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003105 int err;
Johan Hedberg03811012010-12-08 00:21:06 +02003106
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003107 if (!test_bit(HCI_MGMT, &hdev->dev_flags))
3108 return 0;
3109
Johan Hedberg69ab39e2011-12-15 00:47:35 +02003110 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
Johan Hedberg03811012010-12-08 00:21:06 +02003111
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003112 if (powered) {
3113 u8 scan = 0;
3114
3115 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3116 scan |= SCAN_PAGE;
3117 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3118 scan |= SCAN_INQUIRY;
3119
3120 if (scan)
3121 hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
3122 } else {
Johan Hedbergb24752f2011-11-03 14:40:33 +02003123 u8 status = ENETDOWN;
Johan Hedberg744cf192011-11-08 20:40:14 +02003124 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02003125 }
3126
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003127 err = new_settings(hdev, match.sk);
Johan Hedberg03811012010-12-08 00:21:06 +02003128
3129 if (match.sk)
3130 sock_put(match.sk);
3131
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003132 return err;
Johan Hedberg03811012010-12-08 00:21:06 +02003133}
3134
Johan Hedberg744cf192011-11-08 20:40:14 +02003135int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg03811012010-12-08 00:21:06 +02003136{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02003137 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003138 bool changed = false;
3139 int err = 0;
Johan Hedberg03811012010-12-08 00:21:06 +02003140
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003141 if (discoverable) {
3142 if (!test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3143 changed = true;
3144 } else {
3145 if (test_and_clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3146 changed = true;
3147 }
Johan Hedberg03811012010-12-08 00:21:06 +02003148
Johan Hedberged9b5f22012-02-21 20:47:06 +02003149 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp,
3150 &match);
3151
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003152 if (changed)
3153 err = new_settings(hdev, match.sk);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003154
Johan Hedberg03811012010-12-08 00:21:06 +02003155 if (match.sk)
3156 sock_put(match.sk);
3157
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003158 return err;
Johan Hedberg03811012010-12-08 00:21:06 +02003159}
3160
Johan Hedberg744cf192011-11-08 20:40:14 +02003161int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg03811012010-12-08 00:21:06 +02003162{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02003163 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003164 bool changed = false;
3165 int err = 0;
Johan Hedberg03811012010-12-08 00:21:06 +02003166
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003167 if (connectable) {
3168 if (!test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3169 changed = true;
3170 } else {
3171 if (test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3172 changed = true;
3173 }
Johan Hedberg03811012010-12-08 00:21:06 +02003174
Johan Hedberged9b5f22012-02-21 20:47:06 +02003175 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev, settings_rsp,
3176 &match);
3177
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003178 if (changed)
3179 err = new_settings(hdev, match.sk);
Johan Hedberg03811012010-12-08 00:21:06 +02003180
3181 if (match.sk)
3182 sock_put(match.sk);
3183
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003184 return err;
Johan Hedberg03811012010-12-08 00:21:06 +02003185}
3186
Johan Hedberg744cf192011-11-08 20:40:14 +02003187int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003188{
Johan Hedbergca69b792011-11-11 18:10:00 +02003189 u8 mgmt_err = mgmt_status(status);
3190
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003191 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02003192 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Johan Hedbergca69b792011-11-11 18:10:00 +02003193 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003194
3195 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02003196 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Johan Hedbergca69b792011-11-11 18:10:00 +02003197 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003198
3199 return 0;
3200}
3201
Johan Hedberg744cf192011-11-08 20:40:14 +02003202int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
3203 u8 persistent)
Johan Hedberg03811012010-12-08 00:21:06 +02003204{
Johan Hedberg86742e12011-11-07 23:13:38 +02003205 struct mgmt_ev_new_link_key ev;
Johan Hedberg03811012010-12-08 00:21:06 +02003206
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003207 memset(&ev, 0, sizeof(ev));
Johan Hedberg03811012010-12-08 00:21:06 +02003208
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003209 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02003210 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
3211 ev.key.addr.type = MGMT_ADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003212 ev.key.type = key->type;
3213 memcpy(ev.key.val, key->val, 16);
3214 ev.key.pin_len = key->pin_len;
Johan Hedberg03811012010-12-08 00:21:06 +02003215
Johan Hedberg744cf192011-11-08 20:40:14 +02003216 return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02003217}
Johan Hedbergf7520542011-01-20 12:34:39 +02003218
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003219int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
3220{
3221 struct mgmt_ev_new_long_term_key ev;
3222
3223 memset(&ev, 0, sizeof(ev));
3224
3225 ev.store_hint = persistent;
3226 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
3227 ev.key.addr.type = key->bdaddr_type;
3228 ev.key.authenticated = key->authenticated;
3229 ev.key.enc_size = key->enc_size;
3230 ev.key.ediv = key->ediv;
3231
3232 if (key->type == HCI_SMP_LTK)
3233 ev.key.master = 1;
3234
3235 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
3236 memcpy(ev.key.val, key->val, sizeof(key->val));
3237
3238 return mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev,
3239 &ev, sizeof(ev), NULL);
3240}
3241
Johan Hedbergafc747a2012-01-15 18:11:07 +02003242int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Johan Hedbergb644ba32012-01-17 21:48:47 +02003243 u8 addr_type, u8 *name, u8 name_len,
3244 u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02003245{
Johan Hedbergb644ba32012-01-17 21:48:47 +02003246 char buf[512];
3247 struct mgmt_ev_device_connected *ev = (void *) buf;
3248 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02003249
Johan Hedbergb644ba32012-01-17 21:48:47 +02003250 bacpy(&ev->addr.bdaddr, bdaddr);
3251 ev->addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02003252
Johan Hedbergb644ba32012-01-17 21:48:47 +02003253 if (name_len > 0)
3254 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
3255 name, name_len);
3256
3257 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
3258 eir_len = eir_append_data(&ev->eir[eir_len], eir_len,
3259 EIR_CLASS_OF_DEV, dev_class, 3);
3260
3261 put_unaligned_le16(eir_len, &ev->eir_len);
3262
3263 return mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
3264 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02003265}
3266
Johan Hedberg8962ee72011-01-20 12:40:27 +02003267static void disconnect_rsp(struct pending_cmd *cmd, void *data)
3268{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01003269 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003270 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02003271 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003272
Johan Hedberg88c3df12012-02-09 14:27:38 +02003273 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3274 rp.addr.type = cp->addr.type;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003275
Johan Hedbergaee9b212012-02-18 15:07:59 +02003276 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, 0, &rp,
3277 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003278
3279 *sk = cmd->sk;
3280 sock_hold(*sk);
3281
Johan Hedberga664b5b2011-02-19 12:06:02 -03003282 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003283}
3284
Johan Hedberg124f6e32012-02-09 13:50:12 +02003285static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02003286{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003287 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02003288 struct mgmt_cp_unpair_device *cp = cmd->param;
3289 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02003290
3291 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02003292 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3293 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02003294
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003295 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
3296
Johan Hedbergaee9b212012-02-18 15:07:59 +02003297 cmd_complete(cmd->sk, cmd->index, cmd->opcode, 0, &rp, sizeof(rp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02003298
3299 mgmt_pending_remove(cmd);
3300}
3301
Johan Hedbergafc747a2012-01-15 18:11:07 +02003302int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
3303 u8 link_type, u8 addr_type)
Johan Hedbergf7520542011-01-20 12:34:39 +02003304{
Johan Hedberg4c659c32011-11-07 23:13:39 +02003305 struct mgmt_addr_info ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003306 struct sock *sk = NULL;
3307 int err;
3308
Johan Hedberg744cf192011-11-08 20:40:14 +02003309 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02003310
Johan Hedbergf7520542011-01-20 12:34:39 +02003311 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02003312 ev.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02003313
Johan Hedbergafc747a2012-01-15 18:11:07 +02003314 err = mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev),
3315 sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003316
3317 if (sk)
3318 sock_put(sk);
3319
Johan Hedberg124f6e32012-02-09 13:50:12 +02003320 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003321 hdev);
Johan Hedberga8a1d192011-11-10 15:54:38 +02003322
Johan Hedberg8962ee72011-01-20 12:40:27 +02003323 return err;
3324}
3325
Johan Hedberg88c3df12012-02-09 14:27:38 +02003326int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
3327 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02003328{
Johan Hedberg88c3df12012-02-09 14:27:38 +02003329 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003330 struct pending_cmd *cmd;
3331 int err;
3332
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003333 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003334 if (!cmd)
3335 return -ENOENT;
3336
Johan Hedberg88c3df12012-02-09 14:27:38 +02003337 bacpy(&rp.addr.bdaddr, bdaddr);
3338 rp.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02003339
Johan Hedberg88c3df12012-02-09 14:27:38 +02003340 err = cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
Johan Hedbergaee9b212012-02-18 15:07:59 +02003341 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003342
Johan Hedberga664b5b2011-02-19 12:06:02 -03003343 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003344
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003345 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
3346 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003347 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02003348}
Johan Hedberg17d5c042011-01-22 06:09:08 +02003349
Johan Hedberg48264f02011-11-09 13:58:58 +02003350int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
3351 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02003352{
3353 struct mgmt_ev_connect_failed ev;
3354
Johan Hedberg4c659c32011-11-07 23:13:39 +02003355 bacpy(&ev.addr.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02003356 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003357 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003358
Johan Hedberg744cf192011-11-08 20:40:14 +02003359 return mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003360}
Johan Hedberg980e1a52011-01-22 06:10:07 +02003361
Johan Hedberg744cf192011-11-08 20:40:14 +02003362int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003363{
3364 struct mgmt_ev_pin_code_request ev;
3365
Johan Hedbergd8457692012-02-17 14:24:57 +02003366 bacpy(&ev.addr.bdaddr, bdaddr);
3367 ev.addr.type = MGMT_ADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02003368 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003369
Johan Hedberg744cf192011-11-08 20:40:14 +02003370 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01003371 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003372}
3373
Johan Hedberg744cf192011-11-08 20:40:14 +02003374int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3375 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003376{
3377 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003378 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003379 int err;
3380
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003381 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003382 if (!cmd)
3383 return -ENOENT;
3384
Johan Hedbergd8457692012-02-17 14:24:57 +02003385 bacpy(&rp.addr.bdaddr, bdaddr);
3386 rp.addr.type = MGMT_ADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003387
Johan Hedbergaee9b212012-02-18 15:07:59 +02003388 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
3389 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003390
Johan Hedberga664b5b2011-02-19 12:06:02 -03003391 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003392
3393 return err;
3394}
3395
Johan Hedberg744cf192011-11-08 20:40:14 +02003396int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3397 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003398{
3399 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003400 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003401 int err;
3402
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003403 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003404 if (!cmd)
3405 return -ENOENT;
3406
Johan Hedbergd8457692012-02-17 14:24:57 +02003407 bacpy(&rp.addr.bdaddr, bdaddr);
3408 rp.addr.type = MGMT_ADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003409
Johan Hedbergaee9b212012-02-18 15:07:59 +02003410 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
3411 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003412
Johan Hedberga664b5b2011-02-19 12:06:02 -03003413 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003414
3415 return err;
3416}
Johan Hedberga5c29682011-02-19 12:05:57 -03003417
Johan Hedberg744cf192011-11-08 20:40:14 +02003418int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003419 u8 link_type, u8 addr_type, __le32 value,
3420 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03003421{
3422 struct mgmt_ev_user_confirm_request ev;
3423
Johan Hedberg744cf192011-11-08 20:40:14 +02003424 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03003425
Johan Hedberg272d90d2012-02-09 15:26:12 +02003426 bacpy(&ev.addr.bdaddr, bdaddr);
3427 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07003428 ev.confirm_hint = confirm_hint;
Johan Hedberga5c29682011-02-19 12:05:57 -03003429 put_unaligned_le32(value, &ev.value);
3430
Johan Hedberg744cf192011-11-08 20:40:14 +02003431 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01003432 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03003433}
3434
Johan Hedberg272d90d2012-02-09 15:26:12 +02003435int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
3436 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08003437{
3438 struct mgmt_ev_user_passkey_request ev;
3439
3440 BT_DBG("%s", hdev->name);
3441
Johan Hedberg272d90d2012-02-09 15:26:12 +02003442 bacpy(&ev.addr.bdaddr, bdaddr);
3443 ev.addr.type = link_to_mgmt(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08003444
3445 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
3446 NULL);
3447}
3448
Brian Gix0df4c182011-11-16 13:53:13 -08003449static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003450 u8 link_type, u8 addr_type, u8 status,
3451 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03003452{
3453 struct pending_cmd *cmd;
3454 struct mgmt_rp_user_confirm_reply rp;
3455 int err;
3456
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003457 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03003458 if (!cmd)
3459 return -ENOENT;
3460
Johan Hedberg272d90d2012-02-09 15:26:12 +02003461 bacpy(&rp.addr.bdaddr, bdaddr);
3462 rp.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergaee9b212012-02-18 15:07:59 +02003463 err = cmd_complete(cmd->sk, hdev->id, opcode, mgmt_status(status),
3464 &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03003465
Johan Hedberga664b5b2011-02-19 12:06:02 -03003466 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03003467
3468 return err;
3469}
3470
Johan Hedberg744cf192011-11-08 20:40:14 +02003471int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003472 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003473{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003474 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3475 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003476}
3477
Johan Hedberg272d90d2012-02-09 15:26:12 +02003478int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3479 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003480{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003481 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3482 status, MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003483}
Johan Hedberg2a611692011-02-19 12:06:00 -03003484
Brian Gix604086b2011-11-23 08:28:33 -08003485int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003486 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003487{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003488 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3489 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003490}
3491
Johan Hedberg272d90d2012-02-09 15:26:12 +02003492int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3493 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003494{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003495 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3496 status, MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003497}
3498
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003499int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
3500 u8 addr_type, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03003501{
3502 struct mgmt_ev_auth_failed ev;
3503
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003504 bacpy(&ev.addr.bdaddr, bdaddr);
3505 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003506 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03003507
Johan Hedberg744cf192011-11-08 20:40:14 +02003508 return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03003509}
Johan Hedbergb312b1612011-03-16 14:29:37 +02003510
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003511int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
3512{
3513 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg47990ea2012-02-22 11:58:37 +02003514 bool changed = false;
3515 int err = 0;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003516
3517 if (status) {
3518 u8 mgmt_err = mgmt_status(status);
3519 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
3520 cmd_status_rsp, &mgmt_err);
3521 return 0;
3522 }
3523
Johan Hedberg47990ea2012-02-22 11:58:37 +02003524 if (test_bit(HCI_AUTH, &hdev->flags)) {
3525 if (!test_and_set_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
3526 changed = true;
3527 } else {
3528 if (test_and_clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
3529 changed = true;
3530 }
3531
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003532 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
3533 &match);
3534
Johan Hedberg47990ea2012-02-22 11:58:37 +02003535 if (changed)
3536 err = new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003537
3538 if (match.sk)
3539 sock_put(match.sk);
3540
3541 return err;
3542}
3543
Johan Hedbergcacaf522012-02-21 00:52:42 +02003544static int clear_eir(struct hci_dev *hdev)
3545{
3546 struct hci_cp_write_eir cp;
3547
3548 if (!(hdev->features[6] & LMP_EXT_INQ))
3549 return 0;
3550
Johan Hedbergc80da272012-02-22 15:38:48 +02003551 memset(hdev->eir, 0, sizeof(hdev->eir));
3552
Johan Hedbergcacaf522012-02-21 00:52:42 +02003553 memset(&cp, 0, sizeof(cp));
3554
3555 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
3556}
3557
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003558int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003559{
3560 struct cmd_lookup match = { NULL, hdev };
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003561 bool changed = false;
3562 int err = 0;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003563
3564 if (status) {
3565 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003566
3567 if (enable && test_and_clear_bit(HCI_SSP_ENABLED,
3568 &hdev->dev_flags))
3569 err = new_settings(hdev, NULL);
3570
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003571 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev,
3572 cmd_status_rsp, &mgmt_err);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003573
3574 return err;
3575 }
3576
3577 if (enable) {
3578 if (!test_and_set_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3579 changed = true;
3580 } else {
3581 if (test_and_clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3582 changed = true;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003583 }
3584
3585 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
3586
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003587 if (changed)
3588 err = new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003589
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02003590 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003591 sock_put(match.sk);
3592
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02003593 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3594 update_eir(hdev);
3595 else
3596 clear_eir(hdev);
Johan Hedbergcacaf522012-02-21 00:52:42 +02003597
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003598 return err;
3599}
3600
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003601int mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
3602 u8 status)
3603{
3604 int err;
3605
3606 err = mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class, 3, NULL);
3607
3608 return err;
3609}
3610
Johan Hedberg744cf192011-11-08 20:40:14 +02003611int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02003612{
3613 struct pending_cmd *cmd;
3614 struct mgmt_cp_set_local_name ev;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003615 bool changed = false;
3616 int err = 0;
3617
3618 if (memcmp(name, hdev->dev_name, sizeof(hdev->dev_name)) != 0) {
3619 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
3620 changed = true;
3621 }
Johan Hedbergb312b1612011-03-16 14:29:37 +02003622
3623 memset(&ev, 0, sizeof(ev));
3624 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003625 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003626
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003627 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003628 if (!cmd)
3629 goto send_event;
3630
Johan Hedberg7bdaae42012-02-22 21:39:58 +02003631 /* Always assume that either the short or the complete name has
3632 * changed if there was a pending mgmt command */
3633 changed = true;
3634
Johan Hedbergb312b1612011-03-16 14:29:37 +02003635 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02003636 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
Johan Hedbergca69b792011-11-11 18:10:00 +02003637 mgmt_status(status));
Johan Hedbergb312b1612011-03-16 14:29:37 +02003638 goto failed;
3639 }
3640
Johan Hedbergaee9b212012-02-18 15:07:59 +02003641 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0, &ev,
Johan Hedbergb312b1612011-03-16 14:29:37 +02003642 sizeof(ev));
3643 if (err < 0)
3644 goto failed;
3645
3646send_event:
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003647 if (changed)
3648 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev,
3649 sizeof(ev), cmd ? cmd->sk : NULL);
3650
Johan Hedbergf51d5b22012-02-22 18:17:32 +02003651 update_eir(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003652
3653failed:
3654 if (cmd)
3655 mgmt_pending_remove(cmd);
3656 return err;
3657}
Szymon Jancc35938b2011-03-22 13:12:21 +01003658
Johan Hedberg744cf192011-11-08 20:40:14 +02003659int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
3660 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01003661{
3662 struct pending_cmd *cmd;
3663 int err;
3664
Johan Hedberg744cf192011-11-08 20:40:14 +02003665 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01003666
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003667 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003668 if (!cmd)
3669 return -ENOENT;
3670
3671 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02003672 err = cmd_status(cmd->sk, hdev->id,
Johan Hedbergca69b792011-11-11 18:10:00 +02003673 MGMT_OP_READ_LOCAL_OOB_DATA,
3674 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01003675 } else {
3676 struct mgmt_rp_read_local_oob_data rp;
3677
3678 memcpy(rp.hash, hash, sizeof(rp.hash));
3679 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
3680
Johan Hedberg744cf192011-11-08 20:40:14 +02003681 err = cmd_complete(cmd->sk, hdev->id,
3682 MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergaee9b212012-02-18 15:07:59 +02003683 0, &rp, sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01003684 }
3685
3686 mgmt_pending_remove(cmd);
3687
3688 return err;
3689}
Johan Hedberge17acd42011-03-30 23:57:16 +03003690
Johan Hedberg06199cf2012-02-22 16:37:11 +02003691int mgmt_le_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
3692{
3693 struct cmd_lookup match = { NULL, hdev };
3694 bool changed = false;
3695 int err = 0;
3696
3697 if (status) {
3698 u8 mgmt_err = mgmt_status(status);
3699
3700 if (enable && test_and_clear_bit(HCI_LE_ENABLED,
3701 &hdev->dev_flags))
3702 err = new_settings(hdev, NULL);
3703
3704 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev,
3705 cmd_status_rsp, &mgmt_err);
3706
3707 return err;
3708 }
3709
3710 if (enable) {
3711 if (!test_and_set_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3712 changed = true;
3713 } else {
3714 if (test_and_clear_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3715 changed = true;
3716 }
3717
3718 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
3719
3720 if (changed)
3721 err = new_settings(hdev, match.sk);
3722
3723 if (match.sk)
3724 sock_put(match.sk);
3725
3726 return err;
3727}
3728
Johan Hedberg48264f02011-11-09 13:58:58 +02003729int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Johan Hedberg561aafb2012-01-04 13:31:59 +02003730 u8 addr_type, u8 *dev_class, s8 rssi,
Johan Hedberge319d2e2012-01-15 19:51:59 +02003731 u8 cfm_name, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03003732{
Johan Hedberge319d2e2012-01-15 19:51:59 +02003733 char buf[512];
3734 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02003735 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03003736
Johan Hedberg1dc06092012-01-15 21:01:23 +02003737 /* Leave 5 bytes for a potential CoD field */
3738 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Andre Guedes7d262f82012-01-10 18:20:49 -03003739 return -EINVAL;
3740
Johan Hedberg1dc06092012-01-15 21:01:23 +02003741 memset(buf, 0, sizeof(buf));
3742
Johan Hedberge319d2e2012-01-15 19:51:59 +02003743 bacpy(&ev->addr.bdaddr, bdaddr);
3744 ev->addr.type = link_to_mgmt(link_type, addr_type);
3745 ev->rssi = rssi;
3746 ev->confirm_name = cfm_name;
Johan Hedberge17acd42011-03-30 23:57:16 +03003747
Johan Hedberg1dc06092012-01-15 21:01:23 +02003748 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02003749 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03003750
Johan Hedberg1dc06092012-01-15 21:01:23 +02003751 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
3752 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
3753 dev_class, 3);
3754
3755 put_unaligned_le16(eir_len, &ev->eir_len);
3756
3757 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03003758
Johan Hedberge319d2e2012-01-15 19:51:59 +02003759 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03003760}
Johan Hedberga88a9652011-03-30 13:18:12 +03003761
Johan Hedbergb644ba32012-01-17 21:48:47 +02003762int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
3763 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03003764{
Johan Hedbergb644ba32012-01-17 21:48:47 +02003765 struct mgmt_ev_device_found *ev;
3766 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
3767 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03003768
Johan Hedbergb644ba32012-01-17 21:48:47 +02003769 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03003770
Johan Hedbergb644ba32012-01-17 21:48:47 +02003771 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03003772
Johan Hedbergb644ba32012-01-17 21:48:47 +02003773 bacpy(&ev->addr.bdaddr, bdaddr);
3774 ev->addr.type = link_to_mgmt(link_type, addr_type);
3775 ev->rssi = rssi;
3776
3777 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
3778 name_len);
3779
3780 put_unaligned_le16(eir_len, &ev->eir_len);
3781
Johan Hedberg053c7e02012-02-04 00:06:00 +02003782 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev,
3783 sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03003784}
Johan Hedberg314b2382011-04-27 10:29:57 -04003785
Andre Guedes7a135102011-11-09 17:14:25 -03003786int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
Johan Hedberg164a6e72011-11-01 17:06:44 +02003787{
3788 struct pending_cmd *cmd;
Johan Hedbergf808e162012-02-19 12:52:07 +02003789 u8 type;
Johan Hedberg164a6e72011-11-01 17:06:44 +02003790 int err;
3791
Andre Guedes203159d2012-02-13 15:41:01 -03003792 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3793
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003794 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003795 if (!cmd)
3796 return -ENOENT;
3797
Johan Hedbergf808e162012-02-19 12:52:07 +02003798 type = hdev->discovery.type;
3799
3800 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
3801 &type, sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02003802 mgmt_pending_remove(cmd);
3803
3804 return err;
3805}
3806
Andre Guedese6d465c2011-11-09 17:14:26 -03003807int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
3808{
3809 struct pending_cmd *cmd;
3810 int err;
3811
3812 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
3813 if (!cmd)
3814 return -ENOENT;
3815
Johan Hedbergd9306502012-02-20 23:25:18 +02003816 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
3817 &hdev->discovery.type,
3818 sizeof(hdev->discovery.type));
Johan Hedberg03811012010-12-08 00:21:06 +02003819 mgmt_pending_remove(cmd);
3820
3821 return err;
3822}
Johan Hedberg314b2382011-04-27 10:29:57 -04003823
Johan Hedberg744cf192011-11-08 20:40:14 +02003824int mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04003825{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02003826 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02003827 struct pending_cmd *cmd;
3828
Andre Guedes343fb142011-11-22 17:14:19 -03003829 BT_DBG("%s discovering %u", hdev->name, discovering);
3830
Johan Hedberg164a6e72011-11-01 17:06:44 +02003831 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003832 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003833 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003834 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003835
3836 if (cmd != NULL) {
Johan Hedbergf808e162012-02-19 12:52:07 +02003837 u8 type = hdev->discovery.type;
3838
Johan Hedbergd9306502012-02-20 23:25:18 +02003839 cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0,
Johan Hedbergf808e162012-02-19 12:52:07 +02003840 &type, sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02003841 mgmt_pending_remove(cmd);
3842 }
3843
Johan Hedbergf963e8e2012-02-20 23:30:44 +02003844 memset(&ev, 0, sizeof(ev));
3845 ev.type = hdev->discovery.type;
3846 ev.discovering = discovering;
3847
3848 return mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04003849}
Antti Julku5e762442011-08-25 16:48:02 +03003850
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003851int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003852{
3853 struct pending_cmd *cmd;
3854 struct mgmt_ev_device_blocked ev;
3855
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003856 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003857
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003858 bacpy(&ev.addr.bdaddr, bdaddr);
3859 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003860
Johan Hedberg744cf192011-11-08 20:40:14 +02003861 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
3862 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003863}
3864
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003865int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003866{
3867 struct pending_cmd *cmd;
3868 struct mgmt_ev_device_unblocked ev;
3869
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003870 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003871
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003872 bacpy(&ev.addr.bdaddr, bdaddr);
3873 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003874
Johan Hedberg744cf192011-11-08 20:40:14 +02003875 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
3876 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003877}
Marcel Holtmannd7b7e792012-02-20 21:47:49 +01003878
3879module_param(enable_hs, bool, 0644);
3880MODULE_PARM_DESC(enable_hs, "Enable High Speed support");
3881
3882module_param(enable_le, bool, 0644);
3883MODULE_PARM_DESC(enable_le, "Enable Low Energy support");