blob: 000abc07bc1e17cb9d36cc2708b216c3fd3afefd [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 Hedbergf7b64e62010-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 Hedbergf7b64e62010-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 Hedbergf7b64e62010-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 Hedbergf7b64e62010-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 Hedbergf7b64e62010-12-13 21:07:06 +0200231 kfree_skb(skb);
232
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300233 return err;
Johan Hedbergf7b64e62010-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 Hedbergf7b64e62010-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 Hedbergf7b64e62010-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 Hedbergf7b64e62010-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 Hedbergf7b64e62010-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 Hedbergf7b64e62010-12-13 21:07:06 +0200418
Johan Hedberg6d80dfd2012-02-20 23:50:38 +0200419 if (test_bit(HCI_HS_ENABLED, &hdev->dev_flags))
420 settings |= MGMT_SETTING_HS;
421
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200422 return settings;
Johan Hedbergc542a062011-01-26 13:11:03 +0200423}
424
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300425#define PNP_INFO_SVCLASS_ID 0x1200
426
427static u8 bluetooth_base_uuid[] = {
428 0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80,
429 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
430};
431
432static u16 get_uuid16(u8 *uuid128)
433{
434 u32 val;
435 int i;
436
437 for (i = 0; i < 12; i++) {
438 if (bluetooth_base_uuid[i] != uuid128[i])
439 return 0;
440 }
441
442 memcpy(&val, &uuid128[12], 4);
443
444 val = le32_to_cpu(val);
445 if (val > 0xffff)
446 return 0;
447
448 return (u16) val;
449}
450
451static void create_eir(struct hci_dev *hdev, u8 *data)
452{
453 u8 *ptr = data;
454 u16 eir_len = 0;
455 u16 uuid16_list[HCI_MAX_EIR_LENGTH / sizeof(u16)];
456 int i, truncated = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200457 struct bt_uuid *uuid;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300458 size_t name_len;
459
460 name_len = strlen(hdev->dev_name);
461
462 if (name_len > 0) {
463 /* EIR Data type */
464 if (name_len > 48) {
465 name_len = 48;
466 ptr[1] = EIR_NAME_SHORT;
467 } else
468 ptr[1] = EIR_NAME_COMPLETE;
469
470 /* EIR Data length */
471 ptr[0] = name_len + 1;
472
473 memcpy(ptr + 2, hdev->dev_name, name_len);
474
475 eir_len += (name_len + 2);
476 ptr += (name_len + 2);
477 }
478
479 memset(uuid16_list, 0, sizeof(uuid16_list));
480
481 /* Group all UUID16 types */
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200482 list_for_each_entry(uuid, &hdev->uuids, list) {
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300483 u16 uuid16;
484
485 uuid16 = get_uuid16(uuid->uuid);
486 if (uuid16 == 0)
487 return;
488
489 if (uuid16 < 0x1100)
490 continue;
491
492 if (uuid16 == PNP_INFO_SVCLASS_ID)
493 continue;
494
495 /* Stop if not enough space to put next UUID */
496 if (eir_len + 2 + sizeof(u16) > HCI_MAX_EIR_LENGTH) {
497 truncated = 1;
498 break;
499 }
500
501 /* Check for duplicates */
502 for (i = 0; uuid16_list[i] != 0; i++)
503 if (uuid16_list[i] == uuid16)
504 break;
505
506 if (uuid16_list[i] == 0) {
507 uuid16_list[i] = uuid16;
508 eir_len += sizeof(u16);
509 }
510 }
511
512 if (uuid16_list[0] != 0) {
513 u8 *length = ptr;
514
515 /* EIR Data type */
516 ptr[1] = truncated ? EIR_UUID16_SOME : EIR_UUID16_ALL;
517
518 ptr += 2;
519 eir_len += 2;
520
521 for (i = 0; uuid16_list[i] != 0; i++) {
522 *ptr++ = (uuid16_list[i] & 0x00ff);
523 *ptr++ = (uuid16_list[i] & 0xff00) >> 8;
524 }
525
526 /* EIR Data length */
527 *length = (i * sizeof(u16)) + 1;
528 }
529}
530
531static int update_eir(struct hci_dev *hdev)
532{
533 struct hci_cp_write_eir cp;
534
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200535 if (!hdev_is_powered(hdev))
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200536 return 0;
537
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300538 if (!(hdev->features[6] & LMP_EXT_INQ))
539 return 0;
540
Johan 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 Hedberg504c8dc2012-02-23 13:30:41 +0200576 if (!hdev_is_powered(hdev))
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200577 return 0;
578
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200579 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200580 return 0;
581
582 cod[0] = hdev->minor_class;
583 cod[1] = hdev->major_class;
584 cod[2] = get_service_classes(hdev);
585
586 if (memcmp(cod, hdev->dev_class, 3) == 0)
587 return 0;
588
589 return hci_send_cmd(hdev, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
590}
591
Johan Hedberg7d785252011-12-15 00:47:39 +0200592static void service_cache_off(struct work_struct *work)
593{
594 struct hci_dev *hdev = container_of(work, struct hci_dev,
595 service_cache.work);
596
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200597 if (!test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200598 return;
599
600 hci_dev_lock(hdev);
601
602 update_eir(hdev);
603 update_class(hdev);
604
605 hci_dev_unlock(hdev);
606}
607
608static void mgmt_init_hdev(struct hci_dev *hdev)
609{
Johan Hedberg0cbf4ed2012-02-21 17:25:22 +0200610 if (!test_and_set_bit(HCI_MGMT, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +0200611 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
612
Johan Hedberg0cbf4ed2012-02-21 17:25:22 +0200613 /* Non-mgmt controlled devices get this bit set
614 * implicitly so that pairing works for them, however
615 * for mgmt we require user-space to explicitly enable
616 * it
617 */
618 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
619 }
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 Hedbergf7b64e62010-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 Hedbergf7b64e62010-12-13 21:07:06 +0200869
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300870 hci_dev_lock(hdev);
Johan Hedbergf7b64e62010-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 Hedbergf7b64e62010-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 Hedbergf7b64e62010-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 Hedbergf7b64e62010-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 Hedberg9997a532012-02-23 15:57:46 +02001370 err = cmd_complete(sk, index, MGMT_OP_ADD_UUID, 0, hdev->dev_class, 3);
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 Hedberg9997a532012-02-23 15:57:46 +02001431 err = cmd_complete(sk, index, MGMT_OP_REMOVE_UUID, 0,
1432 hdev->dev_class, 3);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001433
1434unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001435 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001436 hci_dev_put(hdev);
1437
1438 return err;
1439}
1440
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001441static int set_dev_class(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001442{
1443 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001444 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001445 int err;
1446
Szymon Janc4e51eae2011-02-25 19:05:48 +01001447 BT_DBG("request for hci%u", index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001448
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001449 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001450 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS,
1451 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001452
Szymon Janc4e51eae2011-02-25 19:05:48 +01001453 hdev = hci_dev_get(index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001454 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001455 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS,
1456 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001457
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001458 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001459
1460 hdev->major_class = cp->major;
1461 hdev->minor_class = cp->minor;
1462
Johan Hedberg932f5ff2012-02-22 22:11:32 +02001463 if (!hdev_is_powered(hdev)) {
1464 err = cmd_complete(sk, index, MGMT_OP_SET_DEV_CLASS, 0,
1465 hdev->dev_class, 3);
1466 goto unlock;
1467 }
1468
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001469 if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02001470 hci_dev_unlock(hdev);
1471 cancel_delayed_work_sync(&hdev->service_cache);
1472 hci_dev_lock(hdev);
Johan Hedberg14c0b602011-12-15 00:47:37 +02001473 update_eir(hdev);
Johan Hedberg7d785252011-12-15 00:47:39 +02001474 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02001475
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001476 err = update_class(hdev);
1477
1478 if (err == 0)
Johan Hedbergaee9b212012-02-18 15:07:59 +02001479 err = cmd_complete(sk, index, MGMT_OP_SET_DEV_CLASS, 0,
Johan Hedberg8ec37032012-02-22 22:02:50 +02001480 hdev->dev_class, 3);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001481
Johan Hedbergb5235a62012-02-21 14:32:24 +02001482unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001483 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001484 hci_dev_put(hdev);
1485
1486 return err;
1487}
1488
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001489static int load_link_keys(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001490{
1491 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001492 struct mgmt_cp_load_link_keys *cp = data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001493 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001494 int i;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001495
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001496 if (len < sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001497 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1498 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001499
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001500 key_count = get_unaligned_le16(&cp->key_count);
1501
Johan Hedberg86742e12011-11-07 23:13:38 +02001502 expected_len = sizeof(*cp) + key_count *
1503 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001504 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001505 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001506 len, expected_len);
Johan Hedbergca69b792011-11-11 18:10:00 +02001507 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1508 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001509 }
1510
Szymon Janc4e51eae2011-02-25 19:05:48 +01001511 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001512 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001513 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1514 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001515
Szymon Janc4e51eae2011-02-25 19:05:48 +01001516 BT_DBG("hci%u debug_keys %u key_count %u", index, cp->debug_keys,
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001517 key_count);
1518
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001519 hci_dev_lock(hdev);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001520
1521 hci_link_keys_clear(hdev);
1522
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001523 set_bit(HCI_LINK_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001524
1525 if (cp->debug_keys)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001526 set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001527 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001528 clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001529
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001530 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001531 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001532
Johan Hedbergd753fdc2012-02-17 14:06:34 +02001533 hci_add_link_key(hdev, NULL, 0, &key->addr.bdaddr, key->val,
1534 key->type, key->pin_len);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001535 }
1536
Johan Hedbergaee9b212012-02-18 15:07:59 +02001537 cmd_complete(sk, index, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02001538
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001539 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001540 hci_dev_put(hdev);
1541
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001542 return 0;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001543}
1544
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001545static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
1546 u8 addr_type, struct sock *skip_sk)
1547{
1548 struct mgmt_ev_device_unpaired ev;
1549
1550 bacpy(&ev.addr.bdaddr, bdaddr);
1551 ev.addr.type = addr_type;
1552
1553 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
1554 skip_sk);
1555}
1556
Johan Hedberg124f6e32012-02-09 13:50:12 +02001557static int unpair_device(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001558{
1559 struct hci_dev *hdev;
Johan Hedberg124f6e32012-02-09 13:50:12 +02001560 struct mgmt_cp_unpair_device *cp = data;
1561 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001562 struct hci_cp_disconnect dc;
1563 struct pending_cmd *cmd;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001564 struct hci_conn *conn;
Johan Hedberg55ed8ca2011-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 Hedberg55ed8ca2011-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 Hedberg55ed8ca2011-01-17 14:41:05 +02001575
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001576 hci_dev_lock(hdev);
Johan Hedberg55ed8ca2011-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 Hedberg86a8cfc2012-02-22 22:53:34 +02001582 if (!hdev_is_powered(hdev)) {
1583 err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE,
1584 MGMT_STATUS_NOT_POWERED,
1585 &rp, sizeof(rp));
1586 goto unlock;
1587 }
1588
Johan Hedberg124f6e32012-02-09 13:50:12 +02001589 if (cp->addr.type == MGMT_ADDR_BREDR)
1590 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
1591 else
1592 err = hci_remove_ltk(hdev, &cp->addr.bdaddr);
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03001593
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001594 if (err < 0) {
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001595 err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE,
1596 MGMT_STATUS_NOT_PAIRED,
1597 &rp, sizeof(rp));
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001598 goto unlock;
1599 }
1600
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001601 if (cp->disconnect) {
1602 if (cp->addr.type == MGMT_ADDR_BREDR)
1603 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
1604 &cp->addr.bdaddr);
1605 else
1606 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
1607 &cp->addr.bdaddr);
1608 } else {
1609 conn = NULL;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001610 }
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001611
Johan Hedberga8a1d192011-11-10 15:54:38 +02001612 if (!conn) {
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001613 err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE, 0,
Johan Hedbergaee9b212012-02-18 15:07:59 +02001614 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001615 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001616 goto unlock;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001617 }
1618
Johan Hedberg124f6e32012-02-09 13:50:12 +02001619 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
1620 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02001621 if (!cmd) {
1622 err = -ENOMEM;
1623 goto unlock;
1624 }
1625
1626 put_unaligned_le16(conn->handle, &dc.handle);
1627 dc.reason = 0x13; /* Remote User Terminated Connection */
1628 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1629 if (err < 0)
1630 mgmt_pending_remove(cmd);
1631
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001632unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001633 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001634 hci_dev_put(hdev);
1635
1636 return err;
1637}
1638
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001639static int disconnect(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02001640{
1641 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001642 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001643 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03001644 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001645 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001646 int err;
1647
1648 BT_DBG("");
1649
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001650 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001651 return cmd_status(sk, index, MGMT_OP_DISCONNECT,
1652 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001653
Szymon Janc4e51eae2011-02-25 19:05:48 +01001654 hdev = hci_dev_get(index);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001655 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001656 return cmd_status(sk, index, MGMT_OP_DISCONNECT,
1657 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001658
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001659 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001660
1661 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001662 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1663 MGMT_STATUS_NOT_POWERED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001664 goto failed;
1665 }
1666
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001667 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001668 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1669 MGMT_STATUS_BUSY);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001670 goto failed;
1671 }
1672
Johan Hedberg88c3df12012-02-09 14:27:38 +02001673 if (cp->addr.type == MGMT_ADDR_BREDR)
1674 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
1675 else
1676 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03001677
Johan Hedberg8962ee72011-01-20 12:40:27 +02001678 if (!conn) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001679 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1680 MGMT_STATUS_NOT_CONNECTED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001681 goto failed;
1682 }
1683
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001684 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001685 if (!cmd) {
1686 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001687 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001688 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001689
1690 put_unaligned_le16(conn->handle, &dc.handle);
1691 dc.reason = 0x13; /* Remote User Terminated Connection */
1692
1693 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1694 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001695 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001696
1697failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001698 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001699 hci_dev_put(hdev);
1700
1701 return err;
1702}
1703
Johan Hedberg48264f02011-11-09 13:58:58 +02001704static u8 link_to_mgmt(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02001705{
1706 switch (link_type) {
1707 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02001708 switch (addr_type) {
1709 case ADDR_LE_DEV_PUBLIC:
1710 return MGMT_ADDR_LE_PUBLIC;
1711 case ADDR_LE_DEV_RANDOM:
1712 return MGMT_ADDR_LE_RANDOM;
1713 default:
1714 return MGMT_ADDR_INVALID;
1715 }
Johan Hedberg4c659c32011-11-07 23:13:39 +02001716 case ACL_LINK:
1717 return MGMT_ADDR_BREDR;
1718 default:
1719 return MGMT_ADDR_INVALID;
1720 }
1721}
1722
Szymon Janc8ce62842011-03-01 16:55:32 +01001723static int get_connections(struct sock *sk, u16 index)
Johan Hedberg2784eb42011-01-21 13:56:35 +02001724{
Johan Hedberg2784eb42011-01-21 13:56:35 +02001725 struct mgmt_rp_get_connections *rp;
1726 struct hci_dev *hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001727 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02001728 size_t rp_len;
Johan Hedberg60fc5fb2012-02-23 09:52:28 +02001729 int err;
1730 u16 i;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001731
1732 BT_DBG("");
1733
Szymon Janc4e51eae2011-02-25 19:05:48 +01001734 hdev = hci_dev_get(index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001735 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001736 return cmd_status(sk, index, MGMT_OP_GET_CONNECTIONS,
1737 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001738
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001739 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001740
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001741 if (!hdev_is_powered(hdev)) {
1742 err = cmd_status(sk, index, MGMT_OP_GET_CONNECTIONS,
1743 MGMT_STATUS_NOT_POWERED);
1744 goto unlock;
1745 }
1746
Johan Hedberg60fc5fb2012-02-23 09:52:28 +02001747 i = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02001748 list_for_each_entry(c, &hdev->conn_hash.list, list) {
1749 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
Johan Hedberg60fc5fb2012-02-23 09:52:28 +02001750 i++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001751 }
1752
Johan Hedberg60fc5fb2012-02-23 09:52:28 +02001753 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberga38528f2011-01-22 06:46:43 +02001754 rp = kmalloc(rp_len, GFP_ATOMIC);
1755 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02001756 err = -ENOMEM;
1757 goto unlock;
1758 }
1759
Johan Hedberg2784eb42011-01-21 13:56:35 +02001760 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001761 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02001762 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
1763 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001764 bacpy(&rp->addr[i].bdaddr, &c->dst);
Johan Hedberg48264f02011-11-09 13:58:58 +02001765 rp->addr[i].type = link_to_mgmt(c->type, c->dst_type);
Johan Hedberg4c659c32011-11-07 23:13:39 +02001766 if (rp->addr[i].type == MGMT_ADDR_INVALID)
1767 continue;
1768 i++;
1769 }
1770
Johan Hedberg60fc5fb2012-02-23 09:52:28 +02001771 put_unaligned_le16(i, &rp->conn_count);
1772
Johan Hedberg4c659c32011-11-07 23:13:39 +02001773 /* Recalculate length in case of filtered SCO connections, etc */
1774 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02001775
Johan Hedbergaee9b212012-02-18 15:07:59 +02001776 err = cmd_complete(sk, index, MGMT_OP_GET_CONNECTIONS, 0, rp, rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001777
Johan Hedberga38528f2011-01-22 06:46:43 +02001778 kfree(rp);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001779
1780unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001781 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001782 hci_dev_put(hdev);
1783 return err;
1784}
1785
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001786static int send_pin_code_neg_reply(struct sock *sk, u16 index,
1787 struct hci_dev *hdev, struct mgmt_cp_pin_code_neg_reply *cp)
1788{
1789 struct pending_cmd *cmd;
1790 int err;
1791
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001792 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001793 sizeof(*cp));
1794 if (!cmd)
1795 return -ENOMEM;
1796
Johan Hedbergd8457692012-02-17 14:24:57 +02001797 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
1798 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001799 if (err < 0)
1800 mgmt_pending_remove(cmd);
1801
1802 return err;
1803}
1804
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001805static int pin_code_reply(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001806{
1807 struct hci_dev *hdev;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001808 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001809 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001810 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03001811 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001812 int err;
1813
1814 BT_DBG("");
1815
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001816 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001817 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1818 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001819
Szymon Janc4e51eae2011-02-25 19:05:48 +01001820 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001821 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001822 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1823 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001824
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001825 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001826
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001827 if (!hdev_is_powered(hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001828 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1829 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001830 goto failed;
1831 }
1832
Johan Hedbergd8457692012-02-17 14:24:57 +02001833 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001834 if (!conn) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001835 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1836 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001837 goto failed;
1838 }
1839
1840 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02001841 struct mgmt_cp_pin_code_neg_reply ncp;
1842
1843 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001844
1845 BT_ERR("PIN code is not 16 bytes long");
1846
1847 err = send_pin_code_neg_reply(sk, index, hdev, &ncp);
1848 if (err >= 0)
1849 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001850 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001851
1852 goto failed;
1853 }
1854
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001855 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data,
1856 len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001857 if (!cmd) {
1858 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001859 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001860 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02001861
Johan Hedbergd8457692012-02-17 14:24:57 +02001862 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001863 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02001864 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02001865
1866 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
1867 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001868 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001869
1870failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001871 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001872 hci_dev_put(hdev);
1873
1874 return err;
1875}
1876
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001877static int pin_code_neg_reply(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001878{
1879 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001880 struct mgmt_cp_pin_code_neg_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001881 int err;
1882
1883 BT_DBG("");
1884
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001885 if (len != sizeof(*cp))
1886 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001887 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001888
Szymon Janc4e51eae2011-02-25 19:05:48 +01001889 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001890 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001891 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001892 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001893
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001894 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001895
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001896 if (!hdev_is_powered(hdev)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001897 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001898 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001899 goto failed;
1900 }
1901
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001902 err = send_pin_code_neg_reply(sk, index, hdev, cp);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001903
1904failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001905 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001906 hci_dev_put(hdev);
1907
1908 return err;
1909}
1910
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001911static int set_io_capability(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001912{
1913 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001914 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001915
1916 BT_DBG("");
1917
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001918 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001919 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY,
1920 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001921
Szymon Janc4e51eae2011-02-25 19:05:48 +01001922 hdev = hci_dev_get(index);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001923 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001924 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY,
1925 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001926
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001927 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001928
1929 hdev->io_capability = cp->io_capability;
1930
1931 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Szymon Jancb8534e02011-03-01 16:55:34 +01001932 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001933
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001934 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001935 hci_dev_put(hdev);
1936
Johan Hedbergaee9b212012-02-18 15:07:59 +02001937 return cmd_complete(sk, index, MGMT_OP_SET_IO_CAPABILITY, 0, NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001938}
1939
Johan Hedberge9a416b2011-02-19 12:05:56 -03001940static inline struct pending_cmd *find_pairing(struct hci_conn *conn)
1941{
1942 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001943 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001944
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001945 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03001946 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
1947 continue;
1948
Johan Hedberge9a416b2011-02-19 12:05:56 -03001949 if (cmd->user_data != conn)
1950 continue;
1951
1952 return cmd;
1953 }
1954
1955 return NULL;
1956}
1957
1958static void pairing_complete(struct pending_cmd *cmd, u8 status)
1959{
1960 struct mgmt_rp_pair_device rp;
1961 struct hci_conn *conn = cmd->user_data;
1962
Johan Hedbergba4e5642011-11-11 00:07:34 +02001963 bacpy(&rp.addr.bdaddr, &conn->dst);
1964 rp.addr.type = link_to_mgmt(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001965
Johan Hedbergaee9b212012-02-18 15:07:59 +02001966 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, status,
1967 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001968
1969 /* So we don't get further callbacks for this connection */
1970 conn->connect_cfm_cb = NULL;
1971 conn->security_cfm_cb = NULL;
1972 conn->disconn_cfm_cb = NULL;
1973
1974 hci_conn_put(conn);
1975
Johan Hedberga664b5b2011-02-19 12:06:02 -03001976 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001977}
1978
1979static void pairing_complete_cb(struct hci_conn *conn, u8 status)
1980{
1981 struct pending_cmd *cmd;
1982
1983 BT_DBG("status %u", status);
1984
Johan Hedberg56e5cb82011-11-08 20:40:16 +02001985 cmd = find_pairing(conn);
1986 if (!cmd)
1987 BT_DBG("Unable to find a pending command");
1988 else
Johan Hedberge2113262012-02-18 15:20:03 +02001989 pairing_complete(cmd, mgmt_status(status));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001990}
1991
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001992static int pair_device(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001993{
1994 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001995 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02001996 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001997 struct pending_cmd *cmd;
1998 u8 sec_level, auth_type;
1999 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002000 int err;
2001
2002 BT_DBG("");
2003
Szymon Jancbdce7ba2011-02-25 19:05:49 +01002004 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02002005 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE,
2006 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01002007
Szymon Janc4e51eae2011-02-25 19:05:48 +01002008 hdev = hci_dev_get(index);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002009 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002010 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE,
2011 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002012
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002013 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002014
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002015 if (!hdev_is_powered(hdev)) {
2016 err = cmd_status(sk, index, MGMT_OP_PAIR_DEVICE,
2017 MGMT_STATUS_NOT_POWERED);
2018 goto unlock;
2019 }
2020
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002021 sec_level = BT_SECURITY_MEDIUM;
2022 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002023 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002024 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03002025 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002026
Johan Hedbergba4e5642011-11-11 00:07:34 +02002027 if (cp->addr.type == MGMT_ADDR_BREDR)
2028 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr, sec_level,
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002029 auth_type);
2030 else
Johan Hedbergba4e5642011-11-11 00:07:34 +02002031 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr, sec_level,
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002032 auth_type);
2033
Johan Hedberg1425acb2011-11-11 00:07:35 +02002034 memset(&rp, 0, sizeof(rp));
2035 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2036 rp.addr.type = cp->addr.type;
2037
Ville Tervo30e76272011-02-22 16:10:53 -03002038 if (IS_ERR(conn)) {
Johan Hedberge2113262012-02-18 15:20:03 +02002039 err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE,
2040 MGMT_STATUS_CONNECT_FAILED,
2041 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002042 goto unlock;
2043 }
2044
2045 if (conn->connect_cfm_cb) {
2046 hci_conn_put(conn);
Johan Hedberge2113262012-02-18 15:20:03 +02002047 err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE,
2048 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002049 goto unlock;
2050 }
2051
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002052 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002053 if (!cmd) {
2054 err = -ENOMEM;
2055 hci_conn_put(conn);
2056 goto unlock;
2057 }
2058
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002059 /* For LE, just connecting isn't a proof that the pairing finished */
Johan Hedbergba4e5642011-11-11 00:07:34 +02002060 if (cp->addr.type == MGMT_ADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002061 conn->connect_cfm_cb = pairing_complete_cb;
2062
Johan Hedberge9a416b2011-02-19 12:05:56 -03002063 conn->security_cfm_cb = pairing_complete_cb;
2064 conn->disconn_cfm_cb = pairing_complete_cb;
2065 conn->io_capability = cp->io_cap;
2066 cmd->user_data = conn;
2067
2068 if (conn->state == BT_CONNECTED &&
2069 hci_conn_security(conn, sec_level, auth_type))
2070 pairing_complete(cmd, 0);
2071
2072 err = 0;
2073
2074unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002075 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002076 hci_dev_put(hdev);
2077
2078 return err;
2079}
2080
Johan Hedberg28424702012-02-02 04:02:29 +02002081static int cancel_pair_device(struct sock *sk, u16 index,
2082 unsigned char *data, u16 len)
2083{
2084 struct mgmt_addr_info *addr = (void *) data;
2085 struct hci_dev *hdev;
2086 struct pending_cmd *cmd;
2087 struct hci_conn *conn;
2088 int err;
2089
2090 BT_DBG("");
2091
2092 if (len != sizeof(*addr))
2093 return cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
2094 MGMT_STATUS_INVALID_PARAMS);
2095
2096 hdev = hci_dev_get(index);
2097 if (!hdev)
2098 return cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
2099 MGMT_STATUS_INVALID_PARAMS);
2100
2101 hci_dev_lock(hdev);
2102
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002103 if (!hdev_is_powered(hdev)) {
2104 err = cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
2105 MGMT_STATUS_NOT_POWERED);
2106 goto unlock;
2107 }
2108
Johan Hedberg28424702012-02-02 04:02:29 +02002109 cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
2110 if (!cmd) {
2111 err = cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
2112 MGMT_STATUS_INVALID_PARAMS);
2113 goto unlock;
2114 }
2115
2116 conn = cmd->user_data;
2117
2118 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
2119 err = cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
2120 MGMT_STATUS_INVALID_PARAMS);
2121 goto unlock;
2122 }
2123
2124 pairing_complete(cmd, MGMT_STATUS_CANCELLED);
2125
Johan Hedbergaee9b212012-02-18 15:07:59 +02002126 err = cmd_complete(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE, 0, addr,
Johan Hedberg28424702012-02-02 04:02:29 +02002127 sizeof(*addr));
2128unlock:
2129 hci_dev_unlock(hdev);
2130 hci_dev_put(hdev);
2131
2132 return err;
2133}
2134
Brian Gix0df4c182011-11-16 13:53:13 -08002135static int user_pairing_resp(struct sock *sk, u16 index, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02002136 u8 type, u16 mgmt_op, u16 hci_op,
2137 __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03002138{
Johan Hedberga5c29682011-02-19 12:05:57 -03002139 struct pending_cmd *cmd;
2140 struct hci_dev *hdev;
Brian Gix0df4c182011-11-16 13:53:13 -08002141 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03002142 int err;
2143
Szymon Janc4e51eae2011-02-25 19:05:48 +01002144 hdev = hci_dev_get(index);
Johan Hedberga5c29682011-02-19 12:05:57 -03002145 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002146 return cmd_status(sk, index, mgmt_op,
2147 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga5c29682011-02-19 12:05:57 -03002148
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002149 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02002150
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002151 if (!hdev_is_powered(hdev)) {
Brian Gix0df4c182011-11-16 13:53:13 -08002152 err = cmd_status(sk, index, mgmt_op, MGMT_STATUS_NOT_POWERED);
2153 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002154 }
2155
Johan Hedberg272d90d2012-02-09 15:26:12 +02002156 if (type == MGMT_ADDR_BREDR)
2157 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, bdaddr);
2158 else
Brian Gix47c15e22011-11-16 13:53:14 -08002159 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, bdaddr);
Brian Gix47c15e22011-11-16 13:53:14 -08002160
Johan Hedberg272d90d2012-02-09 15:26:12 +02002161 if (!conn) {
2162 err = cmd_status(sk, index, mgmt_op,
2163 MGMT_STATUS_NOT_CONNECTED);
2164 goto done;
2165 }
2166
2167 if (type == MGMT_ADDR_LE_PUBLIC || type == MGMT_ADDR_LE_RANDOM) {
Brian Gix47c15e22011-11-16 13:53:14 -08002168 /* Continue with pairing via SMP */
Brian Gix5fe57d92011-12-21 16:12:13 -08002169 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix47c15e22011-11-16 13:53:14 -08002170
Brian Gix5fe57d92011-12-21 16:12:13 -08002171 if (!err)
2172 err = cmd_status(sk, index, mgmt_op,
2173 MGMT_STATUS_SUCCESS);
2174 else
2175 err = cmd_status(sk, index, mgmt_op,
2176 MGMT_STATUS_FAILED);
2177
Brian Gix47c15e22011-11-16 13:53:14 -08002178 goto done;
2179 }
2180
Brian Gix0df4c182011-11-16 13:53:13 -08002181 cmd = mgmt_pending_add(sk, mgmt_op, hdev, bdaddr, sizeof(*bdaddr));
Johan Hedberga5c29682011-02-19 12:05:57 -03002182 if (!cmd) {
2183 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08002184 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002185 }
2186
Brian Gix0df4c182011-11-16 13:53:13 -08002187 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08002188 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
2189 struct hci_cp_user_passkey_reply cp;
2190
2191 bacpy(&cp.bdaddr, bdaddr);
2192 cp.passkey = passkey;
2193 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
2194 } else
2195 err = hci_send_cmd(hdev, hci_op, sizeof(*bdaddr), bdaddr);
2196
Johan Hedberga664b5b2011-02-19 12:06:02 -03002197 if (err < 0)
2198 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002199
Brian Gix0df4c182011-11-16 13:53:13 -08002200done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002201 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002202 hci_dev_put(hdev);
2203
2204 return err;
2205}
2206
Brian Gix0df4c182011-11-16 13:53:13 -08002207static int user_confirm_reply(struct sock *sk, u16 index, void *data, u16 len)
2208{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002209 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002210
2211 BT_DBG("");
2212
2213 if (len != sizeof(*cp))
2214 return cmd_status(sk, index, MGMT_OP_USER_CONFIRM_REPLY,
2215 MGMT_STATUS_INVALID_PARAMS);
2216
Johan Hedberg272d90d2012-02-09 15:26:12 +02002217 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
2218 MGMT_OP_USER_CONFIRM_REPLY,
2219 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002220}
2221
2222static int user_confirm_neg_reply(struct sock *sk, u16 index, void *data,
2223 u16 len)
2224{
Johan Hedbergc9c26592011-12-15 00:47:41 +02002225 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002226
2227 BT_DBG("");
2228
2229 if (len != sizeof(*cp))
2230 return cmd_status(sk, index, MGMT_OP_USER_CONFIRM_NEG_REPLY,
2231 MGMT_STATUS_INVALID_PARAMS);
2232
Johan Hedberg272d90d2012-02-09 15:26:12 +02002233 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
2234 MGMT_OP_USER_CONFIRM_NEG_REPLY,
2235 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002236}
2237
Brian Gix604086b2011-11-23 08:28:33 -08002238static int user_passkey_reply(struct sock *sk, u16 index, void *data, u16 len)
2239{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002240 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002241
2242 BT_DBG("");
2243
2244 if (len != sizeof(*cp))
2245 return cmd_status(sk, index, MGMT_OP_USER_PASSKEY_REPLY,
2246 EINVAL);
2247
Johan Hedberg272d90d2012-02-09 15:26:12 +02002248 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
2249 MGMT_OP_USER_PASSKEY_REPLY,
2250 HCI_OP_USER_PASSKEY_REPLY,
2251 cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08002252}
2253
2254static int user_passkey_neg_reply(struct sock *sk, u16 index, void *data,
2255 u16 len)
2256{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002257 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002258
2259 BT_DBG("");
2260
2261 if (len != sizeof(*cp))
2262 return cmd_status(sk, index, MGMT_OP_USER_PASSKEY_NEG_REPLY,
2263 EINVAL);
2264
Johan Hedberg272d90d2012-02-09 15:26:12 +02002265 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
2266 MGMT_OP_USER_PASSKEY_NEG_REPLY,
2267 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08002268}
2269
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002270static int set_local_name(struct sock *sk, u16 index, void *data,
Johan Hedbergb312b1612011-03-16 14:29:37 +02002271 u16 len)
2272{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002273 struct mgmt_cp_set_local_name *mgmt_cp = data;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002274 struct hci_cp_write_local_name hci_cp;
2275 struct hci_dev *hdev;
2276 struct pending_cmd *cmd;
2277 int err;
2278
2279 BT_DBG("");
2280
2281 if (len != sizeof(*mgmt_cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02002282 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME,
2283 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002284
2285 hdev = hci_dev_get(index);
2286 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002287 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME,
2288 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002289
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002290 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002291
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002292 memcpy(hdev->short_name, mgmt_cp->short_name,
2293 sizeof(hdev->short_name));
2294
Johan Hedbergb5235a62012-02-21 14:32:24 +02002295 if (!hdev_is_powered(hdev)) {
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002296 memcpy(hdev->dev_name, mgmt_cp->name, sizeof(hdev->dev_name));
2297
2298 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
2299 data, len);
2300 if (err < 0)
2301 goto failed;
2302
2303 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data, len,
2304 sk);
2305
Johan Hedbergb5235a62012-02-21 14:32:24 +02002306 goto failed;
2307 }
2308
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002309 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002310 if (!cmd) {
2311 err = -ENOMEM;
2312 goto failed;
2313 }
2314
2315 memcpy(hci_cp.name, mgmt_cp->name, sizeof(hci_cp.name));
2316 err = hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(hci_cp),
2317 &hci_cp);
2318 if (err < 0)
2319 mgmt_pending_remove(cmd);
2320
2321failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002322 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002323 hci_dev_put(hdev);
2324
2325 return err;
2326}
2327
Szymon Jancc35938b2011-03-22 13:12:21 +01002328static int read_local_oob_data(struct sock *sk, u16 index)
2329{
2330 struct hci_dev *hdev;
2331 struct pending_cmd *cmd;
2332 int err;
2333
2334 BT_DBG("hci%u", index);
2335
2336 hdev = hci_dev_get(index);
2337 if (!hdev)
2338 return cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002339 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancc35938b2011-03-22 13:12:21 +01002340
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002341 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002342
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002343 if (!hdev_is_powered(hdev)) {
Szymon Jancc35938b2011-03-22 13:12:21 +01002344 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002345 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002346 goto unlock;
2347 }
2348
2349 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
2350 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002351 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002352 goto unlock;
2353 }
2354
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002355 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02002356 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2357 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01002358 goto unlock;
2359 }
2360
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002361 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01002362 if (!cmd) {
2363 err = -ENOMEM;
2364 goto unlock;
2365 }
2366
2367 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
2368 if (err < 0)
2369 mgmt_pending_remove(cmd);
2370
2371unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002372 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002373 hci_dev_put(hdev);
2374
2375 return err;
2376}
2377
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002378static int add_remote_oob_data(struct sock *sk, u16 index, void *data,
2379 u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002380{
2381 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002382 struct mgmt_cp_add_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002383 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002384 int err;
2385
2386 BT_DBG("hci%u ", index);
2387
2388 if (len != sizeof(*cp))
2389 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002390 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01002391
2392 hdev = hci_dev_get(index);
2393 if (!hdev)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002394 return cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
2395 MGMT_STATUS_INVALID_PARAMS,
2396 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002397
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002398 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002399
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002400 if (!hdev_is_powered(hdev)) {
2401 err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
2402 MGMT_STATUS_NOT_POWERED,
2403 &cp->addr, sizeof(cp->addr));
2404 goto unlock;
2405 }
2406
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002407 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, cp->hash,
Szymon Janc2763eda2011-03-22 13:12:22 +01002408 cp->randomizer);
2409 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002410 status = MGMT_STATUS_FAILED;
Szymon Janc2763eda2011-03-22 13:12:22 +01002411 else
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002412 status = 0;
2413
2414 err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, status,
2415 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002416
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002417unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002418 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002419 hci_dev_put(hdev);
2420
2421 return err;
2422}
2423
2424static int remove_remote_oob_data(struct sock *sk, u16 index,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002425 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002426{
2427 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002428 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002429 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002430 int err;
2431
2432 BT_DBG("hci%u ", index);
2433
2434 if (len != sizeof(*cp))
2435 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002436 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01002437
2438 hdev = hci_dev_get(index);
2439 if (!hdev)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002440 return cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2441 MGMT_STATUS_INVALID_PARAMS,
2442 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002443
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002444 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002445
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002446 if (!hdev_is_powered(hdev)) {
2447 err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2448 MGMT_STATUS_NOT_POWERED,
2449 &cp->addr, sizeof(cp->addr));
2450 goto unlock;
2451 }
2452
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002453 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr);
Szymon Janc2763eda2011-03-22 13:12:22 +01002454 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002455 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01002456 else
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002457 status = 0;
2458
2459 err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA, status,
2460 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002461
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002462unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002463 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002464 hci_dev_put(hdev);
2465
2466 return err;
2467}
2468
Andre Guedes5e0452c2012-02-17 20:39:38 -03002469static int discovery(struct hci_dev *hdev)
2470{
2471 int err;
2472
2473 if (lmp_host_le_capable(hdev)) {
2474 if (lmp_bredr_capable(hdev)) {
2475 err = hci_le_scan(hdev, LE_SCAN_TYPE,
2476 LE_SCAN_INT, LE_SCAN_WIN,
2477 LE_SCAN_TIMEOUT_BREDR_LE);
2478 } else {
2479 hdev->discovery.type = DISCOV_TYPE_LE;
2480 err = hci_le_scan(hdev, LE_SCAN_TYPE,
2481 LE_SCAN_INT, LE_SCAN_WIN,
2482 LE_SCAN_TIMEOUT_LE_ONLY);
2483 }
2484 } else {
2485 hdev->discovery.type = DISCOV_TYPE_BREDR;
2486 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
2487 }
2488
2489 return err;
2490}
2491
2492int mgmt_interleaved_discovery(struct hci_dev *hdev)
2493{
2494 int err;
2495
2496 BT_DBG("%s", hdev->name);
2497
2498 hci_dev_lock(hdev);
2499
2500 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR_LE);
2501 if (err < 0)
2502 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2503
2504 hci_dev_unlock(hdev);
2505
2506 return err;
2507}
2508
Johan Hedberg450dfda2011-11-12 11:58:22 +02002509static int start_discovery(struct sock *sk, u16 index,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002510 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002511{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002512 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002513 struct pending_cmd *cmd;
2514 struct hci_dev *hdev;
2515 int err;
2516
2517 BT_DBG("hci%u", index);
2518
Johan Hedberg450dfda2011-11-12 11:58:22 +02002519 if (len != sizeof(*cp))
2520 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2521 MGMT_STATUS_INVALID_PARAMS);
2522
Johan Hedberg14a53662011-04-27 10:29:56 -04002523 hdev = hci_dev_get(index);
2524 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002525 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2526 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg14a53662011-04-27 10:29:56 -04002527
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002528 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002529
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002530 if (!hdev_is_powered(hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02002531 err = cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2532 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02002533 goto failed;
2534 }
2535
Johan Hedbergff9ef572012-01-04 14:23:45 +02002536 if (hdev->discovery.state != DISCOVERY_STOPPED) {
2537 err = cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2538 MGMT_STATUS_BUSY);
2539 goto failed;
2540 }
2541
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002542 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002543 if (!cmd) {
2544 err = -ENOMEM;
2545 goto failed;
2546 }
2547
Andre Guedes4aab14e2012-02-17 20:39:36 -03002548 hdev->discovery.type = cp->type;
2549
2550 switch (hdev->discovery.type) {
Andre Guedesf39799f2012-02-17 20:39:35 -03002551 case DISCOV_TYPE_BREDR:
Andre Guedes3fd24152012-02-03 17:48:01 -03002552 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
Andre Guedesf39799f2012-02-17 20:39:35 -03002553 break;
2554
2555 case DISCOV_TYPE_LE:
Andre Guedes3fd24152012-02-03 17:48:01 -03002556 err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT,
2557 LE_SCAN_WIN, LE_SCAN_TIMEOUT_LE_ONLY);
Andre Guedesf39799f2012-02-17 20:39:35 -03002558 break;
2559
Andre Guedes5e0452c2012-02-17 20:39:38 -03002560 case DISCOV_TYPE_INTERLEAVED:
2561 err = discovery(hdev);
2562 break;
2563
Andre Guedesf39799f2012-02-17 20:39:35 -03002564 default:
Andre Guedes3fd24152012-02-03 17:48:01 -03002565 err = -EINVAL;
Andre Guedesf39799f2012-02-17 20:39:35 -03002566 }
Andre Guedes3fd24152012-02-03 17:48:01 -03002567
Johan Hedberg14a53662011-04-27 10:29:56 -04002568 if (err < 0)
2569 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002570 else
2571 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002572
2573failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002574 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002575 hci_dev_put(hdev);
2576
2577 return err;
2578}
2579
Johan Hedbergd9306502012-02-20 23:25:18 +02002580static int stop_discovery(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002581{
Johan Hedbergd9306502012-02-20 23:25:18 +02002582 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002583 struct hci_dev *hdev;
2584 struct pending_cmd *cmd;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002585 struct hci_cp_remote_name_req_cancel cp;
2586 struct inquiry_entry *e;
Johan Hedberg14a53662011-04-27 10:29:56 -04002587 int err;
2588
2589 BT_DBG("hci%u", index);
2590
Johan Hedbergd9306502012-02-20 23:25:18 +02002591 if (len != sizeof(*mgmt_cp))
2592 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY,
2593 MGMT_STATUS_INVALID_PARAMS);
2594
Johan Hedberg14a53662011-04-27 10:29:56 -04002595 hdev = hci_dev_get(index);
2596 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002597 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY,
2598 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg14a53662011-04-27 10:29:56 -04002599
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002600 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002601
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002602 if (!hci_discovery_active(hdev)) {
Johan Hedbergd9306502012-02-20 23:25:18 +02002603 err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY,
2604 MGMT_STATUS_REJECTED,
2605 &mgmt_cp->type, sizeof(mgmt_cp->type));
2606 goto unlock;
2607 }
2608
2609 if (hdev->discovery.type != mgmt_cp->type) {
2610 err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY,
2611 MGMT_STATUS_INVALID_PARAMS,
2612 &mgmt_cp->type, sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002613 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02002614 }
2615
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002616 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002617 if (!cmd) {
2618 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002619 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04002620 }
2621
Andre Guedes343f9352012-02-17 20:39:37 -03002622 if (hdev->discovery.state == DISCOVERY_FINDING) {
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002623 err = hci_cancel_inquiry(hdev);
2624 if (err < 0)
2625 mgmt_pending_remove(cmd);
2626 else
2627 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
2628 goto unlock;
2629 }
2630
2631 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY, NAME_PENDING);
2632 if (!e) {
2633 mgmt_pending_remove(cmd);
Johan Hedbergaee9b212012-02-18 15:07:59 +02002634 err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY, 0,
Johan Hedbergd9306502012-02-20 23:25:18 +02002635 &mgmt_cp->type, sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002636 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2637 goto unlock;
2638 }
2639
2640 bacpy(&cp.bdaddr, &e->data.bdaddr);
2641 err = hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ_CANCEL,
2642 sizeof(cp), &cp);
Johan Hedberg14a53662011-04-27 10:29:56 -04002643 if (err < 0)
2644 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002645 else
2646 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002647
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002648unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002649 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002650 hci_dev_put(hdev);
2651
2652 return err;
2653}
2654
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002655static int confirm_name(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02002656{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002657 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002658 struct inquiry_entry *e;
2659 struct hci_dev *hdev;
2660 int err;
2661
2662 BT_DBG("hci%u", index);
2663
2664 if (len != sizeof(*cp))
2665 return cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2666 MGMT_STATUS_INVALID_PARAMS);
2667
2668 hdev = hci_dev_get(index);
2669 if (!hdev)
2670 return cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2671 MGMT_STATUS_INVALID_PARAMS);
2672
2673 hci_dev_lock(hdev);
2674
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002675 if (!hci_discovery_active(hdev)) {
2676 err = cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2677 MGMT_STATUS_FAILED);
2678 goto failed;
2679 }
2680
Johan Hedberga198e7b2012-02-17 14:27:06 +02002681 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002682 if (!e) {
Marcel Holtmanne5f0e152012-02-22 11:59:01 +01002683 err = cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
Johan Hedberg561aafb2012-01-04 13:31:59 +02002684 MGMT_STATUS_INVALID_PARAMS);
2685 goto failed;
2686 }
2687
2688 if (cp->name_known) {
2689 e->name_state = NAME_KNOWN;
2690 list_del(&e->list);
2691 } else {
2692 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e202012-01-09 00:53:02 +02002693 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002694 }
2695
2696 err = 0;
2697
2698failed:
2699 hci_dev_unlock(hdev);
2700
2701 return err;
2702}
2703
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002704static int block_device(struct sock *sk, u16 index, void *data, u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002705{
2706 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002707 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002708 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03002709 int err;
2710
2711 BT_DBG("hci%u", index);
2712
Antti Julku7fbec222011-06-15 12:01:15 +03002713 if (len != sizeof(*cp))
2714 return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002715 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002716
2717 hdev = hci_dev_get(index);
2718 if (!hdev)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002719 return cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE,
2720 MGMT_STATUS_INVALID_PARAMS,
2721 &cp->addr, sizeof(cp->addr));
Antti Julku7fbec222011-06-15 12:01:15 +03002722
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002723 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002724
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002725 err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002726 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002727 status = MGMT_STATUS_FAILED;
Antti Julku7fbec222011-06-15 12:01:15 +03002728 else
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002729 status = 0;
2730
2731 err = cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE, status,
2732 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03002733
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002734 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002735 hci_dev_put(hdev);
2736
2737 return err;
2738}
2739
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002740static int unblock_device(struct sock *sk, u16 index, void *data, u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002741{
2742 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002743 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002744 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03002745 int err;
2746
2747 BT_DBG("hci%u", index);
2748
Antti Julku7fbec222011-06-15 12:01:15 +03002749 if (len != sizeof(*cp))
2750 return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002751 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002752
2753 hdev = hci_dev_get(index);
2754 if (!hdev)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002755 return cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE,
2756 MGMT_STATUS_INVALID_PARAMS,
2757 &cp->addr, sizeof(cp->addr));
Antti Julku7fbec222011-06-15 12:01:15 +03002758
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002759 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002760
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002761 err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002762 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002763 status = MGMT_STATUS_INVALID_PARAMS;
Antti Julku7fbec222011-06-15 12:01:15 +03002764 else
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002765 status = 0;
2766
2767 err = cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE, status,
2768 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03002769
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002770 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002771 hci_dev_put(hdev);
2772
2773 return err;
2774}
2775
Antti Julkuf6422ec2011-06-22 13:11:56 +03002776static int set_fast_connectable(struct sock *sk, u16 index,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002777 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03002778{
2779 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002780 struct mgmt_mode *cp = data;
Antti Julkuf6422ec2011-06-22 13:11:56 +03002781 struct hci_cp_write_page_scan_activity acp;
2782 u8 type;
2783 int err;
2784
2785 BT_DBG("hci%u", index);
2786
2787 if (len != sizeof(*cp))
2788 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002789 MGMT_STATUS_INVALID_PARAMS);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002790
2791 hdev = hci_dev_get(index);
2792 if (!hdev)
2793 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002794 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg5400c042012-02-21 16:40:33 +02002795 if (!hdev_is_powered(hdev))
2796 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
2797 MGMT_STATUS_NOT_POWERED);
2798
2799 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
2800 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
2801 MGMT_STATUS_REJECTED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002802
2803 hci_dev_lock(hdev);
2804
Johan Hedbergf7c68692011-12-15 00:47:36 +02002805 if (cp->val) {
Antti Julkuf6422ec2011-06-22 13:11:56 +03002806 type = PAGE_SCAN_TYPE_INTERLACED;
2807 acp.interval = 0x0024; /* 22.5 msec page scan interval */
2808 } else {
2809 type = PAGE_SCAN_TYPE_STANDARD; /* default */
2810 acp.interval = 0x0800; /* default 1.28 sec page scan */
2811 }
2812
2813 acp.window = 0x0012; /* default 11.25 msec page scan window */
2814
2815 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
2816 sizeof(acp), &acp);
2817 if (err < 0) {
2818 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002819 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002820 goto done;
2821 }
2822
2823 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
2824 if (err < 0) {
2825 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002826 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002827 goto done;
2828 }
2829
Johan Hedbergaee9b212012-02-18 15:07:59 +02002830 err = cmd_complete(sk, index, MGMT_OP_SET_FAST_CONNECTABLE, 0,
2831 NULL, 0);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002832done:
2833 hci_dev_unlock(hdev);
2834 hci_dev_put(hdev);
2835
2836 return err;
2837}
2838
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002839static int load_long_term_keys(struct sock *sk, u16 index,
2840 void *cp_data, u16 len)
2841{
2842 struct hci_dev *hdev;
2843 struct mgmt_cp_load_long_term_keys *cp = cp_data;
2844 u16 key_count, expected_len;
2845 int i;
2846
2847 if (len < sizeof(*cp))
2848 return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS,
2849 EINVAL);
2850
2851 key_count = get_unaligned_le16(&cp->key_count);
2852
2853 expected_len = sizeof(*cp) + key_count *
2854 sizeof(struct mgmt_ltk_info);
2855 if (expected_len != len) {
2856 BT_ERR("load_keys: expected %u bytes, got %u bytes",
2857 len, expected_len);
2858 return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS,
2859 EINVAL);
2860 }
2861
2862 hdev = hci_dev_get(index);
2863 if (!hdev)
2864 return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS,
2865 ENODEV);
2866
2867 BT_DBG("hci%u key_count %u", index, key_count);
2868
2869 hci_dev_lock(hdev);
2870
2871 hci_smp_ltks_clear(hdev);
2872
2873 for (i = 0; i < key_count; i++) {
2874 struct mgmt_ltk_info *key = &cp->keys[i];
2875 u8 type;
2876
2877 if (key->master)
2878 type = HCI_SMP_LTK;
2879 else
2880 type = HCI_SMP_LTK_SLAVE;
2881
2882 hci_add_ltk(hdev, &key->addr.bdaddr, key->addr.type,
2883 type, 0, key->authenticated, key->val,
2884 key->enc_size, key->ediv, key->rand);
2885 }
2886
2887 hci_dev_unlock(hdev);
2888 hci_dev_put(hdev);
2889
2890 return 0;
2891}
2892
Johan Hedberg03811012010-12-08 00:21:06 +02002893int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
2894{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002895 void *buf;
2896 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02002897 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002898 u16 opcode, index, len;
Johan Hedberg03811012010-12-08 00:21:06 +02002899 int err;
2900
2901 BT_DBG("got %zu bytes", msglen);
2902
2903 if (msglen < sizeof(*hdr))
2904 return -EINVAL;
2905
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03002906 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02002907 if (!buf)
2908 return -ENOMEM;
2909
2910 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
2911 err = -EFAULT;
2912 goto done;
2913 }
2914
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002915 hdr = buf;
Johan Hedberg03811012010-12-08 00:21:06 +02002916 opcode = get_unaligned_le16(&hdr->opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002917 index = get_unaligned_le16(&hdr->index);
Johan Hedberg03811012010-12-08 00:21:06 +02002918 len = get_unaligned_le16(&hdr->len);
2919
2920 if (len != msglen - sizeof(*hdr)) {
2921 err = -EINVAL;
2922 goto done;
2923 }
2924
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002925 cp = buf + sizeof(*hdr);
2926
Johan Hedberg03811012010-12-08 00:21:06 +02002927 switch (opcode) {
Johan Hedberg02d98122010-12-13 21:07:04 +02002928 case MGMT_OP_READ_VERSION:
2929 err = read_version(sk);
2930 break;
Johan Hedberge70bb2e2012-02-13 16:59:33 +02002931 case MGMT_OP_READ_COMMANDS:
2932 err = read_commands(sk);
2933 break;
Johan Hedbergfaba42e2010-12-13 21:07:05 +02002934 case MGMT_OP_READ_INDEX_LIST:
2935 err = read_index_list(sk);
2936 break;
Johan Hedbergf7b64e62010-12-13 21:07:06 +02002937 case MGMT_OP_READ_INFO:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002938 err = read_controller_info(sk, index);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02002939 break;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002940 case MGMT_OP_SET_POWERED:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002941 err = set_powered(sk, index, cp, len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002942 break;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002943 case MGMT_OP_SET_DISCOVERABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002944 err = set_discoverable(sk, index, cp, len);
Johan Hedberg73f22f62010-12-29 16:00:25 +02002945 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002946 case MGMT_OP_SET_CONNECTABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002947 err = set_connectable(sk, index, cp, len);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002948 break;
Johan Hedbergf7c68692011-12-15 00:47:36 +02002949 case MGMT_OP_SET_FAST_CONNECTABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002950 err = set_fast_connectable(sk, index, cp, len);
Johan Hedbergf7c68692011-12-15 00:47:36 +02002951 break;
Johan Hedbergc542a062011-01-26 13:11:03 +02002952 case MGMT_OP_SET_PAIRABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002953 err = set_pairable(sk, index, cp, len);
Johan Hedbergc542a062011-01-26 13:11:03 +02002954 break;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02002955 case MGMT_OP_SET_LINK_SECURITY:
2956 err = set_link_security(sk, index, cp, len);
2957 break;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02002958 case MGMT_OP_SET_SSP:
2959 err = set_ssp(sk, index, cp, len);
2960 break;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02002961 case MGMT_OP_SET_HS:
2962 err = set_hs(sk, index, cp, len);
2963 break;
Johan Hedberg06199cf2012-02-22 16:37:11 +02002964 case MGMT_OP_SET_LE:
2965 err = set_le(sk, index, cp, len);
2966 break;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002967 case MGMT_OP_ADD_UUID:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002968 err = add_uuid(sk, index, cp, len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002969 break;
2970 case MGMT_OP_REMOVE_UUID:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002971 err = remove_uuid(sk, index, cp, len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002972 break;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002973 case MGMT_OP_SET_DEV_CLASS:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002974 err = set_dev_class(sk, index, cp, len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002975 break;
Johan Hedberg86742e12011-11-07 23:13:38 +02002976 case MGMT_OP_LOAD_LINK_KEYS:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002977 err = load_link_keys(sk, index, cp, len);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002978 break;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002979 case MGMT_OP_DISCONNECT:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002980 err = disconnect(sk, index, cp, len);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002981 break;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002982 case MGMT_OP_GET_CONNECTIONS:
Szymon Janc8ce62842011-03-01 16:55:32 +01002983 err = get_connections(sk, index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002984 break;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002985 case MGMT_OP_PIN_CODE_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002986 err = pin_code_reply(sk, index, cp, len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002987 break;
2988 case MGMT_OP_PIN_CODE_NEG_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002989 err = pin_code_neg_reply(sk, index, cp, len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002990 break;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002991 case MGMT_OP_SET_IO_CAPABILITY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002992 err = set_io_capability(sk, index, cp, len);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002993 break;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002994 case MGMT_OP_PAIR_DEVICE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002995 err = pair_device(sk, index, cp, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002996 break;
Johan Hedberg28424702012-02-02 04:02:29 +02002997 case MGMT_OP_CANCEL_PAIR_DEVICE:
2998 err = cancel_pair_device(sk, index, buf + sizeof(*hdr), len);
2999 break;
Johan Hedberg124f6e32012-02-09 13:50:12 +02003000 case MGMT_OP_UNPAIR_DEVICE:
3001 err = unpair_device(sk, index, cp, len);
3002 break;
Johan Hedberga5c29682011-02-19 12:05:57 -03003003 case MGMT_OP_USER_CONFIRM_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003004 err = user_confirm_reply(sk, index, cp, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03003005 break;
3006 case MGMT_OP_USER_CONFIRM_NEG_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003007 err = user_confirm_neg_reply(sk, index, cp, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03003008 break;
Brian Gix604086b2011-11-23 08:28:33 -08003009 case MGMT_OP_USER_PASSKEY_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003010 err = user_passkey_reply(sk, index, cp, len);
Brian Gix604086b2011-11-23 08:28:33 -08003011 break;
3012 case MGMT_OP_USER_PASSKEY_NEG_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003013 err = user_passkey_neg_reply(sk, index, cp, len);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02003014 break;
Johan Hedbergb312b1612011-03-16 14:29:37 +02003015 case MGMT_OP_SET_LOCAL_NAME:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003016 err = set_local_name(sk, index, cp, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003017 break;
Szymon Jancc35938b2011-03-22 13:12:21 +01003018 case MGMT_OP_READ_LOCAL_OOB_DATA:
3019 err = read_local_oob_data(sk, index);
3020 break;
Szymon Janc2763eda2011-03-22 13:12:22 +01003021 case MGMT_OP_ADD_REMOTE_OOB_DATA:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003022 err = add_remote_oob_data(sk, index, cp, len);
Szymon Janc2763eda2011-03-22 13:12:22 +01003023 break;
3024 case MGMT_OP_REMOVE_REMOTE_OOB_DATA:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003025 err = remove_remote_oob_data(sk, index, cp, len);
Szymon Janc2763eda2011-03-22 13:12:22 +01003026 break;
Johan Hedberg14a53662011-04-27 10:29:56 -04003027 case MGMT_OP_START_DISCOVERY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003028 err = start_discovery(sk, index, cp, len);
Johan Hedberg14a53662011-04-27 10:29:56 -04003029 break;
3030 case MGMT_OP_STOP_DISCOVERY:
Johan Hedbergd9306502012-02-20 23:25:18 +02003031 err = stop_discovery(sk, index, cp, len);
Johan Hedberg14a53662011-04-27 10:29:56 -04003032 break;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003033 case MGMT_OP_CONFIRM_NAME:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003034 err = confirm_name(sk, index, cp, len);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003035 break;
Antti Julku7fbec222011-06-15 12:01:15 +03003036 case MGMT_OP_BLOCK_DEVICE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003037 err = block_device(sk, index, cp, len);
Antti Julku7fbec222011-06-15 12:01:15 +03003038 break;
3039 case MGMT_OP_UNBLOCK_DEVICE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003040 err = unblock_device(sk, index, cp, len);
Antti Julku7fbec222011-06-15 12:01:15 +03003041 break;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003042 case MGMT_OP_LOAD_LONG_TERM_KEYS:
3043 err = load_long_term_keys(sk, index, cp, len);
3044 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003045 default:
Johan Hedberg72a734e2010-12-30 00:38:22 +02003046 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02003047 err = cmd_status(sk, index, opcode,
3048 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003049 break;
3050 }
Johan Hedberg72a734e2010-12-30 00:38:22 +02003051
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003052 if (err < 0)
Johan Hedberg72a734e2010-12-30 00:38:22 +02003053 goto done;
3054
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003055 err = msglen;
3056
3057done:
3058 kfree(buf);
3059 return err;
3060}
3061
Johan Hedbergb24752f2011-11-03 14:40:33 +02003062static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
3063{
3064 u8 *status = data;
3065
3066 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
3067 mgmt_pending_remove(cmd);
3068}
3069
Johan Hedberg744cf192011-11-08 20:40:14 +02003070int mgmt_index_added(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +02003071{
Johan Hedberg744cf192011-11-08 20:40:14 +02003072 return mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02003073}
3074
Johan Hedberg744cf192011-11-08 20:40:14 +02003075int mgmt_index_removed(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +02003076{
Johan Hedbergb24752f2011-11-03 14:40:33 +02003077 u8 status = ENODEV;
3078
Johan Hedberg744cf192011-11-08 20:40:14 +02003079 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02003080
Johan Hedberg744cf192011-11-08 20:40:14 +02003081 return mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02003082}
3083
3084struct cmd_lookup {
Johan Hedberg03811012010-12-08 00:21:06 +02003085 struct sock *sk;
Johan Hedberg69ab39e2011-12-15 00:47:35 +02003086 struct hci_dev *hdev;
Johan Hedberg03811012010-12-08 00:21:06 +02003087};
3088
Johan Hedberg69ab39e2011-12-15 00:47:35 +02003089static void settings_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberg03811012010-12-08 00:21:06 +02003090{
Johan Hedberg03811012010-12-08 00:21:06 +02003091 struct cmd_lookup *match = data;
3092
Johan Hedberg69ab39e2011-12-15 00:47:35 +02003093 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02003094
3095 list_del(&cmd->list);
3096
3097 if (match->sk == NULL) {
3098 match->sk = cmd->sk;
3099 sock_hold(match->sk);
3100 }
3101
3102 mgmt_pending_free(cmd);
3103}
3104
Johan Hedberg744cf192011-11-08 20:40:14 +02003105int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg03811012010-12-08 00:21:06 +02003106{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02003107 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003108 int err;
Johan Hedberg03811012010-12-08 00:21:06 +02003109
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003110 if (!test_bit(HCI_MGMT, &hdev->dev_flags))
3111 return 0;
3112
Johan Hedberg69ab39e2011-12-15 00:47:35 +02003113 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
Johan Hedberg03811012010-12-08 00:21:06 +02003114
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003115 if (powered) {
3116 u8 scan = 0;
3117
3118 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3119 scan |= SCAN_PAGE;
3120 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3121 scan |= SCAN_INQUIRY;
3122
3123 if (scan)
3124 hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
Johan Hedberg504c8dc2012-02-23 13:30:41 +02003125
3126 update_class(hdev);
3127 update_eir(hdev);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003128 } else {
Johan Hedbergb24752f2011-11-03 14:40:33 +02003129 u8 status = ENETDOWN;
Johan Hedberg744cf192011-11-08 20:40:14 +02003130 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02003131 }
3132
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003133 err = new_settings(hdev, match.sk);
Johan Hedberg03811012010-12-08 00:21:06 +02003134
3135 if (match.sk)
3136 sock_put(match.sk);
3137
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003138 return err;
Johan Hedberg03811012010-12-08 00:21:06 +02003139}
3140
Johan Hedberg744cf192011-11-08 20:40:14 +02003141int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg03811012010-12-08 00:21:06 +02003142{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02003143 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003144 bool changed = false;
3145 int err = 0;
Johan Hedberg03811012010-12-08 00:21:06 +02003146
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003147 if (discoverable) {
3148 if (!test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3149 changed = true;
3150 } else {
3151 if (test_and_clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3152 changed = true;
3153 }
Johan Hedberg03811012010-12-08 00:21:06 +02003154
Johan Hedberged9b5f22012-02-21 20:47:06 +02003155 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp,
3156 &match);
3157
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003158 if (changed)
3159 err = new_settings(hdev, match.sk);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003160
Johan Hedberg03811012010-12-08 00:21:06 +02003161 if (match.sk)
3162 sock_put(match.sk);
3163
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003164 return err;
Johan Hedberg03811012010-12-08 00:21:06 +02003165}
3166
Johan Hedberg744cf192011-11-08 20:40:14 +02003167int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg03811012010-12-08 00:21:06 +02003168{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02003169 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003170 bool changed = false;
3171 int err = 0;
Johan Hedberg03811012010-12-08 00:21:06 +02003172
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003173 if (connectable) {
3174 if (!test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3175 changed = true;
3176 } else {
3177 if (test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3178 changed = true;
3179 }
Johan Hedberg03811012010-12-08 00:21:06 +02003180
Johan Hedberged9b5f22012-02-21 20:47:06 +02003181 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev, settings_rsp,
3182 &match);
3183
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003184 if (changed)
3185 err = new_settings(hdev, match.sk);
Johan Hedberg03811012010-12-08 00:21:06 +02003186
3187 if (match.sk)
3188 sock_put(match.sk);
3189
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003190 return err;
Johan Hedberg03811012010-12-08 00:21:06 +02003191}
3192
Johan Hedberg744cf192011-11-08 20:40:14 +02003193int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003194{
Johan Hedbergca69b792011-11-11 18:10:00 +02003195 u8 mgmt_err = mgmt_status(status);
3196
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003197 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02003198 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Johan Hedbergca69b792011-11-11 18:10:00 +02003199 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003200
3201 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02003202 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Johan Hedbergca69b792011-11-11 18:10:00 +02003203 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003204
3205 return 0;
3206}
3207
Johan Hedberg744cf192011-11-08 20:40:14 +02003208int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
3209 u8 persistent)
Johan Hedberg03811012010-12-08 00:21:06 +02003210{
Johan Hedberg86742e12011-11-07 23:13:38 +02003211 struct mgmt_ev_new_link_key ev;
Johan Hedberg03811012010-12-08 00:21:06 +02003212
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003213 memset(&ev, 0, sizeof(ev));
Johan Hedberg03811012010-12-08 00:21:06 +02003214
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003215 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02003216 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
3217 ev.key.addr.type = MGMT_ADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003218 ev.key.type = key->type;
3219 memcpy(ev.key.val, key->val, 16);
3220 ev.key.pin_len = key->pin_len;
Johan Hedberg03811012010-12-08 00:21:06 +02003221
Johan Hedberg744cf192011-11-08 20:40:14 +02003222 return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02003223}
Johan Hedbergf7520542011-01-20 12:34:39 +02003224
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003225int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
3226{
3227 struct mgmt_ev_new_long_term_key ev;
3228
3229 memset(&ev, 0, sizeof(ev));
3230
3231 ev.store_hint = persistent;
3232 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
3233 ev.key.addr.type = key->bdaddr_type;
3234 ev.key.authenticated = key->authenticated;
3235 ev.key.enc_size = key->enc_size;
3236 ev.key.ediv = key->ediv;
3237
3238 if (key->type == HCI_SMP_LTK)
3239 ev.key.master = 1;
3240
3241 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
3242 memcpy(ev.key.val, key->val, sizeof(key->val));
3243
3244 return mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev,
3245 &ev, sizeof(ev), NULL);
3246}
3247
Johan Hedbergafc747a2012-01-15 18:11:07 +02003248int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Johan Hedbergb644ba32012-01-17 21:48:47 +02003249 u8 addr_type, u8 *name, u8 name_len,
3250 u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02003251{
Johan Hedbergb644ba32012-01-17 21:48:47 +02003252 char buf[512];
3253 struct mgmt_ev_device_connected *ev = (void *) buf;
3254 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02003255
Johan Hedbergb644ba32012-01-17 21:48:47 +02003256 bacpy(&ev->addr.bdaddr, bdaddr);
3257 ev->addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02003258
Johan Hedbergb644ba32012-01-17 21:48:47 +02003259 if (name_len > 0)
3260 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
3261 name, name_len);
3262
3263 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
3264 eir_len = eir_append_data(&ev->eir[eir_len], eir_len,
3265 EIR_CLASS_OF_DEV, dev_class, 3);
3266
3267 put_unaligned_le16(eir_len, &ev->eir_len);
3268
3269 return mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
3270 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02003271}
3272
Johan Hedberg8962ee72011-01-20 12:40:27 +02003273static void disconnect_rsp(struct pending_cmd *cmd, void *data)
3274{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01003275 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003276 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02003277 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003278
Johan Hedberg88c3df12012-02-09 14:27:38 +02003279 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3280 rp.addr.type = cp->addr.type;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003281
Johan Hedbergaee9b212012-02-18 15:07:59 +02003282 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, 0, &rp,
3283 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003284
3285 *sk = cmd->sk;
3286 sock_hold(*sk);
3287
Johan Hedberga664b5b2011-02-19 12:06:02 -03003288 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003289}
3290
Johan Hedberg124f6e32012-02-09 13:50:12 +02003291static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02003292{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003293 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02003294 struct mgmt_cp_unpair_device *cp = cmd->param;
3295 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02003296
3297 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02003298 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3299 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02003300
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003301 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
3302
Johan Hedbergaee9b212012-02-18 15:07:59 +02003303 cmd_complete(cmd->sk, cmd->index, cmd->opcode, 0, &rp, sizeof(rp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02003304
3305 mgmt_pending_remove(cmd);
3306}
3307
Johan Hedbergafc747a2012-01-15 18:11:07 +02003308int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
3309 u8 link_type, u8 addr_type)
Johan Hedbergf7520542011-01-20 12:34:39 +02003310{
Johan Hedberg4c659c32011-11-07 23:13:39 +02003311 struct mgmt_addr_info ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003312 struct sock *sk = NULL;
3313 int err;
3314
Johan Hedberg744cf192011-11-08 20:40:14 +02003315 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02003316
Johan Hedbergf7520542011-01-20 12:34:39 +02003317 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02003318 ev.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02003319
Johan Hedbergafc747a2012-01-15 18:11:07 +02003320 err = mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev),
3321 sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003322
3323 if (sk)
3324 sock_put(sk);
3325
Johan Hedberg124f6e32012-02-09 13:50:12 +02003326 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003327 hdev);
Johan Hedberga8a1d192011-11-10 15:54:38 +02003328
Johan Hedberg8962ee72011-01-20 12:40:27 +02003329 return err;
3330}
3331
Johan Hedberg88c3df12012-02-09 14:27:38 +02003332int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
3333 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02003334{
Johan Hedberg88c3df12012-02-09 14:27:38 +02003335 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003336 struct pending_cmd *cmd;
3337 int err;
3338
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003339 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003340 if (!cmd)
3341 return -ENOENT;
3342
Johan Hedberg88c3df12012-02-09 14:27:38 +02003343 bacpy(&rp.addr.bdaddr, bdaddr);
3344 rp.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02003345
Johan Hedberg88c3df12012-02-09 14:27:38 +02003346 err = cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
Johan Hedbergaee9b212012-02-18 15:07:59 +02003347 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003348
Johan Hedberga664b5b2011-02-19 12:06:02 -03003349 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003350
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003351 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
3352 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003353 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02003354}
Johan Hedberg17d5c042011-01-22 06:09:08 +02003355
Johan Hedberg48264f02011-11-09 13:58:58 +02003356int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
3357 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02003358{
3359 struct mgmt_ev_connect_failed ev;
3360
Johan Hedberg4c659c32011-11-07 23:13:39 +02003361 bacpy(&ev.addr.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02003362 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003363 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003364
Johan Hedberg744cf192011-11-08 20:40:14 +02003365 return mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003366}
Johan Hedberg980e1a52011-01-22 06:10:07 +02003367
Johan Hedberg744cf192011-11-08 20:40:14 +02003368int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003369{
3370 struct mgmt_ev_pin_code_request ev;
3371
Johan Hedbergd8457692012-02-17 14:24:57 +02003372 bacpy(&ev.addr.bdaddr, bdaddr);
3373 ev.addr.type = MGMT_ADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02003374 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003375
Johan Hedberg744cf192011-11-08 20:40:14 +02003376 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01003377 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003378}
3379
Johan Hedberg744cf192011-11-08 20:40:14 +02003380int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3381 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003382{
3383 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003384 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003385 int err;
3386
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003387 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003388 if (!cmd)
3389 return -ENOENT;
3390
Johan Hedbergd8457692012-02-17 14:24:57 +02003391 bacpy(&rp.addr.bdaddr, bdaddr);
3392 rp.addr.type = MGMT_ADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003393
Johan Hedbergaee9b212012-02-18 15:07:59 +02003394 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
3395 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003396
Johan Hedberga664b5b2011-02-19 12:06:02 -03003397 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003398
3399 return err;
3400}
3401
Johan Hedberg744cf192011-11-08 20:40:14 +02003402int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3403 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003404{
3405 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003406 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003407 int err;
3408
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003409 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003410 if (!cmd)
3411 return -ENOENT;
3412
Johan Hedbergd8457692012-02-17 14:24:57 +02003413 bacpy(&rp.addr.bdaddr, bdaddr);
3414 rp.addr.type = MGMT_ADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003415
Johan Hedbergaee9b212012-02-18 15:07:59 +02003416 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
3417 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003418
Johan Hedberga664b5b2011-02-19 12:06:02 -03003419 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003420
3421 return err;
3422}
Johan Hedberga5c29682011-02-19 12:05:57 -03003423
Johan Hedberg744cf192011-11-08 20:40:14 +02003424int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003425 u8 link_type, u8 addr_type, __le32 value,
3426 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03003427{
3428 struct mgmt_ev_user_confirm_request ev;
3429
Johan Hedberg744cf192011-11-08 20:40:14 +02003430 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03003431
Johan Hedberg272d90d2012-02-09 15:26:12 +02003432 bacpy(&ev.addr.bdaddr, bdaddr);
3433 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07003434 ev.confirm_hint = confirm_hint;
Johan Hedberga5c29682011-02-19 12:05:57 -03003435 put_unaligned_le32(value, &ev.value);
3436
Johan Hedberg744cf192011-11-08 20:40:14 +02003437 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01003438 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03003439}
3440
Johan Hedberg272d90d2012-02-09 15:26:12 +02003441int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
3442 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08003443{
3444 struct mgmt_ev_user_passkey_request ev;
3445
3446 BT_DBG("%s", hdev->name);
3447
Johan Hedberg272d90d2012-02-09 15:26:12 +02003448 bacpy(&ev.addr.bdaddr, bdaddr);
3449 ev.addr.type = link_to_mgmt(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08003450
3451 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
3452 NULL);
3453}
3454
Brian Gix0df4c182011-11-16 13:53:13 -08003455static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003456 u8 link_type, u8 addr_type, u8 status,
3457 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03003458{
3459 struct pending_cmd *cmd;
3460 struct mgmt_rp_user_confirm_reply rp;
3461 int err;
3462
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003463 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03003464 if (!cmd)
3465 return -ENOENT;
3466
Johan Hedberg272d90d2012-02-09 15:26:12 +02003467 bacpy(&rp.addr.bdaddr, bdaddr);
3468 rp.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergaee9b212012-02-18 15:07:59 +02003469 err = cmd_complete(cmd->sk, hdev->id, opcode, mgmt_status(status),
3470 &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03003471
Johan Hedberga664b5b2011-02-19 12:06:02 -03003472 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03003473
3474 return err;
3475}
3476
Johan Hedberg744cf192011-11-08 20:40:14 +02003477int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003478 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003479{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003480 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3481 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003482}
3483
Johan Hedberg272d90d2012-02-09 15:26:12 +02003484int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3485 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003486{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003487 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3488 status, MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003489}
Johan Hedberg2a611692011-02-19 12:06:00 -03003490
Brian Gix604086b2011-11-23 08:28:33 -08003491int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003492 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003493{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003494 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3495 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003496}
3497
Johan Hedberg272d90d2012-02-09 15:26:12 +02003498int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3499 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003500{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003501 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3502 status, MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003503}
3504
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003505int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
3506 u8 addr_type, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03003507{
3508 struct mgmt_ev_auth_failed ev;
3509
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003510 bacpy(&ev.addr.bdaddr, bdaddr);
3511 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003512 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03003513
Johan Hedberg744cf192011-11-08 20:40:14 +02003514 return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03003515}
Johan Hedbergb312b1612011-03-16 14:29:37 +02003516
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003517int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
3518{
3519 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg47990ea2012-02-22 11:58:37 +02003520 bool changed = false;
3521 int err = 0;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003522
3523 if (status) {
3524 u8 mgmt_err = mgmt_status(status);
3525 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
3526 cmd_status_rsp, &mgmt_err);
3527 return 0;
3528 }
3529
Johan Hedberg47990ea2012-02-22 11:58:37 +02003530 if (test_bit(HCI_AUTH, &hdev->flags)) {
3531 if (!test_and_set_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
3532 changed = true;
3533 } else {
3534 if (test_and_clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
3535 changed = true;
3536 }
3537
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003538 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
3539 &match);
3540
Johan Hedberg47990ea2012-02-22 11:58:37 +02003541 if (changed)
3542 err = new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003543
3544 if (match.sk)
3545 sock_put(match.sk);
3546
3547 return err;
3548}
3549
Johan Hedbergcacaf522012-02-21 00:52:42 +02003550static int clear_eir(struct hci_dev *hdev)
3551{
3552 struct hci_cp_write_eir cp;
3553
3554 if (!(hdev->features[6] & LMP_EXT_INQ))
3555 return 0;
3556
Johan Hedbergc80da272012-02-22 15:38:48 +02003557 memset(hdev->eir, 0, sizeof(hdev->eir));
3558
Johan Hedbergcacaf522012-02-21 00:52:42 +02003559 memset(&cp, 0, sizeof(cp));
3560
3561 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
3562}
3563
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003564int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003565{
3566 struct cmd_lookup match = { NULL, hdev };
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003567 bool changed = false;
3568 int err = 0;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003569
3570 if (status) {
3571 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003572
3573 if (enable && test_and_clear_bit(HCI_SSP_ENABLED,
3574 &hdev->dev_flags))
3575 err = new_settings(hdev, NULL);
3576
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003577 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev,
3578 cmd_status_rsp, &mgmt_err);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003579
3580 return err;
3581 }
3582
3583 if (enable) {
3584 if (!test_and_set_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3585 changed = true;
3586 } else {
3587 if (test_and_clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3588 changed = true;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003589 }
3590
3591 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
3592
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003593 if (changed)
3594 err = new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003595
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02003596 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003597 sock_put(match.sk);
3598
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02003599 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3600 update_eir(hdev);
3601 else
3602 clear_eir(hdev);
Johan Hedbergcacaf522012-02-21 00:52:42 +02003603
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003604 return err;
3605}
3606
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003607int mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
3608 u8 status)
3609{
3610 int err;
3611
3612 err = mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class, 3, NULL);
3613
3614 return err;
3615}
3616
Johan Hedberg744cf192011-11-08 20:40:14 +02003617int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02003618{
3619 struct pending_cmd *cmd;
3620 struct mgmt_cp_set_local_name ev;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003621 bool changed = false;
3622 int err = 0;
3623
3624 if (memcmp(name, hdev->dev_name, sizeof(hdev->dev_name)) != 0) {
3625 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
3626 changed = true;
3627 }
Johan Hedbergb312b1612011-03-16 14:29:37 +02003628
3629 memset(&ev, 0, sizeof(ev));
3630 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003631 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003632
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003633 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003634 if (!cmd)
3635 goto send_event;
3636
Johan Hedberg7bdaae42012-02-22 21:39:58 +02003637 /* Always assume that either the short or the complete name has
3638 * changed if there was a pending mgmt command */
3639 changed = true;
3640
Johan Hedbergb312b1612011-03-16 14:29:37 +02003641 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02003642 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
Johan Hedbergca69b792011-11-11 18:10:00 +02003643 mgmt_status(status));
Johan Hedbergb312b1612011-03-16 14:29:37 +02003644 goto failed;
3645 }
3646
Johan Hedbergaee9b212012-02-18 15:07:59 +02003647 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0, &ev,
Johan Hedbergb312b1612011-03-16 14:29:37 +02003648 sizeof(ev));
3649 if (err < 0)
3650 goto failed;
3651
3652send_event:
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003653 if (changed)
3654 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev,
3655 sizeof(ev), cmd ? cmd->sk : NULL);
3656
Johan Hedbergf51d5b22012-02-22 18:17:32 +02003657 update_eir(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003658
3659failed:
3660 if (cmd)
3661 mgmt_pending_remove(cmd);
3662 return err;
3663}
Szymon Jancc35938b2011-03-22 13:12:21 +01003664
Johan Hedberg744cf192011-11-08 20:40:14 +02003665int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
3666 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01003667{
3668 struct pending_cmd *cmd;
3669 int err;
3670
Johan Hedberg744cf192011-11-08 20:40:14 +02003671 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01003672
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003673 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003674 if (!cmd)
3675 return -ENOENT;
3676
3677 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02003678 err = cmd_status(cmd->sk, hdev->id,
Johan Hedbergca69b792011-11-11 18:10:00 +02003679 MGMT_OP_READ_LOCAL_OOB_DATA,
3680 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01003681 } else {
3682 struct mgmt_rp_read_local_oob_data rp;
3683
3684 memcpy(rp.hash, hash, sizeof(rp.hash));
3685 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
3686
Johan Hedberg744cf192011-11-08 20:40:14 +02003687 err = cmd_complete(cmd->sk, hdev->id,
3688 MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergaee9b212012-02-18 15:07:59 +02003689 0, &rp, sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01003690 }
3691
3692 mgmt_pending_remove(cmd);
3693
3694 return err;
3695}
Johan Hedberge17acd42011-03-30 23:57:16 +03003696
Johan Hedberg06199cf2012-02-22 16:37:11 +02003697int mgmt_le_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
3698{
3699 struct cmd_lookup match = { NULL, hdev };
3700 bool changed = false;
3701 int err = 0;
3702
3703 if (status) {
3704 u8 mgmt_err = mgmt_status(status);
3705
3706 if (enable && test_and_clear_bit(HCI_LE_ENABLED,
3707 &hdev->dev_flags))
3708 err = new_settings(hdev, NULL);
3709
3710 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev,
3711 cmd_status_rsp, &mgmt_err);
3712
3713 return err;
3714 }
3715
3716 if (enable) {
3717 if (!test_and_set_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3718 changed = true;
3719 } else {
3720 if (test_and_clear_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3721 changed = true;
3722 }
3723
3724 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
3725
3726 if (changed)
3727 err = new_settings(hdev, match.sk);
3728
3729 if (match.sk)
3730 sock_put(match.sk);
3731
3732 return err;
3733}
3734
Johan Hedberg48264f02011-11-09 13:58:58 +02003735int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Johan Hedberg561aafb2012-01-04 13:31:59 +02003736 u8 addr_type, u8 *dev_class, s8 rssi,
Johan Hedberg388fc8f2012-02-23 00:38:59 +02003737 u8 cfm_name, u8 ssp, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03003738{
Johan Hedberge319d2e2012-01-15 19:51:59 +02003739 char buf[512];
3740 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02003741 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03003742
Johan Hedberg1dc06092012-01-15 21:01:23 +02003743 /* Leave 5 bytes for a potential CoD field */
3744 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Andre Guedes7d262f82012-01-10 18:20:49 -03003745 return -EINVAL;
3746
Johan Hedberg1dc06092012-01-15 21:01:23 +02003747 memset(buf, 0, sizeof(buf));
3748
Johan Hedberge319d2e2012-01-15 19:51:59 +02003749 bacpy(&ev->addr.bdaddr, bdaddr);
3750 ev->addr.type = link_to_mgmt(link_type, addr_type);
3751 ev->rssi = rssi;
Johan Hedberg9a395a82012-02-23 00:00:32 +02003752 if (cfm_name)
3753 ev->flags[0] |= MGMT_DEV_FOUND_CONFIRM_NAME;
Johan Hedberg388fc8f2012-02-23 00:38:59 +02003754 if (!ssp)
3755 ev->flags[0] |= MGMT_DEV_FOUND_LEGACY_PAIRING;
Johan Hedberge17acd42011-03-30 23:57:16 +03003756
Johan Hedberg1dc06092012-01-15 21:01:23 +02003757 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02003758 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03003759
Johan Hedberg1dc06092012-01-15 21:01:23 +02003760 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
3761 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
3762 dev_class, 3);
3763
3764 put_unaligned_le16(eir_len, &ev->eir_len);
3765
3766 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03003767
Johan Hedberge319d2e2012-01-15 19:51:59 +02003768 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03003769}
Johan Hedberga88a9652011-03-30 13:18:12 +03003770
Johan Hedbergb644ba32012-01-17 21:48:47 +02003771int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
3772 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03003773{
Johan Hedbergb644ba32012-01-17 21:48:47 +02003774 struct mgmt_ev_device_found *ev;
3775 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
3776 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03003777
Johan Hedbergb644ba32012-01-17 21:48:47 +02003778 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03003779
Johan Hedbergb644ba32012-01-17 21:48:47 +02003780 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03003781
Johan Hedbergb644ba32012-01-17 21:48:47 +02003782 bacpy(&ev->addr.bdaddr, bdaddr);
3783 ev->addr.type = link_to_mgmt(link_type, addr_type);
3784 ev->rssi = rssi;
3785
3786 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
3787 name_len);
3788
3789 put_unaligned_le16(eir_len, &ev->eir_len);
3790
Johan Hedberg053c7e02012-02-04 00:06:00 +02003791 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev,
3792 sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03003793}
Johan Hedberg314b2382011-04-27 10:29:57 -04003794
Andre Guedes7a135102011-11-09 17:14:25 -03003795int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
Johan Hedberg164a6e72011-11-01 17:06:44 +02003796{
3797 struct pending_cmd *cmd;
Johan Hedbergf808e162012-02-19 12:52:07 +02003798 u8 type;
Johan Hedberg164a6e72011-11-01 17:06:44 +02003799 int err;
3800
Andre Guedes203159d2012-02-13 15:41:01 -03003801 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3802
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003803 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003804 if (!cmd)
3805 return -ENOENT;
3806
Johan Hedbergf808e162012-02-19 12:52:07 +02003807 type = hdev->discovery.type;
3808
3809 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
3810 &type, sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02003811 mgmt_pending_remove(cmd);
3812
3813 return err;
3814}
3815
Andre Guedese6d465c2011-11-09 17:14:26 -03003816int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
3817{
3818 struct pending_cmd *cmd;
3819 int err;
3820
3821 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
3822 if (!cmd)
3823 return -ENOENT;
3824
Johan Hedbergd9306502012-02-20 23:25:18 +02003825 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
3826 &hdev->discovery.type,
3827 sizeof(hdev->discovery.type));
Johan Hedberg03811012010-12-08 00:21:06 +02003828 mgmt_pending_remove(cmd);
3829
3830 return err;
3831}
Johan Hedberg314b2382011-04-27 10:29:57 -04003832
Johan Hedberg744cf192011-11-08 20:40:14 +02003833int mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04003834{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02003835 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02003836 struct pending_cmd *cmd;
3837
Andre Guedes343fb142011-11-22 17:14:19 -03003838 BT_DBG("%s discovering %u", hdev->name, discovering);
3839
Johan Hedberg164a6e72011-11-01 17:06:44 +02003840 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003841 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003842 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003843 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003844
3845 if (cmd != NULL) {
Johan Hedbergf808e162012-02-19 12:52:07 +02003846 u8 type = hdev->discovery.type;
3847
Johan Hedbergd9306502012-02-20 23:25:18 +02003848 cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0,
Johan Hedbergf808e162012-02-19 12:52:07 +02003849 &type, sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02003850 mgmt_pending_remove(cmd);
3851 }
3852
Johan Hedbergf963e8e2012-02-20 23:30:44 +02003853 memset(&ev, 0, sizeof(ev));
3854 ev.type = hdev->discovery.type;
3855 ev.discovering = discovering;
3856
3857 return mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04003858}
Antti Julku5e762442011-08-25 16:48:02 +03003859
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003860int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003861{
3862 struct pending_cmd *cmd;
3863 struct mgmt_ev_device_blocked ev;
3864
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003865 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003866
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003867 bacpy(&ev.addr.bdaddr, bdaddr);
3868 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003869
Johan Hedberg744cf192011-11-08 20:40:14 +02003870 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
3871 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003872}
3873
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003874int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003875{
3876 struct pending_cmd *cmd;
3877 struct mgmt_ev_device_unblocked ev;
3878
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003879 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003880
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003881 bacpy(&ev.addr.bdaddr, bdaddr);
3882 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003883
Johan Hedberg744cf192011-11-08 20:40:14 +02003884 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
3885 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003886}
Marcel Holtmannd7b7e792012-02-20 21:47:49 +01003887
3888module_param(enable_hs, bool, 0644);
3889MODULE_PARM_DESC(enable_hs, "Enable High Speed support");
3890
3891module_param(enable_le, bool, 0644);
3892MODULE_PARM_DESC(enable_le, "Enable Low Energy support");