blob: 36bebfb2d8409a2093745ad632bd5d4bdfaf6375 [file] [log] [blame]
Johan Hedberg03811012010-12-08 00:21:06 +02001/*
2 BlueZ - Bluetooth protocol stack for Linux
Johan Hedbergea585ab2012-02-17 14:50:39 +02003
Johan Hedberg03811012010-12-08 00:21:06 +02004 Copyright (C) 2010 Nokia Corporation
Johan Hedbergea585ab2012-02-17 14:50:39 +02005 Copyright (C) 2011-2012 Intel Corporation
Johan Hedberg03811012010-12-08 00:21:06 +02006
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License version 2 as
9 published by the Free Software Foundation;
10
11 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
12 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
13 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
14 IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
15 CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
16 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19
20 ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
21 COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
22 SOFTWARE IS DISCLAIMED.
23*/
24
25/* Bluetooth HCI Management interface */
26
Johan Hedbergca69b792011-11-11 18:10:00 +020027#include <linux/kernel.h>
Szymon Janc72359752011-02-17 14:16:32 +010028#include <linux/uaccess.h>
Paul Gortmaker3a9a2312011-05-27 09:12:25 -040029#include <linux/module.h>
Johan Hedberg03811012010-12-08 00:21:06 +020030#include <asm/unaligned.h>
31
32#include <net/bluetooth/bluetooth.h>
33#include <net/bluetooth/hci_core.h>
34#include <net/bluetooth/mgmt.h>
Brian Gix5fe57d92011-12-21 16:12:13 -080035#include <net/bluetooth/smp.h>
Johan Hedberg03811012010-12-08 00:21:06 +020036
Marcel Holtmannd7b7e792012-02-20 21:47:49 +010037bool enable_hs;
38bool enable_le;
39
Johan Hedberg2da9c552012-02-17 14:39:28 +020040#define MGMT_VERSION 1
41#define MGMT_REVISION 0
Johan Hedberg02d98122010-12-13 21:07:04 +020042
Johan Hedberge70bb2e2012-02-13 16:59:33 +020043static const u16 mgmt_commands[] = {
44 MGMT_OP_READ_INDEX_LIST,
45 MGMT_OP_READ_INFO,
46 MGMT_OP_SET_POWERED,
47 MGMT_OP_SET_DISCOVERABLE,
48 MGMT_OP_SET_CONNECTABLE,
49 MGMT_OP_SET_FAST_CONNECTABLE,
50 MGMT_OP_SET_PAIRABLE,
51 MGMT_OP_SET_LINK_SECURITY,
52 MGMT_OP_SET_SSP,
53 MGMT_OP_SET_HS,
54 MGMT_OP_SET_LE,
55 MGMT_OP_SET_DEV_CLASS,
56 MGMT_OP_SET_LOCAL_NAME,
57 MGMT_OP_ADD_UUID,
58 MGMT_OP_REMOVE_UUID,
59 MGMT_OP_LOAD_LINK_KEYS,
60 MGMT_OP_LOAD_LONG_TERM_KEYS,
61 MGMT_OP_DISCONNECT,
62 MGMT_OP_GET_CONNECTIONS,
63 MGMT_OP_PIN_CODE_REPLY,
64 MGMT_OP_PIN_CODE_NEG_REPLY,
65 MGMT_OP_SET_IO_CAPABILITY,
66 MGMT_OP_PAIR_DEVICE,
67 MGMT_OP_CANCEL_PAIR_DEVICE,
68 MGMT_OP_UNPAIR_DEVICE,
69 MGMT_OP_USER_CONFIRM_REPLY,
70 MGMT_OP_USER_CONFIRM_NEG_REPLY,
71 MGMT_OP_USER_PASSKEY_REPLY,
72 MGMT_OP_USER_PASSKEY_NEG_REPLY,
73 MGMT_OP_READ_LOCAL_OOB_DATA,
74 MGMT_OP_ADD_REMOTE_OOB_DATA,
75 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
76 MGMT_OP_START_DISCOVERY,
77 MGMT_OP_STOP_DISCOVERY,
78 MGMT_OP_CONFIRM_NAME,
79 MGMT_OP_BLOCK_DEVICE,
80 MGMT_OP_UNBLOCK_DEVICE,
81};
82
83static const u16 mgmt_events[] = {
84 MGMT_EV_CONTROLLER_ERROR,
85 MGMT_EV_INDEX_ADDED,
86 MGMT_EV_INDEX_REMOVED,
87 MGMT_EV_NEW_SETTINGS,
88 MGMT_EV_CLASS_OF_DEV_CHANGED,
89 MGMT_EV_LOCAL_NAME_CHANGED,
90 MGMT_EV_NEW_LINK_KEY,
91 MGMT_EV_NEW_LONG_TERM_KEY,
92 MGMT_EV_DEVICE_CONNECTED,
93 MGMT_EV_DEVICE_DISCONNECTED,
94 MGMT_EV_CONNECT_FAILED,
95 MGMT_EV_PIN_CODE_REQUEST,
96 MGMT_EV_USER_CONFIRM_REQUEST,
97 MGMT_EV_USER_PASSKEY_REQUEST,
98 MGMT_EV_AUTH_FAILED,
99 MGMT_EV_DEVICE_FOUND,
100 MGMT_EV_DISCOVERING,
101 MGMT_EV_DEVICE_BLOCKED,
102 MGMT_EV_DEVICE_UNBLOCKED,
103 MGMT_EV_DEVICE_UNPAIRED,
104};
105
Andre Guedes3fd24152012-02-03 17:48:01 -0300106/*
107 * These LE scan and inquiry parameters were chosen according to LE General
108 * Discovery Procedure specification.
109 */
110#define LE_SCAN_TYPE 0x01
111#define LE_SCAN_WIN 0x12
112#define LE_SCAN_INT 0x12
113#define LE_SCAN_TIMEOUT_LE_ONLY 10240 /* TGAP(gen_disc_scan_min) */
Andre Guedes5e0452c2012-02-17 20:39:38 -0300114#define LE_SCAN_TIMEOUT_BREDR_LE 5120 /* TGAP(100)/2 */
Andre Guedes3fd24152012-02-03 17:48:01 -0300115
Andre Guedese8777522012-02-03 17:48:02 -0300116#define INQUIRY_LEN_BREDR 0x08 /* TGAP(100) */
Andre Guedes5e0452c2012-02-17 20:39:38 -0300117#define INQUIRY_LEN_BREDR_LE 0x04 /* TGAP(100)/2 */
Andre Guedes2519a1f2011-11-07 11:45:24 -0300118
Johan Hedberg7d785252011-12-15 00:47:39 +0200119#define SERVICE_CACHE_TIMEOUT (5 * 1000)
120
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200121#define hdev_is_powered(hdev) (test_bit(HCI_UP, &hdev->flags) && \
122 !test_bit(HCI_AUTO_OFF, &hdev->dev_flags))
123
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200124struct pending_cmd {
125 struct list_head list;
Johan Hedbergfc2f4b12011-11-09 13:58:56 +0200126 u16 opcode;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200127 int index;
Szymon Jancc68fb7f2011-03-22 13:12:19 +0100128 void *param;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200129 struct sock *sk;
Johan Hedberge9a416b2011-02-19 12:05:56 -0300130 void *user_data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200131};
132
Johan Hedbergca69b792011-11-11 18:10:00 +0200133/* HCI to MGMT error code conversion table */
134static u8 mgmt_status_table[] = {
135 MGMT_STATUS_SUCCESS,
136 MGMT_STATUS_UNKNOWN_COMMAND, /* Unknown Command */
137 MGMT_STATUS_NOT_CONNECTED, /* No Connection */
138 MGMT_STATUS_FAILED, /* Hardware Failure */
139 MGMT_STATUS_CONNECT_FAILED, /* Page Timeout */
140 MGMT_STATUS_AUTH_FAILED, /* Authentication Failed */
141 MGMT_STATUS_NOT_PAIRED, /* PIN or Key Missing */
142 MGMT_STATUS_NO_RESOURCES, /* Memory Full */
143 MGMT_STATUS_TIMEOUT, /* Connection Timeout */
144 MGMT_STATUS_NO_RESOURCES, /* Max Number of Connections */
145 MGMT_STATUS_NO_RESOURCES, /* Max Number of SCO Connections */
146 MGMT_STATUS_ALREADY_CONNECTED, /* ACL Connection Exists */
147 MGMT_STATUS_BUSY, /* Command Disallowed */
148 MGMT_STATUS_NO_RESOURCES, /* Rejected Limited Resources */
149 MGMT_STATUS_REJECTED, /* Rejected Security */
150 MGMT_STATUS_REJECTED, /* Rejected Personal */
151 MGMT_STATUS_TIMEOUT, /* Host Timeout */
152 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Feature */
153 MGMT_STATUS_INVALID_PARAMS, /* Invalid Parameters */
154 MGMT_STATUS_DISCONNECTED, /* OE User Ended Connection */
155 MGMT_STATUS_NO_RESOURCES, /* OE Low Resources */
156 MGMT_STATUS_DISCONNECTED, /* OE Power Off */
157 MGMT_STATUS_DISCONNECTED, /* Connection Terminated */
158 MGMT_STATUS_BUSY, /* Repeated Attempts */
159 MGMT_STATUS_REJECTED, /* Pairing Not Allowed */
160 MGMT_STATUS_FAILED, /* Unknown LMP PDU */
161 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Remote Feature */
162 MGMT_STATUS_REJECTED, /* SCO Offset Rejected */
163 MGMT_STATUS_REJECTED, /* SCO Interval Rejected */
164 MGMT_STATUS_REJECTED, /* Air Mode Rejected */
165 MGMT_STATUS_INVALID_PARAMS, /* Invalid LMP Parameters */
166 MGMT_STATUS_FAILED, /* Unspecified Error */
167 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported LMP Parameter Value */
168 MGMT_STATUS_FAILED, /* Role Change Not Allowed */
169 MGMT_STATUS_TIMEOUT, /* LMP Response Timeout */
170 MGMT_STATUS_FAILED, /* LMP Error Transaction Collision */
171 MGMT_STATUS_FAILED, /* LMP PDU Not Allowed */
172 MGMT_STATUS_REJECTED, /* Encryption Mode Not Accepted */
173 MGMT_STATUS_FAILED, /* Unit Link Key Used */
174 MGMT_STATUS_NOT_SUPPORTED, /* QoS Not Supported */
175 MGMT_STATUS_TIMEOUT, /* Instant Passed */
176 MGMT_STATUS_NOT_SUPPORTED, /* Pairing Not Supported */
177 MGMT_STATUS_FAILED, /* Transaction Collision */
178 MGMT_STATUS_INVALID_PARAMS, /* Unacceptable Parameter */
179 MGMT_STATUS_REJECTED, /* QoS Rejected */
180 MGMT_STATUS_NOT_SUPPORTED, /* Classification Not Supported */
181 MGMT_STATUS_REJECTED, /* Insufficient Security */
182 MGMT_STATUS_INVALID_PARAMS, /* Parameter Out Of Range */
183 MGMT_STATUS_BUSY, /* Role Switch Pending */
184 MGMT_STATUS_FAILED, /* Slot Violation */
185 MGMT_STATUS_FAILED, /* Role Switch Failed */
186 MGMT_STATUS_INVALID_PARAMS, /* EIR Too Large */
187 MGMT_STATUS_NOT_SUPPORTED, /* Simple Pairing Not Supported */
188 MGMT_STATUS_BUSY, /* Host Busy Pairing */
189 MGMT_STATUS_REJECTED, /* Rejected, No Suitable Channel */
190 MGMT_STATUS_BUSY, /* Controller Busy */
191 MGMT_STATUS_INVALID_PARAMS, /* Unsuitable Connection Interval */
192 MGMT_STATUS_TIMEOUT, /* Directed Advertising Timeout */
193 MGMT_STATUS_AUTH_FAILED, /* Terminated Due to MIC Failure */
194 MGMT_STATUS_CONNECT_FAILED, /* Connection Establishment Failed */
195 MGMT_STATUS_CONNECT_FAILED, /* MAC Connection Failed */
196};
197
198static u8 mgmt_status(u8 hci_status)
199{
200 if (hci_status < ARRAY_SIZE(mgmt_status_table))
201 return mgmt_status_table[hci_status];
202
203 return MGMT_STATUS_FAILED;
204}
205
Szymon Janc4e51eae2011-02-25 19:05:48 +0100206static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200207{
208 struct sk_buff *skb;
209 struct mgmt_hdr *hdr;
210 struct mgmt_ev_cmd_status *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300211 int err;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200212
Szymon Janc34eb5252011-02-28 14:10:08 +0100213 BT_DBG("sock %p, index %u, cmd %u, status %u", sk, index, cmd, status);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200214
215 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_ATOMIC);
216 if (!skb)
217 return -ENOMEM;
218
219 hdr = (void *) skb_put(skb, sizeof(*hdr));
220
221 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_STATUS);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100222 hdr->index = cpu_to_le16(index);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200223 hdr->len = cpu_to_le16(sizeof(*ev));
224
225 ev = (void *) skb_put(skb, sizeof(*ev));
226 ev->status = status;
227 put_unaligned_le16(cmd, &ev->opcode);
228
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300229 err = sock_queue_rcv_skb(sk, skb);
230 if (err < 0)
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200231 kfree_skb(skb);
232
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300233 return err;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200234}
235
Johan Hedbergaee9b212012-02-18 15:07:59 +0200236static int cmd_complete(struct sock *sk, u16 index, u16 cmd, u8 status,
237 void *rp, size_t rp_len)
Johan Hedberg02d98122010-12-13 21:07:04 +0200238{
239 struct sk_buff *skb;
240 struct mgmt_hdr *hdr;
241 struct mgmt_ev_cmd_complete *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300242 int err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200243
244 BT_DBG("sock %p", sk);
245
Johan Hedberga38528f2011-01-22 06:46:43 +0200246 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + rp_len, GFP_ATOMIC);
Johan Hedberg02d98122010-12-13 21:07:04 +0200247 if (!skb)
248 return -ENOMEM;
249
250 hdr = (void *) skb_put(skb, sizeof(*hdr));
Johan Hedberga38528f2011-01-22 06:46:43 +0200251
Johan Hedberg02d98122010-12-13 21:07:04 +0200252 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100253 hdr->index = cpu_to_le16(index);
Johan Hedberga38528f2011-01-22 06:46:43 +0200254 hdr->len = cpu_to_le16(sizeof(*ev) + rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200255
Johan Hedberga38528f2011-01-22 06:46:43 +0200256 ev = (void *) skb_put(skb, sizeof(*ev) + rp_len);
257 put_unaligned_le16(cmd, &ev->opcode);
Johan Hedbergaee9b212012-02-18 15:07:59 +0200258 ev->status = status;
Szymon Janc8020c162011-02-28 14:09:50 +0100259
260 if (rp)
261 memcpy(ev->data, rp, rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200262
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300263 err = sock_queue_rcv_skb(sk, skb);
264 if (err < 0)
Johan Hedberg02d98122010-12-13 21:07:04 +0200265 kfree_skb(skb);
266
Marcel Holtmanne5f0e152012-02-22 11:59:01 +0100267 return err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200268}
269
Johan Hedberga38528f2011-01-22 06:46:43 +0200270static int read_version(struct sock *sk)
271{
272 struct mgmt_rp_read_version rp;
273
274 BT_DBG("sock %p", sk);
275
276 rp.version = MGMT_VERSION;
277 put_unaligned_le16(MGMT_REVISION, &rp.revision);
278
Johan Hedbergaee9b212012-02-18 15:07:59 +0200279 return cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, 0, &rp,
Szymon Janc4e51eae2011-02-25 19:05:48 +0100280 sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200281}
282
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200283static int read_commands(struct sock *sk)
284{
285 struct mgmt_rp_read_commands *rp;
286 u16 num_commands = ARRAY_SIZE(mgmt_commands);
287 u16 num_events = ARRAY_SIZE(mgmt_events);
288 u16 *opcode;
289 size_t rp_size;
290 int i, err;
291
292 BT_DBG("sock %p", sk);
293
294 rp_size = sizeof(*rp) + ((num_commands + num_events) * sizeof(u16));
295
296 rp = kmalloc(rp_size, GFP_KERNEL);
297 if (!rp)
298 return -ENOMEM;
299
300 put_unaligned_le16(num_commands, &rp->num_commands);
301 put_unaligned_le16(num_events, &rp->num_events);
302
303 for (i = 0, opcode = rp->opcodes; i < num_commands; i++, opcode++)
304 put_unaligned_le16(mgmt_commands[i], opcode);
305
306 for (i = 0; i < num_events; i++, opcode++)
307 put_unaligned_le16(mgmt_events[i], opcode);
308
Johan Hedbergaee9b212012-02-18 15:07:59 +0200309 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_COMMANDS, 0, rp,
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200310 rp_size);
311 kfree(rp);
312
313 return err;
314}
315
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200316static int read_index_list(struct sock *sk)
317{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200318 struct mgmt_rp_read_index_list *rp;
319 struct list_head *p;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200320 struct hci_dev *d;
Johan Hedberga38528f2011-01-22 06:46:43 +0200321 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200322 u16 count;
Johan Hedberga38528f2011-01-22 06:46:43 +0200323 int i, err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200324
325 BT_DBG("sock %p", sk);
326
327 read_lock(&hci_dev_list_lock);
328
329 count = 0;
330 list_for_each(p, &hci_dev_list) {
331 count++;
332 }
333
Johan Hedberga38528f2011-01-22 06:46:43 +0200334 rp_len = sizeof(*rp) + (2 * count);
335 rp = kmalloc(rp_len, GFP_ATOMIC);
336 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100337 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200338 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100339 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200340
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200341 put_unaligned_le16(count, &rp->num_controllers);
342
343 i = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200344 list_for_each_entry(d, &hci_dev_list, list) {
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200345 if (test_bit(HCI_SETUP, &d->dev_flags))
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200346 continue;
347
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200348 put_unaligned_le16(d->id, &rp->index[i++]);
349 BT_DBG("Added hci%u", d->id);
350 }
351
352 read_unlock(&hci_dev_list_lock);
353
Johan Hedbergaee9b212012-02-18 15:07:59 +0200354 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST, 0, rp,
Szymon Janc4e51eae2011-02-25 19:05:48 +0100355 rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200356
Johan Hedberga38528f2011-01-22 06:46:43 +0200357 kfree(rp);
358
359 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200360}
361
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200362static u32 get_supported_settings(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +0200363{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200364 u32 settings = 0;
Johan Hedberg03811012010-12-08 00:21:06 +0200365
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200366 settings |= MGMT_SETTING_POWERED;
367 settings |= MGMT_SETTING_CONNECTABLE;
368 settings |= MGMT_SETTING_FAST_CONNECTABLE;
369 settings |= MGMT_SETTING_DISCOVERABLE;
370 settings |= MGMT_SETTING_PAIRABLE;
Johan Hedberg03811012010-12-08 00:21:06 +0200371
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200372 if (hdev->features[6] & LMP_SIMPLE_PAIR)
373 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200374
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200375 if (!(hdev->features[4] & LMP_NO_BREDR)) {
376 settings |= MGMT_SETTING_BREDR;
377 settings |= MGMT_SETTING_LINK_SECURITY;
378 }
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200379
Marcel Holtmannd7b7e792012-02-20 21:47:49 +0100380 if (enable_hs)
381 settings |= MGMT_SETTING_HS;
382
383 if (enable_le) {
384 if (hdev->features[4] & LMP_LE)
385 settings |= MGMT_SETTING_LE;
386 }
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200387
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200388 return settings;
389}
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200390
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200391static u32 get_current_settings(struct hci_dev *hdev)
392{
393 u32 settings = 0;
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200394
Johan Hedbergf1f0eb02012-02-21 17:15:41 +0200395 if (hdev_is_powered(hdev))
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100396 settings |= MGMT_SETTING_POWERED;
397
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200398 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200399 settings |= MGMT_SETTING_CONNECTABLE;
400
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200401 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200402 settings |= MGMT_SETTING_DISCOVERABLE;
403
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200404 if (test_bit(HCI_PAIRABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200405 settings |= MGMT_SETTING_PAIRABLE;
406
407 if (!(hdev->features[4] & LMP_NO_BREDR))
408 settings |= MGMT_SETTING_BREDR;
409
Johan Hedberg06199cf2012-02-22 16:37:11 +0200410 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200411 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200412
Johan Hedberg47990ea2012-02-22 11:58:37 +0200413 if (test_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200414 settings |= MGMT_SETTING_LINK_SECURITY;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200415
Johan Hedberg84bde9d6c2012-01-25 14:21:06 +0200416 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200417 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200418
Johan Hedberg6d80dfd2012-02-20 23:50:38 +0200419 if (test_bit(HCI_HS_ENABLED, &hdev->dev_flags))
420 settings |= MGMT_SETTING_HS;
421
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200422 return settings;
Johan Hedbergc542a062011-01-26 13:11:03 +0200423}
424
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300425#define PNP_INFO_SVCLASS_ID 0x1200
426
427static u8 bluetooth_base_uuid[] = {
428 0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80,
429 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
430};
431
432static u16 get_uuid16(u8 *uuid128)
433{
434 u32 val;
435 int i;
436
437 for (i = 0; i < 12; i++) {
438 if (bluetooth_base_uuid[i] != uuid128[i])
439 return 0;
440 }
441
442 memcpy(&val, &uuid128[12], 4);
443
444 val = le32_to_cpu(val);
445 if (val > 0xffff)
446 return 0;
447
448 return (u16) val;
449}
450
451static void create_eir(struct hci_dev *hdev, u8 *data)
452{
453 u8 *ptr = data;
454 u16 eir_len = 0;
455 u16 uuid16_list[HCI_MAX_EIR_LENGTH / sizeof(u16)];
456 int i, truncated = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200457 struct bt_uuid *uuid;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300458 size_t name_len;
459
460 name_len = strlen(hdev->dev_name);
461
462 if (name_len > 0) {
463 /* EIR Data type */
464 if (name_len > 48) {
465 name_len = 48;
466 ptr[1] = EIR_NAME_SHORT;
467 } else
468 ptr[1] = EIR_NAME_COMPLETE;
469
470 /* EIR Data length */
471 ptr[0] = name_len + 1;
472
473 memcpy(ptr + 2, hdev->dev_name, name_len);
474
475 eir_len += (name_len + 2);
476 ptr += (name_len + 2);
477 }
478
479 memset(uuid16_list, 0, sizeof(uuid16_list));
480
481 /* Group all UUID16 types */
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200482 list_for_each_entry(uuid, &hdev->uuids, list) {
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300483 u16 uuid16;
484
485 uuid16 = get_uuid16(uuid->uuid);
486 if (uuid16 == 0)
487 return;
488
489 if (uuid16 < 0x1100)
490 continue;
491
492 if (uuid16 == PNP_INFO_SVCLASS_ID)
493 continue;
494
495 /* Stop if not enough space to put next UUID */
496 if (eir_len + 2 + sizeof(u16) > HCI_MAX_EIR_LENGTH) {
497 truncated = 1;
498 break;
499 }
500
501 /* Check for duplicates */
502 for (i = 0; uuid16_list[i] != 0; i++)
503 if (uuid16_list[i] == uuid16)
504 break;
505
506 if (uuid16_list[i] == 0) {
507 uuid16_list[i] = uuid16;
508 eir_len += sizeof(u16);
509 }
510 }
511
512 if (uuid16_list[0] != 0) {
513 u8 *length = ptr;
514
515 /* EIR Data type */
516 ptr[1] = truncated ? EIR_UUID16_SOME : EIR_UUID16_ALL;
517
518 ptr += 2;
519 eir_len += 2;
520
521 for (i = 0; uuid16_list[i] != 0; i++) {
522 *ptr++ = (uuid16_list[i] & 0x00ff);
523 *ptr++ = (uuid16_list[i] & 0xff00) >> 8;
524 }
525
526 /* EIR Data length */
527 *length = (i * sizeof(u16)) + 1;
528 }
529}
530
531static int update_eir(struct hci_dev *hdev)
532{
533 struct hci_cp_write_eir cp;
534
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200535 if (!test_bit(HCI_UP, &hdev->flags))
536 return 0;
537
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300538 if (!(hdev->features[6] & LMP_EXT_INQ))
539 return 0;
540
Johan Hedberg84bde9d6c2012-01-25 14:21:06 +0200541 if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300542 return 0;
543
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200544 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300545 return 0;
546
547 memset(&cp, 0, sizeof(cp));
548
549 create_eir(hdev, cp.data);
550
551 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
552 return 0;
553
554 memcpy(hdev->eir, cp.data, sizeof(cp.data));
555
556 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
557}
558
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200559static u8 get_service_classes(struct hci_dev *hdev)
560{
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300561 struct bt_uuid *uuid;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200562 u8 val = 0;
563
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300564 list_for_each_entry(uuid, &hdev->uuids, list)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200565 val |= uuid->svc_hint;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200566
567 return val;
568}
569
570static int update_class(struct hci_dev *hdev)
571{
572 u8 cod[3];
573
574 BT_DBG("%s", hdev->name);
575
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200576 if (!test_bit(HCI_UP, &hdev->flags))
577 return 0;
578
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200579 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200580 return 0;
581
582 cod[0] = hdev->minor_class;
583 cod[1] = hdev->major_class;
584 cod[2] = get_service_classes(hdev);
585
586 if (memcmp(cod, hdev->dev_class, 3) == 0)
587 return 0;
588
589 return hci_send_cmd(hdev, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
590}
591
Johan Hedberg7d785252011-12-15 00:47:39 +0200592static void service_cache_off(struct work_struct *work)
593{
594 struct hci_dev *hdev = container_of(work, struct hci_dev,
595 service_cache.work);
596
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200597 if (!test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200598 return;
599
600 hci_dev_lock(hdev);
601
602 update_eir(hdev);
603 update_class(hdev);
604
605 hci_dev_unlock(hdev);
606}
607
608static void mgmt_init_hdev(struct hci_dev *hdev)
609{
Johan Hedberg0cbf4ed2012-02-21 17:25:22 +0200610 if (!test_and_set_bit(HCI_MGMT, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +0200611 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
612
Johan Hedberg0cbf4ed2012-02-21 17:25:22 +0200613 /* Non-mgmt controlled devices get this bit set
614 * implicitly so that pairing works for them, however
615 * for mgmt we require user-space to explicitly enable
616 * it
617 */
618 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
619 }
620
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200621 if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200622 schedule_delayed_work(&hdev->service_cache,
623 msecs_to_jiffies(SERVICE_CACHE_TIMEOUT));
624}
625
Johan Hedberg03811012010-12-08 00:21:06 +0200626static int read_controller_info(struct sock *sk, u16 index)
627{
628 struct mgmt_rp_read_info rp;
629 struct hci_dev *hdev;
630
631 BT_DBG("sock %p hci%u", sk, index);
632
633 hdev = hci_dev_get(index);
634 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200635 return cmd_status(sk, index, MGMT_OP_READ_INFO,
636 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200637
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300638 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200639
Johan Hedberg7d785252011-12-15 00:47:39 +0200640 if (test_and_clear_bit(HCI_PI_MGMT_INIT, &hci_pi(sk)->flags))
641 mgmt_init_hdev(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200642
643 memset(&rp, 0, sizeof(rp));
644
Johan Hedberg03811012010-12-08 00:21:06 +0200645 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200646
647 rp.version = hdev->hci_ver;
648
Johan Hedberg03811012010-12-08 00:21:06 +0200649 put_unaligned_le16(hdev->manufacturer, &rp.manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200650
651 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
652 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
653
654 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedberg03811012010-12-08 00:21:06 +0200655
656 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
Johan Hedberg27fcc362012-02-22 21:46:22 +0200657 memcpy(rp.short_name, hdev->short_name, sizeof(hdev->short_name));
Johan Hedberg03811012010-12-08 00:21:06 +0200658
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300659 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200660 hci_dev_put(hdev);
661
Johan Hedbergaee9b212012-02-18 15:07:59 +0200662 return cmd_complete(sk, index, MGMT_OP_READ_INFO, 0, &rp, sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +0200663}
664
665static void mgmt_pending_free(struct pending_cmd *cmd)
666{
667 sock_put(cmd->sk);
668 kfree(cmd->param);
669 kfree(cmd);
670}
671
672static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
673 struct hci_dev *hdev,
674 void *data, u16 len)
675{
676 struct pending_cmd *cmd;
677
678 cmd = kmalloc(sizeof(*cmd), GFP_ATOMIC);
679 if (!cmd)
680 return NULL;
681
682 cmd->opcode = opcode;
683 cmd->index = hdev->id;
684
685 cmd->param = kmalloc(len, GFP_ATOMIC);
686 if (!cmd->param) {
687 kfree(cmd);
688 return NULL;
689 }
690
691 if (data)
692 memcpy(cmd->param, data, len);
693
694 cmd->sk = sk;
695 sock_hold(sk);
696
697 list_add(&cmd->list, &hdev->mgmt_pending);
698
699 return cmd;
700}
701
702static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
703 void (*cb)(struct pending_cmd *cmd, void *data),
704 void *data)
705{
706 struct list_head *p, *n;
707
708 list_for_each_safe(p, n, &hdev->mgmt_pending) {
709 struct pending_cmd *cmd;
710
711 cmd = list_entry(p, struct pending_cmd, list);
712
713 if (opcode > 0 && cmd->opcode != opcode)
714 continue;
715
716 cb(cmd, data);
717 }
718}
719
720static struct pending_cmd *mgmt_pending_find(u16 opcode, struct hci_dev *hdev)
721{
722 struct pending_cmd *cmd;
723
724 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
725 if (cmd->opcode == opcode)
726 return cmd;
727 }
728
729 return NULL;
730}
731
732static void mgmt_pending_remove(struct pending_cmd *cmd)
733{
734 list_del(&cmd->list);
735 mgmt_pending_free(cmd);
736}
737
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200738static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +0200739{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200740 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +0200741
Johan Hedbergaee9b212012-02-18 15:07:59 +0200742 return cmd_complete(sk, hdev->id, opcode, 0, &settings,
743 sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +0200744}
745
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300746static int set_powered(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200747{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300748 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200749 struct hci_dev *hdev;
750 struct pending_cmd *cmd;
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200751 int err;
Johan Hedberg03811012010-12-08 00:21:06 +0200752
Johan Hedberg03811012010-12-08 00:21:06 +0200753 BT_DBG("request for hci%u", index);
754
755 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200756 return cmd_status(sk, index, MGMT_OP_SET_POWERED,
757 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200758
759 hdev = hci_dev_get(index);
760 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200761 return cmd_status(sk, index, MGMT_OP_SET_POWERED,
762 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200763
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300764 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200765
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100766 if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) {
767 cancel_delayed_work(&hdev->power_off);
768
769 if (cp->val) {
770 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
771 mgmt_powered(hdev, 1);
772 goto failed;
773 }
774 }
775
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200776 if (!!cp->val == hdev_is_powered(hdev)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200777 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200778 goto failed;
779 }
780
781 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200782 err = cmd_status(sk, index, MGMT_OP_SET_POWERED,
783 MGMT_STATUS_BUSY);
Johan Hedberg03811012010-12-08 00:21:06 +0200784 goto failed;
785 }
786
787 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
788 if (!cmd) {
789 err = -ENOMEM;
790 goto failed;
791 }
792
793 if (cp->val)
Gustavo F. Padovan7f971042011-12-18 12:40:32 -0200794 schedule_work(&hdev->power_on);
Johan Hedberg03811012010-12-08 00:21:06 +0200795 else
Gustavo F. Padovan80b7ab32011-12-17 14:52:27 -0200796 schedule_work(&hdev->power_off.work);
Johan Hedberg03811012010-12-08 00:21:06 +0200797
798 err = 0;
799
800failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300801 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200802 hci_dev_put(hdev);
803 return err;
804}
805
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200806static int mgmt_event(u16 event, struct hci_dev *hdev, void *data,
807 u16 data_len, struct sock *skip_sk)
808{
809 struct sk_buff *skb;
810 struct mgmt_hdr *hdr;
811
812 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_ATOMIC);
813 if (!skb)
814 return -ENOMEM;
815
816 hdr = (void *) skb_put(skb, sizeof(*hdr));
817 hdr->opcode = cpu_to_le16(event);
818 if (hdev)
819 hdr->index = cpu_to_le16(hdev->id);
820 else
821 hdr->index = cpu_to_le16(MGMT_INDEX_NONE);
822 hdr->len = cpu_to_le16(data_len);
823
824 if (data)
825 memcpy(skb_put(skb, data_len), data, data_len);
826
Marcel Holtmann97e0bde2012-02-22 13:49:28 +0100827 /* Time stamp */
828 __net_timestamp(skb);
829
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200830 hci_send_to_control(skb, skip_sk);
831 kfree_skb(skb);
832
833 return 0;
834}
835
836static int new_settings(struct hci_dev *hdev, struct sock *skip)
837{
838 __le32 ev;
839
840 ev = cpu_to_le32(get_current_settings(hdev));
841
842 return mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), skip);
843}
844
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300845static int set_discoverable(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200846{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300847 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberge41d8b42010-12-13 21:07:03 +0200848 struct hci_dev *hdev;
Johan Hedberg03811012010-12-08 00:21:06 +0200849 struct pending_cmd *cmd;
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200850 u16 timeout;
Johan Hedberg03811012010-12-08 00:21:06 +0200851 u8 scan;
852 int err;
853
Johan Hedberg03811012010-12-08 00:21:06 +0200854 BT_DBG("request for hci%u", index);
855
856 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200857 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
858 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200859
Marcel Holtmann24c54a92012-02-22 18:06:34 +0100860 timeout = get_unaligned_le16(&cp->timeout);
861 if (!cp->val && timeout > 0)
862 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
863 MGMT_STATUS_INVALID_PARAMS);
864
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200865 hdev = hci_dev_get(index);
866 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200867 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
868 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200869
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300870 hci_dev_lock(hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200871
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200872 if (!hdev_is_powered(hdev) && timeout > 0) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200873 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
874 MGMT_STATUS_NOT_POWERED);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200875 goto failed;
876 }
877
878 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
879 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200880 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
881 MGMT_STATUS_BUSY);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200882 goto failed;
883 }
884
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200885 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) {
886 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
887 MGMT_STATUS_REJECTED);
888 goto failed;
889 }
890
891 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200892 bool changed = false;
893
894 if (!!cp->val != test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
895 change_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
896 changed = true;
897 }
898
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200899 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200900 if (err < 0)
901 goto failed;
902
903 if (changed)
904 err = new_settings(hdev, sk);
905
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200906 goto failed;
907 }
908
909 if (!!cp->val == test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
Marcel Holtmann955638e2012-02-22 18:21:00 +0100910 if (hdev->discov_timeout > 0) {
911 cancel_delayed_work(&hdev->discov_off);
912 hdev->discov_timeout = 0;
913 }
914
915 if (cp->val && timeout > 0) {
916 hdev->discov_timeout = timeout;
917 queue_delayed_work(hdev->workqueue, &hdev->discov_off,
918 msecs_to_jiffies(hdev->discov_timeout * 1000));
919 }
920
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200921 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200922 goto failed;
923 }
924
925 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
926 if (!cmd) {
927 err = -ENOMEM;
928 goto failed;
929 }
930
931 scan = SCAN_PAGE;
932
933 if (cp->val)
934 scan |= SCAN_INQUIRY;
935 else
936 cancel_delayed_work(&hdev->discov_off);
937
938 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
939 if (err < 0)
940 mgmt_pending_remove(cmd);
941
Johan Hedberg03811012010-12-08 00:21:06 +0200942 if (cp->val)
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200943 hdev->discov_timeout = timeout;
Johan Hedberg03811012010-12-08 00:21:06 +0200944
945failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300946 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200947 hci_dev_put(hdev);
948
949 return err;
950}
951
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300952static int set_connectable(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200953{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300954 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200955 struct hci_dev *hdev;
956 struct pending_cmd *cmd;
957 u8 scan;
958 int err;
959
Johan Hedberge41d8b42010-12-13 21:07:03 +0200960 BT_DBG("request for hci%u", index);
961
Johan Hedberg03811012010-12-08 00:21:06 +0200962 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200963 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
964 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200965
966 hdev = hci_dev_get(index);
967 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200968 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
969 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200970
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300971 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200972
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200973 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200974 bool changed = false;
975
976 if (!!cp->val != test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
977 changed = true;
978
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +0200979 if (cp->val) {
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200980 set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +0200981 } else {
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200982 clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
983 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
984 }
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200985
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200986 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200987 if (err < 0)
988 goto failed;
989
990 if (changed)
991 err = new_settings(hdev, sk);
992
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200993 goto failed;
994 }
995
996 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
997 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200998 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
999 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001000 goto failed;
1001 }
1002
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001003 if (!!cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001004 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001005 goto failed;
1006 }
1007
1008 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
1009 if (!cmd) {
1010 err = -ENOMEM;
1011 goto failed;
1012 }
1013
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001014 if (cp->val) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001015 scan = SCAN_PAGE;
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001016 } else {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001017 scan = 0;
1018
Johan Hedbergdf2c6c52012-02-21 19:15:49 +02001019 if (test_bit(HCI_ISCAN, &hdev->flags) &&
1020 hdev->discov_timeout > 0)
1021 cancel_delayed_work(&hdev->discov_off);
1022 }
1023
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001024 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1025 if (err < 0)
1026 mgmt_pending_remove(cmd);
1027
1028failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001029 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001030 hci_dev_put(hdev);
1031
1032 return err;
1033}
1034
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001035static int set_pairable(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001036{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001037 struct mgmt_mode *cp = data;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001038 struct hci_dev *hdev;
1039 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001040
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001041 BT_DBG("request for hci%u", index);
1042
1043 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001044 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE,
1045 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001046
1047 hdev = hci_dev_get(index);
1048 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001049 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE,
1050 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001051
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001052 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001053
1054 if (cp->val)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001055 set_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001056 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001057 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001058
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001059 err = send_settings_rsp(sk, MGMT_OP_SET_PAIRABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001060 if (err < 0)
1061 goto failed;
1062
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001063 err = new_settings(hdev, sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001064
1065failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001066 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001067 hci_dev_put(hdev);
1068
1069 return err;
1070}
Johan Hedberg72a734e2010-12-30 00:38:22 +02001071
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001072static int set_link_security(struct sock *sk, u16 index, void *data, u16 len)
1073{
1074 struct mgmt_mode *cp = data;
1075 struct pending_cmd *cmd;
1076 struct hci_dev *hdev;
1077 uint8_t val;
1078 int err;
1079
1080 BT_DBG("request for hci%u", index);
1081
1082 if (len != sizeof(*cp))
1083 return cmd_status(sk, index, MGMT_OP_SET_LINK_SECURITY,
1084 MGMT_STATUS_INVALID_PARAMS);
1085
1086 hdev = hci_dev_get(index);
1087 if (!hdev)
1088 return cmd_status(sk, index, MGMT_OP_SET_LINK_SECURITY,
1089 MGMT_STATUS_INVALID_PARAMS);
1090
1091 hci_dev_lock(hdev);
1092
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001093 if (!hdev_is_powered(hdev)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001094 bool changed = false;
1095
1096 if (!!cp->val != test_bit(HCI_LINK_SECURITY,
1097 &hdev->dev_flags)) {
1098 change_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
1099 changed = true;
1100 }
1101
1102 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1103 if (err < 0)
1104 goto failed;
1105
1106 if (changed)
1107 err = new_settings(hdev, sk);
1108
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001109 goto failed;
1110 }
1111
1112 if (mgmt_pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
1113 err = cmd_status(sk, index, MGMT_OP_SET_LINK_SECURITY,
1114 MGMT_STATUS_BUSY);
1115 goto failed;
1116 }
1117
1118 val = !!cp->val;
1119
1120 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1121 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1122 goto failed;
1123 }
1124
1125 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1126 if (!cmd) {
1127 err = -ENOMEM;
1128 goto failed;
1129 }
1130
1131 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1132 if (err < 0) {
1133 mgmt_pending_remove(cmd);
1134 goto failed;
1135 }
1136
1137failed:
1138 hci_dev_unlock(hdev);
1139 hci_dev_put(hdev);
1140
1141 return err;
1142}
1143
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001144static int set_ssp(struct sock *sk, u16 index, void *data, u16 len)
1145{
1146 struct mgmt_mode *cp = data;
1147 struct pending_cmd *cmd;
1148 struct hci_dev *hdev;
1149 uint8_t val;
1150 int err;
1151
1152 BT_DBG("request for hci%u", index);
1153
1154 if (len != sizeof(*cp))
1155 return cmd_status(sk, index, MGMT_OP_SET_SSP,
1156 MGMT_STATUS_INVALID_PARAMS);
1157
1158 hdev = hci_dev_get(index);
1159 if (!hdev)
1160 return cmd_status(sk, index, MGMT_OP_SET_SSP,
1161 MGMT_STATUS_INVALID_PARAMS);
1162
1163 hci_dev_lock(hdev);
1164
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001165 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
1166 err = cmd_status(sk, index, MGMT_OP_SET_SSP,
1167 MGMT_STATUS_NOT_SUPPORTED);
1168 goto failed;
1169 }
1170
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001171 val = !!cp->val;
1172
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001173 if (!hdev_is_powered(hdev)) {
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001174 bool changed = false;
1175
1176 if (val != test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) {
1177 change_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
1178 changed = true;
1179 }
1180
1181 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1182 if (err < 0)
1183 goto failed;
1184
1185 if (changed)
1186 err = new_settings(hdev, sk);
1187
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001188 goto failed;
1189 }
1190
1191 if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev)) {
1192 err = cmd_status(sk, index, MGMT_OP_SET_SSP, MGMT_STATUS_BUSY);
1193 goto failed;
1194 }
1195
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001196 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) == val) {
1197 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1198 goto failed;
1199 }
1200
1201 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1202 if (!cmd) {
1203 err = -ENOMEM;
1204 goto failed;
1205 }
1206
1207 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, sizeof(val), &val);
1208 if (err < 0) {
1209 mgmt_pending_remove(cmd);
1210 goto failed;
1211 }
1212
1213failed:
1214 hci_dev_unlock(hdev);
1215 hci_dev_put(hdev);
1216
1217 return err;
1218}
1219
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001220static int set_hs(struct sock *sk, u16 index, void *data, u16 len)
1221{
1222 struct mgmt_mode *cp = data;
1223 struct hci_dev *hdev;
1224 int err;
1225
1226 BT_DBG("request for hci%u", index);
1227
1228 if (len != sizeof(*cp))
1229 return cmd_status(sk, index, MGMT_OP_SET_HS,
1230 MGMT_STATUS_INVALID_PARAMS);
1231
1232 hdev = hci_dev_get(index);
1233 if (!hdev)
1234 return cmd_status(sk, index, MGMT_OP_SET_HS,
1235 MGMT_STATUS_INVALID_PARAMS);
1236
1237 if (!enable_hs) {
1238 err = cmd_status(sk, index, MGMT_OP_SET_HS,
1239 MGMT_STATUS_NOT_SUPPORTED);
1240 goto failed;
1241 }
1242
1243 if (cp->val)
1244 set_bit(HCI_HS_ENABLED, &hdev->dev_flags);
1245 else
1246 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
1247
1248 err = send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
1249
1250failed:
1251 hci_dev_put(hdev);
1252 return err;
1253}
1254
Johan Hedberg06199cf2012-02-22 16:37:11 +02001255static int set_le(struct sock *sk, u16 index, void *data, u16 len)
1256{
1257 struct mgmt_mode *cp = data;
1258 struct hci_cp_write_le_host_supported hci_cp;
1259 struct pending_cmd *cmd;
1260 struct hci_dev *hdev;
1261 int err;
1262 u8 val;
1263
1264 BT_DBG("request for hci%u", index);
1265
1266 if (len != sizeof(*cp))
1267 return cmd_status(sk, index, MGMT_OP_SET_LE,
1268 MGMT_STATUS_INVALID_PARAMS);
1269
1270 hdev = hci_dev_get(index);
1271 if (!hdev)
1272 return cmd_status(sk, index, MGMT_OP_SET_LE,
1273 MGMT_STATUS_INVALID_PARAMS);
1274
1275 if (!enable_le || !(hdev->features[4] & LMP_LE)) {
1276 err = cmd_status(sk, index, MGMT_OP_SET_LE,
1277 MGMT_STATUS_NOT_SUPPORTED);
1278 goto failed;
1279 }
1280
1281 val = !!cp->val;
1282
1283 if (!hdev_is_powered(hdev)) {
1284 bool changed = false;
1285
1286 if (val != test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
1287 change_bit(HCI_LE_ENABLED, &hdev->dev_flags);
1288 changed = true;
1289 }
1290
1291 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1292 if (err < 0)
1293 goto failed;
1294
1295 if (changed)
1296 err = new_settings(hdev, sk);
1297
1298 goto failed;
1299 }
1300
1301 if (mgmt_pending_find(MGMT_OP_SET_LE, hdev)) {
1302 err = cmd_status(sk, index, MGMT_OP_SET_LE, MGMT_STATUS_BUSY);
1303 goto failed;
1304 }
1305
1306 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
1307 if (!cmd) {
1308 err = -ENOMEM;
1309 goto failed;
1310 }
1311
1312 memset(&hci_cp, 0, sizeof(hci_cp));
1313
1314 if (val) {
1315 hci_cp.le = val;
1316 hci_cp.simul = !!(hdev->features[6] & LMP_SIMUL_LE_BR);
1317 }
1318
1319 err = hci_send_cmd(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED,
1320 sizeof(hci_cp), &hci_cp);
1321 if (err < 0) {
1322 mgmt_pending_remove(cmd);
1323 goto failed;
1324 }
1325
1326failed:
1327 hci_dev_put(hdev);
1328 return err;
1329}
1330
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001331static int add_uuid(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001332{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001333 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001334 struct hci_dev *hdev;
1335 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001336 int err;
1337
Szymon Janc4e51eae2011-02-25 19:05:48 +01001338 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001339
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001340 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001341 return cmd_status(sk, index, MGMT_OP_ADD_UUID,
1342 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001343
Szymon Janc4e51eae2011-02-25 19:05:48 +01001344 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001345 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001346 return cmd_status(sk, index, MGMT_OP_ADD_UUID,
1347 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001348
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001349 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001350
1351 uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC);
1352 if (!uuid) {
1353 err = -ENOMEM;
1354 goto failed;
1355 }
1356
1357 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001358 uuid->svc_hint = cp->svc_hint;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001359
1360 list_add(&uuid->list, &hdev->uuids);
1361
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001362 err = update_class(hdev);
1363 if (err < 0)
1364 goto failed;
1365
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001366 err = update_eir(hdev);
1367 if (err < 0)
1368 goto failed;
1369
Johan Hedbergaee9b212012-02-18 15:07:59 +02001370 err = cmd_complete(sk, index, MGMT_OP_ADD_UUID, 0, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001371
1372failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001373 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001374 hci_dev_put(hdev);
1375
1376 return err;
1377}
1378
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001379static int remove_uuid(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001380{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001381 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001382 struct list_head *p, *n;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001383 struct hci_dev *hdev;
1384 u8 bt_uuid_any[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001385 int err, found;
1386
Szymon Janc4e51eae2011-02-25 19:05:48 +01001387 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001388
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001389 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001390 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
1391 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001392
Szymon Janc4e51eae2011-02-25 19:05:48 +01001393 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001394 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001395 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
1396 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001397
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001398 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001399
1400 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
1401 err = hci_uuids_clear(hdev);
1402 goto unlock;
1403 }
1404
1405 found = 0;
1406
1407 list_for_each_safe(p, n, &hdev->uuids) {
1408 struct bt_uuid *match = list_entry(p, struct bt_uuid, list);
1409
1410 if (memcmp(match->uuid, cp->uuid, 16) != 0)
1411 continue;
1412
1413 list_del(&match->list);
1414 found++;
1415 }
1416
1417 if (found == 0) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001418 err = cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
1419 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001420 goto unlock;
1421 }
1422
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001423 err = update_class(hdev);
1424 if (err < 0)
1425 goto unlock;
1426
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001427 err = update_eir(hdev);
1428 if (err < 0)
1429 goto unlock;
1430
Johan Hedbergaee9b212012-02-18 15:07:59 +02001431 err = cmd_complete(sk, index, MGMT_OP_REMOVE_UUID, 0, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001432
1433unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001434 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001435 hci_dev_put(hdev);
1436
1437 return err;
1438}
1439
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001440static int set_dev_class(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001441{
1442 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001443 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001444 int err;
1445
Szymon Janc4e51eae2011-02-25 19:05:48 +01001446 BT_DBG("request for hci%u", index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001447
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001448 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001449 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS,
1450 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001451
Szymon Janc4e51eae2011-02-25 19:05:48 +01001452 hdev = hci_dev_get(index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001453 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001454 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS,
1455 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001456
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001457 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001458
1459 hdev->major_class = cp->major;
1460 hdev->minor_class = cp->minor;
1461
Johan Hedberg932f5ff2012-02-22 22:11:32 +02001462 if (!hdev_is_powered(hdev)) {
1463 err = cmd_complete(sk, index, MGMT_OP_SET_DEV_CLASS, 0,
1464 hdev->dev_class, 3);
1465 goto unlock;
1466 }
1467
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001468 if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02001469 hci_dev_unlock(hdev);
1470 cancel_delayed_work_sync(&hdev->service_cache);
1471 hci_dev_lock(hdev);
Johan Hedberg14c0b602011-12-15 00:47:37 +02001472 update_eir(hdev);
Johan Hedberg7d785252011-12-15 00:47:39 +02001473 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02001474
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001475 err = update_class(hdev);
1476
1477 if (err == 0)
Johan Hedbergaee9b212012-02-18 15:07:59 +02001478 err = cmd_complete(sk, index, MGMT_OP_SET_DEV_CLASS, 0,
Johan Hedberg8ec37032012-02-22 22:02:50 +02001479 hdev->dev_class, 3);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001480
Johan Hedbergb5235a62012-02-21 14:32:24 +02001481unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001482 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001483 hci_dev_put(hdev);
1484
1485 return err;
1486}
1487
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001488static int load_link_keys(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001489{
1490 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001491 struct mgmt_cp_load_link_keys *cp = data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001492 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001493 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001494
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001495 if (len < sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001496 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1497 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001498
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001499 key_count = get_unaligned_le16(&cp->key_count);
1500
Johan Hedberg86742e12011-11-07 23:13:38 +02001501 expected_len = sizeof(*cp) + key_count *
1502 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001503 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001504 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001505 len, expected_len);
Johan Hedbergca69b792011-11-11 18:10:00 +02001506 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1507 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001508 }
1509
Szymon Janc4e51eae2011-02-25 19:05:48 +01001510 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001511 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001512 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1513 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001514
Szymon Janc4e51eae2011-02-25 19:05:48 +01001515 BT_DBG("hci%u debug_keys %u key_count %u", index, cp->debug_keys,
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001516 key_count);
1517
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001518 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001519
1520 hci_link_keys_clear(hdev);
1521
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001522 set_bit(HCI_LINK_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001523
1524 if (cp->debug_keys)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001525 set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001526 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001527 clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001528
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001529 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001530 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001531
Johan Hedbergd753fdc2012-02-17 14:06:34 +02001532 hci_add_link_key(hdev, NULL, 0, &key->addr.bdaddr, key->val,
1533 key->type, key->pin_len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001534 }
1535
Johan Hedbergaee9b212012-02-18 15:07:59 +02001536 cmd_complete(sk, index, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02001537
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001538 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001539 hci_dev_put(hdev);
1540
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001541 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001542}
1543
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001544static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
1545 u8 addr_type, struct sock *skip_sk)
1546{
1547 struct mgmt_ev_device_unpaired ev;
1548
1549 bacpy(&ev.addr.bdaddr, bdaddr);
1550 ev.addr.type = addr_type;
1551
1552 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
1553 skip_sk);
1554}
1555
Johan Hedberg124f6e32012-02-09 13:50:12 +02001556static int unpair_device(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001557{
1558 struct hci_dev *hdev;
Johan Hedberg124f6e32012-02-09 13:50:12 +02001559 struct mgmt_cp_unpair_device *cp = data;
1560 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001561 struct hci_cp_disconnect dc;
1562 struct pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001563 struct hci_conn *conn;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001564 int err;
1565
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001566 if (len != sizeof(*cp))
Johan Hedberg124f6e32012-02-09 13:50:12 +02001567 return cmd_status(sk, index, MGMT_OP_UNPAIR_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02001568 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001569
Szymon Janc4e51eae2011-02-25 19:05:48 +01001570 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001571 if (!hdev)
Johan Hedberg124f6e32012-02-09 13:50:12 +02001572 return cmd_status(sk, index, MGMT_OP_UNPAIR_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02001573 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001574
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001575 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001576
Johan Hedberga8a1d192011-11-10 15:54:38 +02001577 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02001578 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1579 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001580
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001581 if (!hdev_is_powered(hdev)) {
1582 err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE,
1583 MGMT_STATUS_NOT_POWERED,
1584 &rp, sizeof(rp));
1585 goto unlock;
1586 }
1587
Johan Hedberg124f6e32012-02-09 13:50:12 +02001588 if (cp->addr.type == MGMT_ADDR_BREDR)
1589 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
1590 else
1591 err = hci_remove_ltk(hdev, &cp->addr.bdaddr);
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03001592
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001593 if (err < 0) {
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001594 err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE,
1595 MGMT_STATUS_NOT_PAIRED,
1596 &rp, sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001597 goto unlock;
1598 }
1599
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001600 if (cp->disconnect) {
1601 if (cp->addr.type == MGMT_ADDR_BREDR)
1602 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
1603 &cp->addr.bdaddr);
1604 else
1605 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
1606 &cp->addr.bdaddr);
1607 } else {
1608 conn = NULL;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001609 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001610
Johan Hedberga8a1d192011-11-10 15:54:38 +02001611 if (!conn) {
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001612 err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE, 0,
Johan Hedbergaee9b212012-02-18 15:07:59 +02001613 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001614 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001615 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001616 }
1617
Johan Hedberg124f6e32012-02-09 13:50:12 +02001618 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
1619 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02001620 if (!cmd) {
1621 err = -ENOMEM;
1622 goto unlock;
1623 }
1624
1625 put_unaligned_le16(conn->handle, &dc.handle);
1626 dc.reason = 0x13; /* Remote User Terminated Connection */
1627 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1628 if (err < 0)
1629 mgmt_pending_remove(cmd);
1630
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001631unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001632 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001633 hci_dev_put(hdev);
1634
1635 return err;
1636}
1637
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001638static int disconnect(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02001639{
1640 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001641 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001642 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03001643 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001644 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001645 int err;
1646
1647 BT_DBG("");
1648
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001649 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001650 return cmd_status(sk, index, MGMT_OP_DISCONNECT,
1651 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001652
Szymon Janc4e51eae2011-02-25 19:05:48 +01001653 hdev = hci_dev_get(index);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001654 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001655 return cmd_status(sk, index, MGMT_OP_DISCONNECT,
1656 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001657
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001658 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001659
1660 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001661 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1662 MGMT_STATUS_NOT_POWERED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001663 goto failed;
1664 }
1665
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001666 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001667 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1668 MGMT_STATUS_BUSY);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001669 goto failed;
1670 }
1671
Johan Hedberg88c3df12012-02-09 14:27:38 +02001672 if (cp->addr.type == MGMT_ADDR_BREDR)
1673 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
1674 else
1675 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03001676
Johan Hedberg8962ee72011-01-20 12:40:27 +02001677 if (!conn) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001678 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1679 MGMT_STATUS_NOT_CONNECTED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001680 goto failed;
1681 }
1682
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001683 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001684 if (!cmd) {
1685 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001686 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001687 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001688
1689 put_unaligned_le16(conn->handle, &dc.handle);
1690 dc.reason = 0x13; /* Remote User Terminated Connection */
1691
1692 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1693 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001694 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001695
1696failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001697 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001698 hci_dev_put(hdev);
1699
1700 return err;
1701}
1702
Johan Hedberg48264f02011-11-09 13:58:58 +02001703static u8 link_to_mgmt(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02001704{
1705 switch (link_type) {
1706 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02001707 switch (addr_type) {
1708 case ADDR_LE_DEV_PUBLIC:
1709 return MGMT_ADDR_LE_PUBLIC;
1710 case ADDR_LE_DEV_RANDOM:
1711 return MGMT_ADDR_LE_RANDOM;
1712 default:
1713 return MGMT_ADDR_INVALID;
1714 }
Johan Hedberg4c659c32011-11-07 23:13:39 +02001715 case ACL_LINK:
1716 return MGMT_ADDR_BREDR;
1717 default:
1718 return MGMT_ADDR_INVALID;
1719 }
1720}
1721
Szymon Janc8ce62842011-03-01 16:55:32 +01001722static int get_connections(struct sock *sk, u16 index)
Johan Hedberg2784eb42011-01-21 13:56:35 +02001723{
Johan Hedberg2784eb42011-01-21 13:56:35 +02001724 struct mgmt_rp_get_connections *rp;
1725 struct hci_dev *hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001726 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02001727 size_t rp_len;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001728 u16 count;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001729 int i, err;
1730
1731 BT_DBG("");
1732
Szymon Janc4e51eae2011-02-25 19:05:48 +01001733 hdev = hci_dev_get(index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001734 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001735 return cmd_status(sk, index, MGMT_OP_GET_CONNECTIONS,
1736 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001737
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001738 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001739
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001740 if (!hdev_is_powered(hdev)) {
1741 err = cmd_status(sk, index, MGMT_OP_GET_CONNECTIONS,
1742 MGMT_STATUS_NOT_POWERED);
1743 goto unlock;
1744 }
1745
Johan Hedberg2784eb42011-01-21 13:56:35 +02001746 count = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02001747 list_for_each_entry(c, &hdev->conn_hash.list, list) {
1748 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
1749 count++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001750 }
1751
Johan Hedberg4c659c32011-11-07 23:13:39 +02001752 rp_len = sizeof(*rp) + (count * sizeof(struct mgmt_addr_info));
Johan Hedberga38528f2011-01-22 06:46:43 +02001753 rp = kmalloc(rp_len, GFP_ATOMIC);
1754 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02001755 err = -ENOMEM;
1756 goto unlock;
1757 }
1758
Johan Hedberg2784eb42011-01-21 13:56:35 +02001759 put_unaligned_le16(count, &rp->conn_count);
1760
Johan Hedberg2784eb42011-01-21 13:56:35 +02001761 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001762 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02001763 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
1764 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001765 bacpy(&rp->addr[i].bdaddr, &c->dst);
Johan Hedberg48264f02011-11-09 13:58:58 +02001766 rp->addr[i].type = link_to_mgmt(c->type, c->dst_type);
Johan Hedberg4c659c32011-11-07 23:13:39 +02001767 if (rp->addr[i].type == MGMT_ADDR_INVALID)
1768 continue;
1769 i++;
1770 }
1771
1772 /* Recalculate length in case of filtered SCO connections, etc */
1773 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02001774
Johan Hedbergaee9b212012-02-18 15:07:59 +02001775 err = cmd_complete(sk, index, MGMT_OP_GET_CONNECTIONS, 0, rp, rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001776
Johan Hedberga38528f2011-01-22 06:46:43 +02001777 kfree(rp);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001778
1779unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001780 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001781 hci_dev_put(hdev);
1782 return err;
1783}
1784
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001785static int send_pin_code_neg_reply(struct sock *sk, u16 index,
1786 struct hci_dev *hdev, struct mgmt_cp_pin_code_neg_reply *cp)
1787{
1788 struct pending_cmd *cmd;
1789 int err;
1790
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001791 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001792 sizeof(*cp));
1793 if (!cmd)
1794 return -ENOMEM;
1795
Johan Hedbergd8457692012-02-17 14:24:57 +02001796 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
1797 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001798 if (err < 0)
1799 mgmt_pending_remove(cmd);
1800
1801 return err;
1802}
1803
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001804static int pin_code_reply(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001805{
1806 struct hci_dev *hdev;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001807 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001808 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001809 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03001810 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001811 int err;
1812
1813 BT_DBG("");
1814
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001815 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001816 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1817 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001818
Szymon Janc4e51eae2011-02-25 19:05:48 +01001819 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001820 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001821 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1822 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001823
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001824 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001825
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001826 if (!hdev_is_powered(hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001827 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1828 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001829 goto failed;
1830 }
1831
Johan Hedbergd8457692012-02-17 14:24:57 +02001832 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001833 if (!conn) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001834 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1835 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001836 goto failed;
1837 }
1838
1839 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02001840 struct mgmt_cp_pin_code_neg_reply ncp;
1841
1842 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001843
1844 BT_ERR("PIN code is not 16 bytes long");
1845
1846 err = send_pin_code_neg_reply(sk, index, hdev, &ncp);
1847 if (err >= 0)
1848 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001849 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001850
1851 goto failed;
1852 }
1853
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001854 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data,
1855 len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001856 if (!cmd) {
1857 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001858 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001859 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02001860
Johan Hedbergd8457692012-02-17 14:24:57 +02001861 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001862 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02001863 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02001864
1865 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
1866 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001867 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001868
1869failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001870 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001871 hci_dev_put(hdev);
1872
1873 return err;
1874}
1875
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001876static int pin_code_neg_reply(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001877{
1878 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001879 struct mgmt_cp_pin_code_neg_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001880 int err;
1881
1882 BT_DBG("");
1883
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001884 if (len != sizeof(*cp))
1885 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001886 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001887
Szymon Janc4e51eae2011-02-25 19:05:48 +01001888 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001889 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001890 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001891 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001892
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001893 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001894
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001895 if (!hdev_is_powered(hdev)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001896 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001897 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001898 goto failed;
1899 }
1900
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001901 err = send_pin_code_neg_reply(sk, index, hdev, cp);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001902
1903failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001904 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001905 hci_dev_put(hdev);
1906
1907 return err;
1908}
1909
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001910static int set_io_capability(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001911{
1912 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001913 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001914
1915 BT_DBG("");
1916
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001917 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001918 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY,
1919 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001920
Szymon Janc4e51eae2011-02-25 19:05:48 +01001921 hdev = hci_dev_get(index);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001922 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001923 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY,
1924 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001925
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001926 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001927
1928 hdev->io_capability = cp->io_capability;
1929
1930 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Szymon Jancb8534e02011-03-01 16:55:34 +01001931 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001932
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001933 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001934 hci_dev_put(hdev);
1935
Johan Hedbergaee9b212012-02-18 15:07:59 +02001936 return cmd_complete(sk, index, MGMT_OP_SET_IO_CAPABILITY, 0, NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001937}
1938
Johan Hedberge9a416b2011-02-19 12:05:56 -03001939static inline struct pending_cmd *find_pairing(struct hci_conn *conn)
1940{
1941 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001942 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001943
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001944 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03001945 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
1946 continue;
1947
Johan Hedberge9a416b2011-02-19 12:05:56 -03001948 if (cmd->user_data != conn)
1949 continue;
1950
1951 return cmd;
1952 }
1953
1954 return NULL;
1955}
1956
1957static void pairing_complete(struct pending_cmd *cmd, u8 status)
1958{
1959 struct mgmt_rp_pair_device rp;
1960 struct hci_conn *conn = cmd->user_data;
1961
Johan Hedbergba4e5642011-11-11 00:07:34 +02001962 bacpy(&rp.addr.bdaddr, &conn->dst);
1963 rp.addr.type = link_to_mgmt(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001964
Johan Hedbergaee9b212012-02-18 15:07:59 +02001965 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, status,
1966 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001967
1968 /* So we don't get further callbacks for this connection */
1969 conn->connect_cfm_cb = NULL;
1970 conn->security_cfm_cb = NULL;
1971 conn->disconn_cfm_cb = NULL;
1972
1973 hci_conn_put(conn);
1974
Johan Hedberga664b5b2011-02-19 12:06:02 -03001975 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001976}
1977
1978static void pairing_complete_cb(struct hci_conn *conn, u8 status)
1979{
1980 struct pending_cmd *cmd;
1981
1982 BT_DBG("status %u", status);
1983
Johan Hedberg56e5cb82011-11-08 20:40:16 +02001984 cmd = find_pairing(conn);
1985 if (!cmd)
1986 BT_DBG("Unable to find a pending command");
1987 else
Johan Hedberge2113262012-02-18 15:20:03 +02001988 pairing_complete(cmd, mgmt_status(status));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001989}
1990
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001991static int pair_device(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001992{
1993 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001994 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02001995 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001996 struct pending_cmd *cmd;
1997 u8 sec_level, auth_type;
1998 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001999 int err;
2000
2001 BT_DBG("");
2002
Szymon Jancbdce7ba2011-02-25 19:05:49 +01002003 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02002004 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE,
2005 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01002006
Szymon Janc4e51eae2011-02-25 19:05:48 +01002007 hdev = hci_dev_get(index);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002008 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002009 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE,
2010 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002011
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002012 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002013
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002014 if (!hdev_is_powered(hdev)) {
2015 err = cmd_status(sk, index, MGMT_OP_PAIR_DEVICE,
2016 MGMT_STATUS_NOT_POWERED);
2017 goto unlock;
2018 }
2019
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002020 sec_level = BT_SECURITY_MEDIUM;
2021 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002022 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002023 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03002024 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002025
Johan Hedbergba4e5642011-11-11 00:07:34 +02002026 if (cp->addr.type == MGMT_ADDR_BREDR)
2027 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr, sec_level,
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002028 auth_type);
2029 else
Johan Hedbergba4e5642011-11-11 00:07:34 +02002030 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr, sec_level,
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002031 auth_type);
2032
Johan Hedberg1425acb2011-11-11 00:07:35 +02002033 memset(&rp, 0, sizeof(rp));
2034 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2035 rp.addr.type = cp->addr.type;
2036
Ville Tervo30e76272011-02-22 16:10:53 -03002037 if (IS_ERR(conn)) {
Johan Hedberge2113262012-02-18 15:20:03 +02002038 err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE,
2039 MGMT_STATUS_CONNECT_FAILED,
2040 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002041 goto unlock;
2042 }
2043
2044 if (conn->connect_cfm_cb) {
2045 hci_conn_put(conn);
Johan Hedberge2113262012-02-18 15:20:03 +02002046 err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE,
2047 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002048 goto unlock;
2049 }
2050
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002051 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002052 if (!cmd) {
2053 err = -ENOMEM;
2054 hci_conn_put(conn);
2055 goto unlock;
2056 }
2057
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002058 /* For LE, just connecting isn't a proof that the pairing finished */
Johan Hedbergba4e5642011-11-11 00:07:34 +02002059 if (cp->addr.type == MGMT_ADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002060 conn->connect_cfm_cb = pairing_complete_cb;
2061
Johan Hedberge9a416b2011-02-19 12:05:56 -03002062 conn->security_cfm_cb = pairing_complete_cb;
2063 conn->disconn_cfm_cb = pairing_complete_cb;
2064 conn->io_capability = cp->io_cap;
2065 cmd->user_data = conn;
2066
2067 if (conn->state == BT_CONNECTED &&
2068 hci_conn_security(conn, sec_level, auth_type))
2069 pairing_complete(cmd, 0);
2070
2071 err = 0;
2072
2073unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002074 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002075 hci_dev_put(hdev);
2076
2077 return err;
2078}
2079
Johan Hedberg28424702012-02-02 04:02:29 +02002080static int cancel_pair_device(struct sock *sk, u16 index,
2081 unsigned char *data, u16 len)
2082{
2083 struct mgmt_addr_info *addr = (void *) data;
2084 struct hci_dev *hdev;
2085 struct pending_cmd *cmd;
2086 struct hci_conn *conn;
2087 int err;
2088
2089 BT_DBG("");
2090
2091 if (len != sizeof(*addr))
2092 return cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
2093 MGMT_STATUS_INVALID_PARAMS);
2094
2095 hdev = hci_dev_get(index);
2096 if (!hdev)
2097 return cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
2098 MGMT_STATUS_INVALID_PARAMS);
2099
2100 hci_dev_lock(hdev);
2101
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002102 if (!hdev_is_powered(hdev)) {
2103 err = cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
2104 MGMT_STATUS_NOT_POWERED);
2105 goto unlock;
2106 }
2107
Johan Hedberg28424702012-02-02 04:02:29 +02002108 cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
2109 if (!cmd) {
2110 err = cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
2111 MGMT_STATUS_INVALID_PARAMS);
2112 goto unlock;
2113 }
2114
2115 conn = cmd->user_data;
2116
2117 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
2118 err = cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
2119 MGMT_STATUS_INVALID_PARAMS);
2120 goto unlock;
2121 }
2122
2123 pairing_complete(cmd, MGMT_STATUS_CANCELLED);
2124
Johan Hedbergaee9b212012-02-18 15:07:59 +02002125 err = cmd_complete(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE, 0, addr,
Johan Hedberg28424702012-02-02 04:02:29 +02002126 sizeof(*addr));
2127unlock:
2128 hci_dev_unlock(hdev);
2129 hci_dev_put(hdev);
2130
2131 return err;
2132}
2133
Brian Gix0df4c182011-11-16 13:53:13 -08002134static int user_pairing_resp(struct sock *sk, u16 index, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02002135 u8 type, u16 mgmt_op, u16 hci_op,
2136 __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03002137{
Johan Hedberga5c29682011-02-19 12:05:57 -03002138 struct pending_cmd *cmd;
2139 struct hci_dev *hdev;
Brian Gix0df4c182011-11-16 13:53:13 -08002140 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03002141 int err;
2142
Szymon Janc4e51eae2011-02-25 19:05:48 +01002143 hdev = hci_dev_get(index);
Johan Hedberga5c29682011-02-19 12:05:57 -03002144 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002145 return cmd_status(sk, index, mgmt_op,
2146 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga5c29682011-02-19 12:05:57 -03002147
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002148 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02002149
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002150 if (!hdev_is_powered(hdev)) {
Brian Gix0df4c182011-11-16 13:53:13 -08002151 err = cmd_status(sk, index, mgmt_op, MGMT_STATUS_NOT_POWERED);
2152 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002153 }
2154
Johan Hedberg272d90d2012-02-09 15:26:12 +02002155 if (type == MGMT_ADDR_BREDR)
2156 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, bdaddr);
2157 else
Brian Gix47c15e22011-11-16 13:53:14 -08002158 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, bdaddr);
Brian Gix47c15e22011-11-16 13:53:14 -08002159
Johan Hedberg272d90d2012-02-09 15:26:12 +02002160 if (!conn) {
2161 err = cmd_status(sk, index, mgmt_op,
2162 MGMT_STATUS_NOT_CONNECTED);
2163 goto done;
2164 }
2165
2166 if (type == MGMT_ADDR_LE_PUBLIC || type == MGMT_ADDR_LE_RANDOM) {
Brian Gix47c15e22011-11-16 13:53:14 -08002167 /* Continue with pairing via SMP */
Brian Gix5fe57d92011-12-21 16:12:13 -08002168 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix47c15e22011-11-16 13:53:14 -08002169
Brian Gix5fe57d92011-12-21 16:12:13 -08002170 if (!err)
2171 err = cmd_status(sk, index, mgmt_op,
2172 MGMT_STATUS_SUCCESS);
2173 else
2174 err = cmd_status(sk, index, mgmt_op,
2175 MGMT_STATUS_FAILED);
2176
Brian Gix47c15e22011-11-16 13:53:14 -08002177 goto done;
2178 }
2179
Brian Gix0df4c182011-11-16 13:53:13 -08002180 cmd = mgmt_pending_add(sk, mgmt_op, hdev, bdaddr, sizeof(*bdaddr));
Johan Hedberga5c29682011-02-19 12:05:57 -03002181 if (!cmd) {
2182 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08002183 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002184 }
2185
Brian Gix0df4c182011-11-16 13:53:13 -08002186 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08002187 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
2188 struct hci_cp_user_passkey_reply cp;
2189
2190 bacpy(&cp.bdaddr, bdaddr);
2191 cp.passkey = passkey;
2192 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
2193 } else
2194 err = hci_send_cmd(hdev, hci_op, sizeof(*bdaddr), bdaddr);
2195
Johan Hedberga664b5b2011-02-19 12:06:02 -03002196 if (err < 0)
2197 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002198
Brian Gix0df4c182011-11-16 13:53:13 -08002199done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002200 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002201 hci_dev_put(hdev);
2202
2203 return err;
2204}
2205
Brian Gix0df4c182011-11-16 13:53:13 -08002206static int user_confirm_reply(struct sock *sk, u16 index, void *data, u16 len)
2207{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002208 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002209
2210 BT_DBG("");
2211
2212 if (len != sizeof(*cp))
2213 return cmd_status(sk, index, MGMT_OP_USER_CONFIRM_REPLY,
2214 MGMT_STATUS_INVALID_PARAMS);
2215
Johan Hedberg272d90d2012-02-09 15:26:12 +02002216 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
2217 MGMT_OP_USER_CONFIRM_REPLY,
2218 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002219}
2220
2221static int user_confirm_neg_reply(struct sock *sk, u16 index, void *data,
2222 u16 len)
2223{
Johan Hedbergc9c26592011-12-15 00:47:41 +02002224 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002225
2226 BT_DBG("");
2227
2228 if (len != sizeof(*cp))
2229 return cmd_status(sk, index, MGMT_OP_USER_CONFIRM_NEG_REPLY,
2230 MGMT_STATUS_INVALID_PARAMS);
2231
Johan Hedberg272d90d2012-02-09 15:26:12 +02002232 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
2233 MGMT_OP_USER_CONFIRM_NEG_REPLY,
2234 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002235}
2236
Brian Gix604086b2011-11-23 08:28:33 -08002237static int user_passkey_reply(struct sock *sk, u16 index, void *data, u16 len)
2238{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002239 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002240
2241 BT_DBG("");
2242
2243 if (len != sizeof(*cp))
2244 return cmd_status(sk, index, MGMT_OP_USER_PASSKEY_REPLY,
2245 EINVAL);
2246
Johan Hedberg272d90d2012-02-09 15:26:12 +02002247 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
2248 MGMT_OP_USER_PASSKEY_REPLY,
2249 HCI_OP_USER_PASSKEY_REPLY,
2250 cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08002251}
2252
2253static int user_passkey_neg_reply(struct sock *sk, u16 index, void *data,
2254 u16 len)
2255{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002256 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002257
2258 BT_DBG("");
2259
2260 if (len != sizeof(*cp))
2261 return cmd_status(sk, index, MGMT_OP_USER_PASSKEY_NEG_REPLY,
2262 EINVAL);
2263
Johan Hedberg272d90d2012-02-09 15:26:12 +02002264 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
2265 MGMT_OP_USER_PASSKEY_NEG_REPLY,
2266 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08002267}
2268
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002269static int set_local_name(struct sock *sk, u16 index, void *data,
Johan Hedbergb312b1612011-03-16 14:29:37 +02002270 u16 len)
2271{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002272 struct mgmt_cp_set_local_name *mgmt_cp = data;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002273 struct hci_cp_write_local_name hci_cp;
2274 struct hci_dev *hdev;
2275 struct pending_cmd *cmd;
2276 int err;
2277
2278 BT_DBG("");
2279
2280 if (len != sizeof(*mgmt_cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02002281 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME,
2282 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002283
2284 hdev = hci_dev_get(index);
2285 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002286 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME,
2287 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002288
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002289 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002290
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002291 memcpy(hdev->short_name, mgmt_cp->short_name,
2292 sizeof(hdev->short_name));
2293
Johan Hedbergb5235a62012-02-21 14:32:24 +02002294 if (!hdev_is_powered(hdev)) {
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002295 memcpy(hdev->dev_name, mgmt_cp->name, sizeof(hdev->dev_name));
2296
2297 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
2298 data, len);
2299 if (err < 0)
2300 goto failed;
2301
2302 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data, len,
2303 sk);
2304
Johan Hedbergb5235a62012-02-21 14:32:24 +02002305 goto failed;
2306 }
2307
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002308 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002309 if (!cmd) {
2310 err = -ENOMEM;
2311 goto failed;
2312 }
2313
2314 memcpy(hci_cp.name, mgmt_cp->name, sizeof(hci_cp.name));
2315 err = hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(hci_cp),
2316 &hci_cp);
2317 if (err < 0)
2318 mgmt_pending_remove(cmd);
2319
2320failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002321 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002322 hci_dev_put(hdev);
2323
2324 return err;
2325}
2326
Szymon Jancc35938b2011-03-22 13:12:21 +01002327static int read_local_oob_data(struct sock *sk, u16 index)
2328{
2329 struct hci_dev *hdev;
2330 struct pending_cmd *cmd;
2331 int err;
2332
2333 BT_DBG("hci%u", index);
2334
2335 hdev = hci_dev_get(index);
2336 if (!hdev)
2337 return cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002338 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancc35938b2011-03-22 13:12:21 +01002339
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002340 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002341
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002342 if (!hdev_is_powered(hdev)) {
Szymon Jancc35938b2011-03-22 13:12:21 +01002343 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002344 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002345 goto unlock;
2346 }
2347
2348 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
2349 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002350 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002351 goto unlock;
2352 }
2353
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002354 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02002355 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2356 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01002357 goto unlock;
2358 }
2359
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002360 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01002361 if (!cmd) {
2362 err = -ENOMEM;
2363 goto unlock;
2364 }
2365
2366 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
2367 if (err < 0)
2368 mgmt_pending_remove(cmd);
2369
2370unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002371 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002372 hci_dev_put(hdev);
2373
2374 return err;
2375}
2376
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002377static int add_remote_oob_data(struct sock *sk, u16 index, void *data,
2378 u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002379{
2380 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002381 struct mgmt_cp_add_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002382 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002383 int err;
2384
2385 BT_DBG("hci%u ", index);
2386
2387 if (len != sizeof(*cp))
2388 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002389 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01002390
2391 hdev = hci_dev_get(index);
2392 if (!hdev)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002393 return cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
2394 MGMT_STATUS_INVALID_PARAMS,
2395 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002396
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002397 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002398
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002399 if (!hdev_is_powered(hdev)) {
2400 err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
2401 MGMT_STATUS_NOT_POWERED,
2402 &cp->addr, sizeof(cp->addr));
2403 goto unlock;
2404 }
2405
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002406 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, cp->hash,
Szymon Janc2763eda2011-03-22 13:12:22 +01002407 cp->randomizer);
2408 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002409 status = MGMT_STATUS_FAILED;
Szymon Janc2763eda2011-03-22 13:12:22 +01002410 else
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002411 status = 0;
2412
2413 err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, status,
2414 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002415
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002416unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002417 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002418 hci_dev_put(hdev);
2419
2420 return err;
2421}
2422
2423static int remove_remote_oob_data(struct sock *sk, u16 index,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002424 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002425{
2426 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002427 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002428 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002429 int err;
2430
2431 BT_DBG("hci%u ", index);
2432
2433 if (len != sizeof(*cp))
2434 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002435 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01002436
2437 hdev = hci_dev_get(index);
2438 if (!hdev)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002439 return cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2440 MGMT_STATUS_INVALID_PARAMS,
2441 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002442
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002443 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002444
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002445 if (!hdev_is_powered(hdev)) {
2446 err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2447 MGMT_STATUS_NOT_POWERED,
2448 &cp->addr, sizeof(cp->addr));
2449 goto unlock;
2450 }
2451
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002452 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr);
Szymon Janc2763eda2011-03-22 13:12:22 +01002453 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002454 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01002455 else
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002456 status = 0;
2457
2458 err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA, status,
2459 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002460
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002461unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002462 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002463 hci_dev_put(hdev);
2464
2465 return err;
2466}
2467
Andre Guedes5e0452c2012-02-17 20:39:38 -03002468static int discovery(struct hci_dev *hdev)
2469{
2470 int err;
2471
2472 if (lmp_host_le_capable(hdev)) {
2473 if (lmp_bredr_capable(hdev)) {
2474 err = hci_le_scan(hdev, LE_SCAN_TYPE,
2475 LE_SCAN_INT, LE_SCAN_WIN,
2476 LE_SCAN_TIMEOUT_BREDR_LE);
2477 } else {
2478 hdev->discovery.type = DISCOV_TYPE_LE;
2479 err = hci_le_scan(hdev, LE_SCAN_TYPE,
2480 LE_SCAN_INT, LE_SCAN_WIN,
2481 LE_SCAN_TIMEOUT_LE_ONLY);
2482 }
2483 } else {
2484 hdev->discovery.type = DISCOV_TYPE_BREDR;
2485 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
2486 }
2487
2488 return err;
2489}
2490
2491int mgmt_interleaved_discovery(struct hci_dev *hdev)
2492{
2493 int err;
2494
2495 BT_DBG("%s", hdev->name);
2496
2497 hci_dev_lock(hdev);
2498
2499 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR_LE);
2500 if (err < 0)
2501 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2502
2503 hci_dev_unlock(hdev);
2504
2505 return err;
2506}
2507
Johan Hedberg450dfda2011-11-12 11:58:22 +02002508static int start_discovery(struct sock *sk, u16 index,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002509 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002510{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002511 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002512 struct pending_cmd *cmd;
2513 struct hci_dev *hdev;
2514 int err;
2515
2516 BT_DBG("hci%u", index);
2517
Johan Hedberg450dfda2011-11-12 11:58:22 +02002518 if (len != sizeof(*cp))
2519 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2520 MGMT_STATUS_INVALID_PARAMS);
2521
Johan Hedberg14a53662011-04-27 10:29:56 -04002522 hdev = hci_dev_get(index);
2523 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002524 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2525 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg14a53662011-04-27 10:29:56 -04002526
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002527 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002528
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002529 if (!hdev_is_powered(hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02002530 err = cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2531 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02002532 goto failed;
2533 }
2534
Johan Hedbergff9ef572012-01-04 14:23:45 +02002535 if (hdev->discovery.state != DISCOVERY_STOPPED) {
2536 err = cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2537 MGMT_STATUS_BUSY);
2538 goto failed;
2539 }
2540
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002541 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002542 if (!cmd) {
2543 err = -ENOMEM;
2544 goto failed;
2545 }
2546
Andre Guedes4aab14e2012-02-17 20:39:36 -03002547 hdev->discovery.type = cp->type;
2548
2549 switch (hdev->discovery.type) {
Andre Guedesf39799f2012-02-17 20:39:35 -03002550 case DISCOV_TYPE_BREDR:
Andre Guedes3fd24152012-02-03 17:48:01 -03002551 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
Andre Guedesf39799f2012-02-17 20:39:35 -03002552 break;
2553
2554 case DISCOV_TYPE_LE:
Andre Guedes3fd24152012-02-03 17:48:01 -03002555 err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT,
2556 LE_SCAN_WIN, LE_SCAN_TIMEOUT_LE_ONLY);
Andre Guedesf39799f2012-02-17 20:39:35 -03002557 break;
2558
Andre Guedes5e0452c2012-02-17 20:39:38 -03002559 case DISCOV_TYPE_INTERLEAVED:
2560 err = discovery(hdev);
2561 break;
2562
Andre Guedesf39799f2012-02-17 20:39:35 -03002563 default:
Andre Guedes3fd24152012-02-03 17:48:01 -03002564 err = -EINVAL;
Andre Guedesf39799f2012-02-17 20:39:35 -03002565 }
Andre Guedes3fd24152012-02-03 17:48:01 -03002566
Johan Hedberg14a53662011-04-27 10:29:56 -04002567 if (err < 0)
2568 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002569 else
2570 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002571
2572failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002573 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002574 hci_dev_put(hdev);
2575
2576 return err;
2577}
2578
Johan Hedbergd9306502012-02-20 23:25:18 +02002579static int stop_discovery(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002580{
Johan Hedbergd9306502012-02-20 23:25:18 +02002581 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002582 struct hci_dev *hdev;
2583 struct pending_cmd *cmd;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002584 struct hci_cp_remote_name_req_cancel cp;
2585 struct inquiry_entry *e;
Johan Hedberg14a53662011-04-27 10:29:56 -04002586 int err;
2587
2588 BT_DBG("hci%u", index);
2589
Johan Hedbergd9306502012-02-20 23:25:18 +02002590 if (len != sizeof(*mgmt_cp))
2591 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY,
2592 MGMT_STATUS_INVALID_PARAMS);
2593
Johan Hedberg14a53662011-04-27 10:29:56 -04002594 hdev = hci_dev_get(index);
2595 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002596 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY,
2597 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg14a53662011-04-27 10:29:56 -04002598
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002599 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002600
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002601 if (!hci_discovery_active(hdev)) {
Johan Hedbergd9306502012-02-20 23:25:18 +02002602 err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY,
2603 MGMT_STATUS_REJECTED,
2604 &mgmt_cp->type, sizeof(mgmt_cp->type));
2605 goto unlock;
2606 }
2607
2608 if (hdev->discovery.type != mgmt_cp->type) {
2609 err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY,
2610 MGMT_STATUS_INVALID_PARAMS,
2611 &mgmt_cp->type, sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002612 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02002613 }
2614
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002615 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002616 if (!cmd) {
2617 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002618 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04002619 }
2620
Andre Guedes343f9352012-02-17 20:39:37 -03002621 if (hdev->discovery.state == DISCOVERY_FINDING) {
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002622 err = hci_cancel_inquiry(hdev);
2623 if (err < 0)
2624 mgmt_pending_remove(cmd);
2625 else
2626 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
2627 goto unlock;
2628 }
2629
2630 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY, NAME_PENDING);
2631 if (!e) {
2632 mgmt_pending_remove(cmd);
Johan Hedbergaee9b212012-02-18 15:07:59 +02002633 err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY, 0,
Johan Hedbergd9306502012-02-20 23:25:18 +02002634 &mgmt_cp->type, sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002635 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2636 goto unlock;
2637 }
2638
2639 bacpy(&cp.bdaddr, &e->data.bdaddr);
2640 err = hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ_CANCEL,
2641 sizeof(cp), &cp);
Johan Hedberg14a53662011-04-27 10:29:56 -04002642 if (err < 0)
2643 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002644 else
2645 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002646
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002647unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002648 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002649 hci_dev_put(hdev);
2650
2651 return err;
2652}
2653
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002654static int confirm_name(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02002655{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002656 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002657 struct inquiry_entry *e;
2658 struct hci_dev *hdev;
2659 int err;
2660
2661 BT_DBG("hci%u", index);
2662
2663 if (len != sizeof(*cp))
2664 return cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2665 MGMT_STATUS_INVALID_PARAMS);
2666
2667 hdev = hci_dev_get(index);
2668 if (!hdev)
2669 return cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2670 MGMT_STATUS_INVALID_PARAMS);
2671
2672 hci_dev_lock(hdev);
2673
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002674 if (!hci_discovery_active(hdev)) {
2675 err = cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2676 MGMT_STATUS_FAILED);
2677 goto failed;
2678 }
2679
Johan Hedberga198e7b2012-02-17 14:27:06 +02002680 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002681 if (!e) {
Marcel Holtmanne5f0e152012-02-22 11:59:01 +01002682 err = cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
Johan Hedberg561aafb2012-01-04 13:31:59 +02002683 MGMT_STATUS_INVALID_PARAMS);
2684 goto failed;
2685 }
2686
2687 if (cp->name_known) {
2688 e->name_state = NAME_KNOWN;
2689 list_del(&e->list);
2690 } else {
2691 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e202012-01-09 00:53:02 +02002692 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002693 }
2694
2695 err = 0;
2696
2697failed:
2698 hci_dev_unlock(hdev);
2699
2700 return err;
2701}
2702
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002703static int block_device(struct sock *sk, u16 index, void *data, u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002704{
2705 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002706 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002707 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03002708 int err;
2709
2710 BT_DBG("hci%u", index);
2711
Antti Julku7fbec222011-06-15 12:01:15 +03002712 if (len != sizeof(*cp))
2713 return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002714 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002715
2716 hdev = hci_dev_get(index);
2717 if (!hdev)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002718 return cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE,
2719 MGMT_STATUS_INVALID_PARAMS,
2720 &cp->addr, sizeof(cp->addr));
Antti Julku7fbec222011-06-15 12:01:15 +03002721
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002722 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002723
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002724 err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002725 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002726 status = MGMT_STATUS_FAILED;
Antti Julku7fbec222011-06-15 12:01:15 +03002727 else
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002728 status = 0;
2729
2730 err = cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE, status,
2731 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03002732
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002733 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002734 hci_dev_put(hdev);
2735
2736 return err;
2737}
2738
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002739static int unblock_device(struct sock *sk, u16 index, void *data, u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002740{
2741 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002742 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002743 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03002744 int err;
2745
2746 BT_DBG("hci%u", index);
2747
Antti Julku7fbec222011-06-15 12:01:15 +03002748 if (len != sizeof(*cp))
2749 return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002750 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002751
2752 hdev = hci_dev_get(index);
2753 if (!hdev)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002754 return cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE,
2755 MGMT_STATUS_INVALID_PARAMS,
2756 &cp->addr, sizeof(cp->addr));
Antti Julku7fbec222011-06-15 12:01:15 +03002757
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002758 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002759
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002760 err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002761 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002762 status = MGMT_STATUS_INVALID_PARAMS;
Antti Julku7fbec222011-06-15 12:01:15 +03002763 else
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002764 status = 0;
2765
2766 err = cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE, status,
2767 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03002768
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002769 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002770 hci_dev_put(hdev);
2771
2772 return err;
2773}
2774
Antti Julkuf6422ec2011-06-22 13:11:56 +03002775static int set_fast_connectable(struct sock *sk, u16 index,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002776 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03002777{
2778 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002779 struct mgmt_mode *cp = data;
Antti Julkuf6422ec2011-06-22 13:11:56 +03002780 struct hci_cp_write_page_scan_activity acp;
2781 u8 type;
2782 int err;
2783
2784 BT_DBG("hci%u", index);
2785
2786 if (len != sizeof(*cp))
2787 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002788 MGMT_STATUS_INVALID_PARAMS);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002789
2790 hdev = hci_dev_get(index);
2791 if (!hdev)
2792 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002793 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg5400c042012-02-21 16:40:33 +02002794 if (!hdev_is_powered(hdev))
2795 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
2796 MGMT_STATUS_NOT_POWERED);
2797
2798 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
2799 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
2800 MGMT_STATUS_REJECTED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002801
2802 hci_dev_lock(hdev);
2803
Johan Hedbergf7c6869ce2011-12-15 00:47:36 +02002804 if (cp->val) {
Antti Julkuf6422ec2011-06-22 13:11:56 +03002805 type = PAGE_SCAN_TYPE_INTERLACED;
2806 acp.interval = 0x0024; /* 22.5 msec page scan interval */
2807 } else {
2808 type = PAGE_SCAN_TYPE_STANDARD; /* default */
2809 acp.interval = 0x0800; /* default 1.28 sec page scan */
2810 }
2811
2812 acp.window = 0x0012; /* default 11.25 msec page scan window */
2813
2814 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
2815 sizeof(acp), &acp);
2816 if (err < 0) {
2817 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002818 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002819 goto done;
2820 }
2821
2822 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
2823 if (err < 0) {
2824 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002825 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002826 goto done;
2827 }
2828
Johan Hedbergaee9b212012-02-18 15:07:59 +02002829 err = cmd_complete(sk, index, MGMT_OP_SET_FAST_CONNECTABLE, 0,
2830 NULL, 0);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002831done:
2832 hci_dev_unlock(hdev);
2833 hci_dev_put(hdev);
2834
2835 return err;
2836}
2837
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002838static int load_long_term_keys(struct sock *sk, u16 index,
2839 void *cp_data, u16 len)
2840{
2841 struct hci_dev *hdev;
2842 struct mgmt_cp_load_long_term_keys *cp = cp_data;
2843 u16 key_count, expected_len;
2844 int i;
2845
2846 if (len < sizeof(*cp))
2847 return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS,
2848 EINVAL);
2849
2850 key_count = get_unaligned_le16(&cp->key_count);
2851
2852 expected_len = sizeof(*cp) + key_count *
2853 sizeof(struct mgmt_ltk_info);
2854 if (expected_len != len) {
2855 BT_ERR("load_keys: expected %u bytes, got %u bytes",
2856 len, expected_len);
2857 return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS,
2858 EINVAL);
2859 }
2860
2861 hdev = hci_dev_get(index);
2862 if (!hdev)
2863 return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS,
2864 ENODEV);
2865
2866 BT_DBG("hci%u key_count %u", index, key_count);
2867
2868 hci_dev_lock(hdev);
2869
2870 hci_smp_ltks_clear(hdev);
2871
2872 for (i = 0; i < key_count; i++) {
2873 struct mgmt_ltk_info *key = &cp->keys[i];
2874 u8 type;
2875
2876 if (key->master)
2877 type = HCI_SMP_LTK;
2878 else
2879 type = HCI_SMP_LTK_SLAVE;
2880
2881 hci_add_ltk(hdev, &key->addr.bdaddr, key->addr.type,
2882 type, 0, key->authenticated, key->val,
2883 key->enc_size, key->ediv, key->rand);
2884 }
2885
2886 hci_dev_unlock(hdev);
2887 hci_dev_put(hdev);
2888
2889 return 0;
2890}
2891
Johan Hedberg03811012010-12-08 00:21:06 +02002892int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
2893{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002894 void *buf;
2895 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02002896 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002897 u16 opcode, index, len;
Johan Hedberg03811012010-12-08 00:21:06 +02002898 int err;
2899
2900 BT_DBG("got %zu bytes", msglen);
2901
2902 if (msglen < sizeof(*hdr))
2903 return -EINVAL;
2904
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03002905 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02002906 if (!buf)
2907 return -ENOMEM;
2908
2909 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
2910 err = -EFAULT;
2911 goto done;
2912 }
2913
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002914 hdr = buf;
Johan Hedberg03811012010-12-08 00:21:06 +02002915 opcode = get_unaligned_le16(&hdr->opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002916 index = get_unaligned_le16(&hdr->index);
Johan Hedberg03811012010-12-08 00:21:06 +02002917 len = get_unaligned_le16(&hdr->len);
2918
2919 if (len != msglen - sizeof(*hdr)) {
2920 err = -EINVAL;
2921 goto done;
2922 }
2923
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002924 cp = buf + sizeof(*hdr);
2925
Johan Hedberg03811012010-12-08 00:21:06 +02002926 switch (opcode) {
Johan Hedberg02d98122010-12-13 21:07:04 +02002927 case MGMT_OP_READ_VERSION:
2928 err = read_version(sk);
2929 break;
Johan Hedberge70bb2e2012-02-13 16:59:33 +02002930 case MGMT_OP_READ_COMMANDS:
2931 err = read_commands(sk);
2932 break;
Johan Hedbergfaba42e2010-12-13 21:07:05 +02002933 case MGMT_OP_READ_INDEX_LIST:
2934 err = read_index_list(sk);
2935 break;
Johan Hedbergf7b64e692010-12-13 21:07:06 +02002936 case MGMT_OP_READ_INFO:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002937 err = read_controller_info(sk, index);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02002938 break;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002939 case MGMT_OP_SET_POWERED:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002940 err = set_powered(sk, index, cp, len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002941 break;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002942 case MGMT_OP_SET_DISCOVERABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002943 err = set_discoverable(sk, index, cp, len);
Johan Hedberg73f22f62010-12-29 16:00:25 +02002944 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002945 case MGMT_OP_SET_CONNECTABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002946 err = set_connectable(sk, index, cp, len);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002947 break;
Johan Hedbergf7c6869ce2011-12-15 00:47:36 +02002948 case MGMT_OP_SET_FAST_CONNECTABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002949 err = set_fast_connectable(sk, index, cp, len);
Johan Hedbergf7c6869ce2011-12-15 00:47:36 +02002950 break;
Johan Hedbergc542a062011-01-26 13:11:03 +02002951 case MGMT_OP_SET_PAIRABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002952 err = set_pairable(sk, index, cp, len);
Johan Hedbergc542a062011-01-26 13:11:03 +02002953 break;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02002954 case MGMT_OP_SET_LINK_SECURITY:
2955 err = set_link_security(sk, index, cp, len);
2956 break;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02002957 case MGMT_OP_SET_SSP:
2958 err = set_ssp(sk, index, cp, len);
2959 break;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02002960 case MGMT_OP_SET_HS:
2961 err = set_hs(sk, index, cp, len);
2962 break;
Johan Hedberg06199cf2012-02-22 16:37:11 +02002963 case MGMT_OP_SET_LE:
2964 err = set_le(sk, index, cp, len);
2965 break;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002966 case MGMT_OP_ADD_UUID:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002967 err = add_uuid(sk, index, cp, len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002968 break;
2969 case MGMT_OP_REMOVE_UUID:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002970 err = remove_uuid(sk, index, cp, len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002971 break;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002972 case MGMT_OP_SET_DEV_CLASS:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002973 err = set_dev_class(sk, index, cp, len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002974 break;
Johan Hedberg86742e12011-11-07 23:13:38 +02002975 case MGMT_OP_LOAD_LINK_KEYS:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002976 err = load_link_keys(sk, index, cp, len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002977 break;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002978 case MGMT_OP_DISCONNECT:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002979 err = disconnect(sk, index, cp, len);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002980 break;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002981 case MGMT_OP_GET_CONNECTIONS:
Szymon Janc8ce62842011-03-01 16:55:32 +01002982 err = get_connections(sk, index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002983 break;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002984 case MGMT_OP_PIN_CODE_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002985 err = pin_code_reply(sk, index, cp, len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002986 break;
2987 case MGMT_OP_PIN_CODE_NEG_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002988 err = pin_code_neg_reply(sk, index, cp, len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002989 break;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002990 case MGMT_OP_SET_IO_CAPABILITY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002991 err = set_io_capability(sk, index, cp, len);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002992 break;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002993 case MGMT_OP_PAIR_DEVICE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002994 err = pair_device(sk, index, cp, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002995 break;
Johan Hedberg28424702012-02-02 04:02:29 +02002996 case MGMT_OP_CANCEL_PAIR_DEVICE:
2997 err = cancel_pair_device(sk, index, buf + sizeof(*hdr), len);
2998 break;
Johan Hedberg124f6e32012-02-09 13:50:12 +02002999 case MGMT_OP_UNPAIR_DEVICE:
3000 err = unpair_device(sk, index, cp, len);
3001 break;
Johan Hedberga5c29682011-02-19 12:05:57 -03003002 case MGMT_OP_USER_CONFIRM_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003003 err = user_confirm_reply(sk, index, cp, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03003004 break;
3005 case MGMT_OP_USER_CONFIRM_NEG_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003006 err = user_confirm_neg_reply(sk, index, cp, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03003007 break;
Brian Gix604086b2011-11-23 08:28:33 -08003008 case MGMT_OP_USER_PASSKEY_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003009 err = user_passkey_reply(sk, index, cp, len);
Brian Gix604086b2011-11-23 08:28:33 -08003010 break;
3011 case MGMT_OP_USER_PASSKEY_NEG_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003012 err = user_passkey_neg_reply(sk, index, cp, len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003013 break;
Johan Hedbergb312b1612011-03-16 14:29:37 +02003014 case MGMT_OP_SET_LOCAL_NAME:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003015 err = set_local_name(sk, index, cp, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003016 break;
Szymon Jancc35938b2011-03-22 13:12:21 +01003017 case MGMT_OP_READ_LOCAL_OOB_DATA:
3018 err = read_local_oob_data(sk, index);
3019 break;
Szymon Janc2763eda2011-03-22 13:12:22 +01003020 case MGMT_OP_ADD_REMOTE_OOB_DATA:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003021 err = add_remote_oob_data(sk, index, cp, len);
Szymon Janc2763eda2011-03-22 13:12:22 +01003022 break;
3023 case MGMT_OP_REMOVE_REMOTE_OOB_DATA:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003024 err = remove_remote_oob_data(sk, index, cp, len);
Szymon Janc2763eda2011-03-22 13:12:22 +01003025 break;
Johan Hedberg14a53662011-04-27 10:29:56 -04003026 case MGMT_OP_START_DISCOVERY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003027 err = start_discovery(sk, index, cp, len);
Johan Hedberg14a53662011-04-27 10:29:56 -04003028 break;
3029 case MGMT_OP_STOP_DISCOVERY:
Johan Hedbergd9306502012-02-20 23:25:18 +02003030 err = stop_discovery(sk, index, cp, len);
Johan Hedberg14a53662011-04-27 10:29:56 -04003031 break;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003032 case MGMT_OP_CONFIRM_NAME:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003033 err = confirm_name(sk, index, cp, len);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003034 break;
Antti Julku7fbec222011-06-15 12:01:15 +03003035 case MGMT_OP_BLOCK_DEVICE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003036 err = block_device(sk, index, cp, len);
Antti Julku7fbec222011-06-15 12:01:15 +03003037 break;
3038 case MGMT_OP_UNBLOCK_DEVICE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003039 err = unblock_device(sk, index, cp, len);
Antti Julku7fbec222011-06-15 12:01:15 +03003040 break;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003041 case MGMT_OP_LOAD_LONG_TERM_KEYS:
3042 err = load_long_term_keys(sk, index, cp, len);
3043 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003044 default:
Johan Hedberg72a734e2010-12-30 00:38:22 +02003045 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02003046 err = cmd_status(sk, index, opcode,
3047 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003048 break;
3049 }
Johan Hedberg72a734e2010-12-30 00:38:22 +02003050
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003051 if (err < 0)
Johan Hedberg72a734e2010-12-30 00:38:22 +02003052 goto done;
3053
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003054 err = msglen;
3055
3056done:
3057 kfree(buf);
3058 return err;
3059}
3060
Johan Hedbergb24752f2011-11-03 14:40:33 +02003061static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
3062{
3063 u8 *status = data;
3064
3065 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
3066 mgmt_pending_remove(cmd);
3067}
3068
Johan Hedberg744cf192011-11-08 20:40:14 +02003069int mgmt_index_added(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +02003070{
Johan Hedberg744cf192011-11-08 20:40:14 +02003071 return mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02003072}
3073
Johan Hedberg744cf192011-11-08 20:40:14 +02003074int mgmt_index_removed(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +02003075{
Johan Hedbergb24752f2011-11-03 14:40:33 +02003076 u8 status = ENODEV;
3077
Johan Hedberg744cf192011-11-08 20:40:14 +02003078 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02003079
Johan Hedberg744cf192011-11-08 20:40:14 +02003080 return mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02003081}
3082
3083struct cmd_lookup {
Johan Hedberg03811012010-12-08 00:21:06 +02003084 struct sock *sk;
Johan Hedberg69ab39e2011-12-15 00:47:35 +02003085 struct hci_dev *hdev;
Johan Hedberg03811012010-12-08 00:21:06 +02003086};
3087
Johan Hedberg69ab39e2011-12-15 00:47:35 +02003088static void settings_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberg03811012010-12-08 00:21:06 +02003089{
Johan Hedberg03811012010-12-08 00:21:06 +02003090 struct cmd_lookup *match = data;
3091
Johan Hedberg69ab39e2011-12-15 00:47:35 +02003092 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02003093
3094 list_del(&cmd->list);
3095
3096 if (match->sk == NULL) {
3097 match->sk = cmd->sk;
3098 sock_hold(match->sk);
3099 }
3100
3101 mgmt_pending_free(cmd);
3102}
3103
Johan Hedberg744cf192011-11-08 20:40:14 +02003104int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg03811012010-12-08 00:21:06 +02003105{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02003106 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003107 int err;
Johan Hedberg03811012010-12-08 00:21:06 +02003108
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003109 if (!test_bit(HCI_MGMT, &hdev->dev_flags))
3110 return 0;
3111
Johan Hedberg69ab39e2011-12-15 00:47:35 +02003112 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
Johan Hedberg03811012010-12-08 00:21:06 +02003113
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003114 if (powered) {
3115 u8 scan = 0;
3116
3117 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3118 scan |= SCAN_PAGE;
3119 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3120 scan |= SCAN_INQUIRY;
3121
3122 if (scan)
3123 hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
3124 } else {
Johan Hedbergb24752f2011-11-03 14:40:33 +02003125 u8 status = ENETDOWN;
Johan Hedberg744cf192011-11-08 20:40:14 +02003126 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02003127 }
3128
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003129 err = new_settings(hdev, match.sk);
Johan Hedberg03811012010-12-08 00:21:06 +02003130
3131 if (match.sk)
3132 sock_put(match.sk);
3133
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003134 return err;
Johan Hedberg03811012010-12-08 00:21:06 +02003135}
3136
Johan Hedberg744cf192011-11-08 20:40:14 +02003137int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg03811012010-12-08 00:21:06 +02003138{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02003139 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003140 bool changed = false;
3141 int err = 0;
Johan Hedberg03811012010-12-08 00:21:06 +02003142
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003143 if (discoverable) {
3144 if (!test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3145 changed = true;
3146 } else {
3147 if (test_and_clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3148 changed = true;
3149 }
Johan Hedberg03811012010-12-08 00:21:06 +02003150
Johan Hedberged9b5f22012-02-21 20:47:06 +02003151 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp,
3152 &match);
3153
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003154 if (changed)
3155 err = new_settings(hdev, match.sk);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003156
Johan Hedberg03811012010-12-08 00:21:06 +02003157 if (match.sk)
3158 sock_put(match.sk);
3159
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003160 return err;
Johan Hedberg03811012010-12-08 00:21:06 +02003161}
3162
Johan Hedberg744cf192011-11-08 20:40:14 +02003163int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg03811012010-12-08 00:21:06 +02003164{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02003165 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003166 bool changed = false;
3167 int err = 0;
Johan Hedberg03811012010-12-08 00:21:06 +02003168
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003169 if (connectable) {
3170 if (!test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3171 changed = true;
3172 } else {
3173 if (test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3174 changed = true;
3175 }
Johan Hedberg03811012010-12-08 00:21:06 +02003176
Johan Hedberged9b5f22012-02-21 20:47:06 +02003177 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev, settings_rsp,
3178 &match);
3179
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003180 if (changed)
3181 err = new_settings(hdev, match.sk);
Johan Hedberg03811012010-12-08 00:21:06 +02003182
3183 if (match.sk)
3184 sock_put(match.sk);
3185
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003186 return err;
Johan Hedberg03811012010-12-08 00:21:06 +02003187}
3188
Johan Hedberg744cf192011-11-08 20:40:14 +02003189int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003190{
Johan Hedbergca69b792011-11-11 18:10:00 +02003191 u8 mgmt_err = mgmt_status(status);
3192
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003193 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02003194 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Johan Hedbergca69b792011-11-11 18:10:00 +02003195 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003196
3197 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02003198 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Johan Hedbergca69b792011-11-11 18:10:00 +02003199 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003200
3201 return 0;
3202}
3203
Johan Hedberg744cf192011-11-08 20:40:14 +02003204int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
3205 u8 persistent)
Johan Hedberg03811012010-12-08 00:21:06 +02003206{
Johan Hedberg86742e12011-11-07 23:13:38 +02003207 struct mgmt_ev_new_link_key ev;
Johan Hedberg03811012010-12-08 00:21:06 +02003208
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003209 memset(&ev, 0, sizeof(ev));
Johan Hedberg03811012010-12-08 00:21:06 +02003210
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003211 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02003212 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
3213 ev.key.addr.type = MGMT_ADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003214 ev.key.type = key->type;
3215 memcpy(ev.key.val, key->val, 16);
3216 ev.key.pin_len = key->pin_len;
Johan Hedberg03811012010-12-08 00:21:06 +02003217
Johan Hedberg744cf192011-11-08 20:40:14 +02003218 return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02003219}
Johan Hedbergf7520542011-01-20 12:34:39 +02003220
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003221int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
3222{
3223 struct mgmt_ev_new_long_term_key ev;
3224
3225 memset(&ev, 0, sizeof(ev));
3226
3227 ev.store_hint = persistent;
3228 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
3229 ev.key.addr.type = key->bdaddr_type;
3230 ev.key.authenticated = key->authenticated;
3231 ev.key.enc_size = key->enc_size;
3232 ev.key.ediv = key->ediv;
3233
3234 if (key->type == HCI_SMP_LTK)
3235 ev.key.master = 1;
3236
3237 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
3238 memcpy(ev.key.val, key->val, sizeof(key->val));
3239
3240 return mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev,
3241 &ev, sizeof(ev), NULL);
3242}
3243
Johan Hedbergafc747a2012-01-15 18:11:07 +02003244int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Johan Hedbergb644ba32012-01-17 21:48:47 +02003245 u8 addr_type, u8 *name, u8 name_len,
3246 u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02003247{
Johan Hedbergb644ba32012-01-17 21:48:47 +02003248 char buf[512];
3249 struct mgmt_ev_device_connected *ev = (void *) buf;
3250 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02003251
Johan Hedbergb644ba32012-01-17 21:48:47 +02003252 bacpy(&ev->addr.bdaddr, bdaddr);
3253 ev->addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02003254
Johan Hedbergb644ba32012-01-17 21:48:47 +02003255 if (name_len > 0)
3256 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
3257 name, name_len);
3258
3259 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
3260 eir_len = eir_append_data(&ev->eir[eir_len], eir_len,
3261 EIR_CLASS_OF_DEV, dev_class, 3);
3262
3263 put_unaligned_le16(eir_len, &ev->eir_len);
3264
3265 return mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
3266 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02003267}
3268
Johan Hedberg8962ee72011-01-20 12:40:27 +02003269static void disconnect_rsp(struct pending_cmd *cmd, void *data)
3270{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01003271 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003272 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02003273 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003274
Johan Hedberg88c3df12012-02-09 14:27:38 +02003275 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3276 rp.addr.type = cp->addr.type;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003277
Johan Hedbergaee9b212012-02-18 15:07:59 +02003278 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, 0, &rp,
3279 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003280
3281 *sk = cmd->sk;
3282 sock_hold(*sk);
3283
Johan Hedberga664b5b2011-02-19 12:06:02 -03003284 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003285}
3286
Johan Hedberg124f6e32012-02-09 13:50:12 +02003287static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02003288{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003289 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02003290 struct mgmt_cp_unpair_device *cp = cmd->param;
3291 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02003292
3293 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02003294 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3295 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02003296
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003297 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
3298
Johan Hedbergaee9b212012-02-18 15:07:59 +02003299 cmd_complete(cmd->sk, cmd->index, cmd->opcode, 0, &rp, sizeof(rp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02003300
3301 mgmt_pending_remove(cmd);
3302}
3303
Johan Hedbergafc747a2012-01-15 18:11:07 +02003304int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
3305 u8 link_type, u8 addr_type)
Johan Hedbergf7520542011-01-20 12:34:39 +02003306{
Johan Hedberg4c659c32011-11-07 23:13:39 +02003307 struct mgmt_addr_info ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003308 struct sock *sk = NULL;
3309 int err;
3310
Johan Hedberg744cf192011-11-08 20:40:14 +02003311 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02003312
Johan Hedbergf7520542011-01-20 12:34:39 +02003313 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02003314 ev.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02003315
Johan Hedbergafc747a2012-01-15 18:11:07 +02003316 err = mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev),
3317 sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003318
3319 if (sk)
3320 sock_put(sk);
3321
Johan Hedberg124f6e32012-02-09 13:50:12 +02003322 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003323 hdev);
Johan Hedberga8a1d192011-11-10 15:54:38 +02003324
Johan Hedberg8962ee72011-01-20 12:40:27 +02003325 return err;
3326}
3327
Johan Hedberg88c3df12012-02-09 14:27:38 +02003328int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
3329 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02003330{
Johan Hedberg88c3df12012-02-09 14:27:38 +02003331 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003332 struct pending_cmd *cmd;
3333 int err;
3334
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003335 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003336 if (!cmd)
3337 return -ENOENT;
3338
Johan Hedberg88c3df12012-02-09 14:27:38 +02003339 bacpy(&rp.addr.bdaddr, bdaddr);
3340 rp.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02003341
Johan Hedberg88c3df12012-02-09 14:27:38 +02003342 err = cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
Johan Hedbergaee9b212012-02-18 15:07:59 +02003343 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003344
Johan Hedberga664b5b2011-02-19 12:06:02 -03003345 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003346
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003347 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
3348 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003349 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02003350}
Johan Hedberg17d5c042011-01-22 06:09:08 +02003351
Johan Hedberg48264f02011-11-09 13:58:58 +02003352int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
3353 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02003354{
3355 struct mgmt_ev_connect_failed ev;
3356
Johan Hedberg4c659c32011-11-07 23:13:39 +02003357 bacpy(&ev.addr.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02003358 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003359 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003360
Johan Hedberg744cf192011-11-08 20:40:14 +02003361 return mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003362}
Johan Hedberg980e1a52011-01-22 06:10:07 +02003363
Johan Hedberg744cf192011-11-08 20:40:14 +02003364int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003365{
3366 struct mgmt_ev_pin_code_request ev;
3367
Johan Hedbergd8457692012-02-17 14:24:57 +02003368 bacpy(&ev.addr.bdaddr, bdaddr);
3369 ev.addr.type = MGMT_ADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02003370 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003371
Johan Hedberg744cf192011-11-08 20:40:14 +02003372 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01003373 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003374}
3375
Johan Hedberg744cf192011-11-08 20:40:14 +02003376int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3377 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003378{
3379 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003380 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003381 int err;
3382
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003383 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003384 if (!cmd)
3385 return -ENOENT;
3386
Johan Hedbergd8457692012-02-17 14:24:57 +02003387 bacpy(&rp.addr.bdaddr, bdaddr);
3388 rp.addr.type = MGMT_ADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003389
Johan Hedbergaee9b212012-02-18 15:07:59 +02003390 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
3391 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003392
Johan Hedberga664b5b2011-02-19 12:06:02 -03003393 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003394
3395 return err;
3396}
3397
Johan Hedberg744cf192011-11-08 20:40:14 +02003398int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3399 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003400{
3401 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003402 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003403 int err;
3404
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003405 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003406 if (!cmd)
3407 return -ENOENT;
3408
Johan Hedbergd8457692012-02-17 14:24:57 +02003409 bacpy(&rp.addr.bdaddr, bdaddr);
3410 rp.addr.type = MGMT_ADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003411
Johan Hedbergaee9b212012-02-18 15:07:59 +02003412 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
3413 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003414
Johan Hedberga664b5b2011-02-19 12:06:02 -03003415 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003416
3417 return err;
3418}
Johan Hedberga5c29682011-02-19 12:05:57 -03003419
Johan Hedberg744cf192011-11-08 20:40:14 +02003420int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003421 u8 link_type, u8 addr_type, __le32 value,
3422 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03003423{
3424 struct mgmt_ev_user_confirm_request ev;
3425
Johan Hedberg744cf192011-11-08 20:40:14 +02003426 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03003427
Johan Hedberg272d90d2012-02-09 15:26:12 +02003428 bacpy(&ev.addr.bdaddr, bdaddr);
3429 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07003430 ev.confirm_hint = confirm_hint;
Johan Hedberga5c29682011-02-19 12:05:57 -03003431 put_unaligned_le32(value, &ev.value);
3432
Johan Hedberg744cf192011-11-08 20:40:14 +02003433 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01003434 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03003435}
3436
Johan Hedberg272d90d2012-02-09 15:26:12 +02003437int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
3438 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08003439{
3440 struct mgmt_ev_user_passkey_request ev;
3441
3442 BT_DBG("%s", hdev->name);
3443
Johan Hedberg272d90d2012-02-09 15:26:12 +02003444 bacpy(&ev.addr.bdaddr, bdaddr);
3445 ev.addr.type = link_to_mgmt(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08003446
3447 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
3448 NULL);
3449}
3450
Brian Gix0df4c182011-11-16 13:53:13 -08003451static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003452 u8 link_type, u8 addr_type, u8 status,
3453 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03003454{
3455 struct pending_cmd *cmd;
3456 struct mgmt_rp_user_confirm_reply rp;
3457 int err;
3458
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003459 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03003460 if (!cmd)
3461 return -ENOENT;
3462
Johan Hedberg272d90d2012-02-09 15:26:12 +02003463 bacpy(&rp.addr.bdaddr, bdaddr);
3464 rp.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergaee9b212012-02-18 15:07:59 +02003465 err = cmd_complete(cmd->sk, hdev->id, opcode, mgmt_status(status),
3466 &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03003467
Johan Hedberga664b5b2011-02-19 12:06:02 -03003468 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03003469
3470 return err;
3471}
3472
Johan Hedberg744cf192011-11-08 20:40:14 +02003473int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003474 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003475{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003476 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3477 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003478}
3479
Johan Hedberg272d90d2012-02-09 15:26:12 +02003480int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3481 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003482{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003483 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3484 status, MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003485}
Johan Hedberg2a611692011-02-19 12:06:00 -03003486
Brian Gix604086b2011-11-23 08:28:33 -08003487int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003488 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003489{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003490 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3491 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003492}
3493
Johan Hedberg272d90d2012-02-09 15:26:12 +02003494int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3495 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003496{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003497 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3498 status, MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003499}
3500
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003501int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
3502 u8 addr_type, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03003503{
3504 struct mgmt_ev_auth_failed ev;
3505
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003506 bacpy(&ev.addr.bdaddr, bdaddr);
3507 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003508 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03003509
Johan Hedberg744cf192011-11-08 20:40:14 +02003510 return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03003511}
Johan Hedbergb312b1612011-03-16 14:29:37 +02003512
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003513int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
3514{
3515 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg47990ea2012-02-22 11:58:37 +02003516 bool changed = false;
3517 int err = 0;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003518
3519 if (status) {
3520 u8 mgmt_err = mgmt_status(status);
3521 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
3522 cmd_status_rsp, &mgmt_err);
3523 return 0;
3524 }
3525
Johan Hedberg47990ea2012-02-22 11:58:37 +02003526 if (test_bit(HCI_AUTH, &hdev->flags)) {
3527 if (!test_and_set_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
3528 changed = true;
3529 } else {
3530 if (test_and_clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
3531 changed = true;
3532 }
3533
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003534 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
3535 &match);
3536
Johan Hedberg47990ea2012-02-22 11:58:37 +02003537 if (changed)
3538 err = new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003539
3540 if (match.sk)
3541 sock_put(match.sk);
3542
3543 return err;
3544}
3545
Johan Hedbergcacaf522012-02-21 00:52:42 +02003546static int clear_eir(struct hci_dev *hdev)
3547{
3548 struct hci_cp_write_eir cp;
3549
3550 if (!(hdev->features[6] & LMP_EXT_INQ))
3551 return 0;
3552
Johan Hedbergc80da272012-02-22 15:38:48 +02003553 memset(hdev->eir, 0, sizeof(hdev->eir));
3554
Johan Hedbergcacaf522012-02-21 00:52:42 +02003555 memset(&cp, 0, sizeof(cp));
3556
3557 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
3558}
3559
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003560int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003561{
3562 struct cmd_lookup match = { NULL, hdev };
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003563 bool changed = false;
3564 int err = 0;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003565
3566 if (status) {
3567 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003568
3569 if (enable && test_and_clear_bit(HCI_SSP_ENABLED,
3570 &hdev->dev_flags))
3571 err = new_settings(hdev, NULL);
3572
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003573 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev,
3574 cmd_status_rsp, &mgmt_err);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003575
3576 return err;
3577 }
3578
3579 if (enable) {
3580 if (!test_and_set_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3581 changed = true;
3582 } else {
3583 if (test_and_clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3584 changed = true;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003585 }
3586
3587 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
3588
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003589 if (changed)
3590 err = new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003591
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02003592 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003593 sock_put(match.sk);
3594
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02003595 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3596 update_eir(hdev);
3597 else
3598 clear_eir(hdev);
Johan Hedbergcacaf522012-02-21 00:52:42 +02003599
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003600 return err;
3601}
3602
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003603int mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
3604 u8 status)
3605{
3606 int err;
3607
3608 err = mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class, 3, NULL);
3609
3610 return err;
3611}
3612
Johan Hedberg744cf192011-11-08 20:40:14 +02003613int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02003614{
3615 struct pending_cmd *cmd;
3616 struct mgmt_cp_set_local_name ev;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003617 bool changed = false;
3618 int err = 0;
3619
3620 if (memcmp(name, hdev->dev_name, sizeof(hdev->dev_name)) != 0) {
3621 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
3622 changed = true;
3623 }
Johan Hedbergb312b1612011-03-16 14:29:37 +02003624
3625 memset(&ev, 0, sizeof(ev));
3626 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003627 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003628
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003629 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003630 if (!cmd)
3631 goto send_event;
3632
Johan Hedberg7bdaae42012-02-22 21:39:58 +02003633 /* Always assume that either the short or the complete name has
3634 * changed if there was a pending mgmt command */
3635 changed = true;
3636
Johan Hedbergb312b1612011-03-16 14:29:37 +02003637 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02003638 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
Johan Hedbergca69b792011-11-11 18:10:00 +02003639 mgmt_status(status));
Johan Hedbergb312b1612011-03-16 14:29:37 +02003640 goto failed;
3641 }
3642
Johan Hedbergaee9b212012-02-18 15:07:59 +02003643 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0, &ev,
Johan Hedbergb312b1612011-03-16 14:29:37 +02003644 sizeof(ev));
3645 if (err < 0)
3646 goto failed;
3647
3648send_event:
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003649 if (changed)
3650 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev,
3651 sizeof(ev), cmd ? cmd->sk : NULL);
3652
Johan Hedbergf51d5b22012-02-22 18:17:32 +02003653 update_eir(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003654
3655failed:
3656 if (cmd)
3657 mgmt_pending_remove(cmd);
3658 return err;
3659}
Szymon Jancc35938b2011-03-22 13:12:21 +01003660
Johan Hedberg744cf192011-11-08 20:40:14 +02003661int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
3662 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01003663{
3664 struct pending_cmd *cmd;
3665 int err;
3666
Johan Hedberg744cf192011-11-08 20:40:14 +02003667 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01003668
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003669 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003670 if (!cmd)
3671 return -ENOENT;
3672
3673 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02003674 err = cmd_status(cmd->sk, hdev->id,
Johan Hedbergca69b792011-11-11 18:10:00 +02003675 MGMT_OP_READ_LOCAL_OOB_DATA,
3676 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01003677 } else {
3678 struct mgmt_rp_read_local_oob_data rp;
3679
3680 memcpy(rp.hash, hash, sizeof(rp.hash));
3681 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
3682
Johan Hedberg744cf192011-11-08 20:40:14 +02003683 err = cmd_complete(cmd->sk, hdev->id,
3684 MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergaee9b212012-02-18 15:07:59 +02003685 0, &rp, sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01003686 }
3687
3688 mgmt_pending_remove(cmd);
3689
3690 return err;
3691}
Johan Hedberge17acd42011-03-30 23:57:16 +03003692
Johan Hedberg06199cf2012-02-22 16:37:11 +02003693int mgmt_le_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
3694{
3695 struct cmd_lookup match = { NULL, hdev };
3696 bool changed = false;
3697 int err = 0;
3698
3699 if (status) {
3700 u8 mgmt_err = mgmt_status(status);
3701
3702 if (enable && test_and_clear_bit(HCI_LE_ENABLED,
3703 &hdev->dev_flags))
3704 err = new_settings(hdev, NULL);
3705
3706 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev,
3707 cmd_status_rsp, &mgmt_err);
3708
3709 return err;
3710 }
3711
3712 if (enable) {
3713 if (!test_and_set_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3714 changed = true;
3715 } else {
3716 if (test_and_clear_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3717 changed = true;
3718 }
3719
3720 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
3721
3722 if (changed)
3723 err = new_settings(hdev, match.sk);
3724
3725 if (match.sk)
3726 sock_put(match.sk);
3727
3728 return err;
3729}
3730
Johan Hedberg48264f02011-11-09 13:58:58 +02003731int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Johan Hedberg561aafb2012-01-04 13:31:59 +02003732 u8 addr_type, u8 *dev_class, s8 rssi,
Johan Hedberge319d2e2012-01-15 19:51:59 +02003733 u8 cfm_name, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03003734{
Johan Hedberge319d2e2012-01-15 19:51:59 +02003735 char buf[512];
3736 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02003737 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03003738
Johan Hedberg1dc06092012-01-15 21:01:23 +02003739 /* Leave 5 bytes for a potential CoD field */
3740 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Andre Guedes7d262f82012-01-10 18:20:49 -03003741 return -EINVAL;
3742
Johan Hedberg1dc06092012-01-15 21:01:23 +02003743 memset(buf, 0, sizeof(buf));
3744
Johan Hedberge319d2e2012-01-15 19:51:59 +02003745 bacpy(&ev->addr.bdaddr, bdaddr);
3746 ev->addr.type = link_to_mgmt(link_type, addr_type);
3747 ev->rssi = rssi;
3748 ev->confirm_name = cfm_name;
Johan Hedberge17acd42011-03-30 23:57:16 +03003749
Johan Hedberg1dc06092012-01-15 21:01:23 +02003750 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02003751 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03003752
Johan Hedberg1dc06092012-01-15 21:01:23 +02003753 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
3754 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
3755 dev_class, 3);
3756
3757 put_unaligned_le16(eir_len, &ev->eir_len);
3758
3759 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03003760
Johan Hedberge319d2e2012-01-15 19:51:59 +02003761 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03003762}
Johan Hedberga88a9652011-03-30 13:18:12 +03003763
Johan Hedbergb644ba32012-01-17 21:48:47 +02003764int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
3765 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03003766{
Johan Hedbergb644ba32012-01-17 21:48:47 +02003767 struct mgmt_ev_device_found *ev;
3768 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
3769 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03003770
Johan Hedbergb644ba32012-01-17 21:48:47 +02003771 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03003772
Johan Hedbergb644ba32012-01-17 21:48:47 +02003773 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03003774
Johan Hedbergb644ba32012-01-17 21:48:47 +02003775 bacpy(&ev->addr.bdaddr, bdaddr);
3776 ev->addr.type = link_to_mgmt(link_type, addr_type);
3777 ev->rssi = rssi;
3778
3779 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
3780 name_len);
3781
3782 put_unaligned_le16(eir_len, &ev->eir_len);
3783
Johan Hedberg053c7e02012-02-04 00:06:00 +02003784 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev,
3785 sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03003786}
Johan Hedberg314b2382011-04-27 10:29:57 -04003787
Andre Guedes7a135102011-11-09 17:14:25 -03003788int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
Johan Hedberg164a6e72011-11-01 17:06:44 +02003789{
3790 struct pending_cmd *cmd;
Johan Hedbergf808e162012-02-19 12:52:07 +02003791 u8 type;
Johan Hedberg164a6e72011-11-01 17:06:44 +02003792 int err;
3793
Andre Guedes203159d2012-02-13 15:41:01 -03003794 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3795
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003796 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003797 if (!cmd)
3798 return -ENOENT;
3799
Johan Hedbergf808e162012-02-19 12:52:07 +02003800 type = hdev->discovery.type;
3801
3802 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
3803 &type, sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02003804 mgmt_pending_remove(cmd);
3805
3806 return err;
3807}
3808
Andre Guedese6d465c2011-11-09 17:14:26 -03003809int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
3810{
3811 struct pending_cmd *cmd;
3812 int err;
3813
3814 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
3815 if (!cmd)
3816 return -ENOENT;
3817
Johan Hedbergd9306502012-02-20 23:25:18 +02003818 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
3819 &hdev->discovery.type,
3820 sizeof(hdev->discovery.type));
Johan Hedberg03811012010-12-08 00:21:06 +02003821 mgmt_pending_remove(cmd);
3822
3823 return err;
3824}
Johan Hedberg314b2382011-04-27 10:29:57 -04003825
Johan Hedberg744cf192011-11-08 20:40:14 +02003826int mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04003827{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02003828 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02003829 struct pending_cmd *cmd;
3830
Andre Guedes343fb142011-11-22 17:14:19 -03003831 BT_DBG("%s discovering %u", hdev->name, discovering);
3832
Johan Hedberg164a6e72011-11-01 17:06:44 +02003833 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003834 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003835 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003836 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003837
3838 if (cmd != NULL) {
Johan Hedbergf808e162012-02-19 12:52:07 +02003839 u8 type = hdev->discovery.type;
3840
Johan Hedbergd9306502012-02-20 23:25:18 +02003841 cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0,
Johan Hedbergf808e162012-02-19 12:52:07 +02003842 &type, sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02003843 mgmt_pending_remove(cmd);
3844 }
3845
Johan Hedbergf963e8e2012-02-20 23:30:44 +02003846 memset(&ev, 0, sizeof(ev));
3847 ev.type = hdev->discovery.type;
3848 ev.discovering = discovering;
3849
3850 return mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04003851}
Antti Julku5e762442011-08-25 16:48:02 +03003852
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003853int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003854{
3855 struct pending_cmd *cmd;
3856 struct mgmt_ev_device_blocked ev;
3857
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003858 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003859
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003860 bacpy(&ev.addr.bdaddr, bdaddr);
3861 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003862
Johan Hedberg744cf192011-11-08 20:40:14 +02003863 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
3864 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003865}
3866
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003867int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003868{
3869 struct pending_cmd *cmd;
3870 struct mgmt_ev_device_unblocked ev;
3871
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003872 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003873
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003874 bacpy(&ev.addr.bdaddr, bdaddr);
3875 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003876
Johan Hedberg744cf192011-11-08 20:40:14 +02003877 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
3878 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003879}
Marcel Holtmannd7b7e792012-02-20 21:47:49 +01003880
3881module_param(enable_hs, bool, 0644);
3882MODULE_PARM_DESC(enable_hs, "Enable High Speed support");
3883
3884module_param(enable_le, bool, 0644);
3885MODULE_PARM_DESC(enable_le, "Enable Low Energy support");