blob: 30a30b7b301ce18165b97801f94b2a7619146967 [file] [log] [blame]
Johan Hedberg03811012010-12-08 00:21:06 +02001/*
2 BlueZ - Bluetooth protocol stack for Linux
Johan Hedbergea585ab2012-02-17 14:50:39 +02003
Johan Hedberg03811012010-12-08 00:21:06 +02004 Copyright (C) 2010 Nokia Corporation
Johan Hedbergea585ab2012-02-17 14:50:39 +02005 Copyright (C) 2011-2012 Intel Corporation
Johan Hedberg03811012010-12-08 00:21:06 +02006
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License version 2 as
9 published by the Free Software Foundation;
10
11 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
12 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
13 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
14 IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
15 CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
16 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19
20 ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
21 COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
22 SOFTWARE IS DISCLAIMED.
23*/
24
25/* Bluetooth HCI Management interface */
26
Johan Hedbergca69b792011-11-11 18:10:00 +020027#include <linux/kernel.h>
Szymon Janc72359752011-02-17 14:16:32 +010028#include <linux/uaccess.h>
Paul Gortmaker3a9a2312011-05-27 09:12:25 -040029#include <linux/module.h>
Johan Hedberg03811012010-12-08 00:21:06 +020030#include <asm/unaligned.h>
31
32#include <net/bluetooth/bluetooth.h>
33#include <net/bluetooth/hci_core.h>
34#include <net/bluetooth/mgmt.h>
Brian Gix5fe57d92011-12-21 16:12:13 -080035#include <net/bluetooth/smp.h>
Johan Hedberg03811012010-12-08 00:21:06 +020036
Marcel Holtmannd7b7e792012-02-20 21:47:49 +010037bool enable_hs;
38bool enable_le;
39
Johan Hedberg2da9c552012-02-17 14:39:28 +020040#define MGMT_VERSION 1
41#define MGMT_REVISION 0
Johan Hedberg02d98122010-12-13 21:07:04 +020042
Johan Hedberge70bb2e2012-02-13 16:59:33 +020043static const u16 mgmt_commands[] = {
44 MGMT_OP_READ_INDEX_LIST,
45 MGMT_OP_READ_INFO,
46 MGMT_OP_SET_POWERED,
47 MGMT_OP_SET_DISCOVERABLE,
48 MGMT_OP_SET_CONNECTABLE,
49 MGMT_OP_SET_FAST_CONNECTABLE,
50 MGMT_OP_SET_PAIRABLE,
51 MGMT_OP_SET_LINK_SECURITY,
52 MGMT_OP_SET_SSP,
53 MGMT_OP_SET_HS,
54 MGMT_OP_SET_LE,
55 MGMT_OP_SET_DEV_CLASS,
56 MGMT_OP_SET_LOCAL_NAME,
57 MGMT_OP_ADD_UUID,
58 MGMT_OP_REMOVE_UUID,
59 MGMT_OP_LOAD_LINK_KEYS,
60 MGMT_OP_LOAD_LONG_TERM_KEYS,
61 MGMT_OP_DISCONNECT,
62 MGMT_OP_GET_CONNECTIONS,
63 MGMT_OP_PIN_CODE_REPLY,
64 MGMT_OP_PIN_CODE_NEG_REPLY,
65 MGMT_OP_SET_IO_CAPABILITY,
66 MGMT_OP_PAIR_DEVICE,
67 MGMT_OP_CANCEL_PAIR_DEVICE,
68 MGMT_OP_UNPAIR_DEVICE,
69 MGMT_OP_USER_CONFIRM_REPLY,
70 MGMT_OP_USER_CONFIRM_NEG_REPLY,
71 MGMT_OP_USER_PASSKEY_REPLY,
72 MGMT_OP_USER_PASSKEY_NEG_REPLY,
73 MGMT_OP_READ_LOCAL_OOB_DATA,
74 MGMT_OP_ADD_REMOTE_OOB_DATA,
75 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
76 MGMT_OP_START_DISCOVERY,
77 MGMT_OP_STOP_DISCOVERY,
78 MGMT_OP_CONFIRM_NAME,
79 MGMT_OP_BLOCK_DEVICE,
80 MGMT_OP_UNBLOCK_DEVICE,
81};
82
83static const u16 mgmt_events[] = {
84 MGMT_EV_CONTROLLER_ERROR,
85 MGMT_EV_INDEX_ADDED,
86 MGMT_EV_INDEX_REMOVED,
87 MGMT_EV_NEW_SETTINGS,
88 MGMT_EV_CLASS_OF_DEV_CHANGED,
89 MGMT_EV_LOCAL_NAME_CHANGED,
90 MGMT_EV_NEW_LINK_KEY,
91 MGMT_EV_NEW_LONG_TERM_KEY,
92 MGMT_EV_DEVICE_CONNECTED,
93 MGMT_EV_DEVICE_DISCONNECTED,
94 MGMT_EV_CONNECT_FAILED,
95 MGMT_EV_PIN_CODE_REQUEST,
96 MGMT_EV_USER_CONFIRM_REQUEST,
97 MGMT_EV_USER_PASSKEY_REQUEST,
98 MGMT_EV_AUTH_FAILED,
99 MGMT_EV_DEVICE_FOUND,
100 MGMT_EV_DISCOVERING,
101 MGMT_EV_DEVICE_BLOCKED,
102 MGMT_EV_DEVICE_UNBLOCKED,
103 MGMT_EV_DEVICE_UNPAIRED,
104};
105
Andre Guedes3fd24152012-02-03 17:48:01 -0300106/*
107 * These LE scan and inquiry parameters were chosen according to LE General
108 * Discovery Procedure specification.
109 */
110#define LE_SCAN_TYPE 0x01
111#define LE_SCAN_WIN 0x12
112#define LE_SCAN_INT 0x12
113#define LE_SCAN_TIMEOUT_LE_ONLY 10240 /* TGAP(gen_disc_scan_min) */
Andre Guedes5e0452c2012-02-17 20:39:38 -0300114#define LE_SCAN_TIMEOUT_BREDR_LE 5120 /* TGAP(100)/2 */
Andre Guedes3fd24152012-02-03 17:48:01 -0300115
Andre Guedese8777522012-02-03 17:48:02 -0300116#define INQUIRY_LEN_BREDR 0x08 /* TGAP(100) */
Andre Guedes5e0452c2012-02-17 20:39:38 -0300117#define INQUIRY_LEN_BREDR_LE 0x04 /* TGAP(100)/2 */
Andre Guedes2519a1f2011-11-07 11:45:24 -0300118
Johan Hedberg7d785252011-12-15 00:47:39 +0200119#define SERVICE_CACHE_TIMEOUT (5 * 1000)
120
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200121#define hdev_is_powered(hdev) (test_bit(HCI_UP, &hdev->flags) && \
122 !test_bit(HCI_AUTO_OFF, &hdev->dev_flags))
123
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200124struct pending_cmd {
125 struct list_head list;
Johan Hedbergfc2f4b12011-11-09 13:58:56 +0200126 u16 opcode;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200127 int index;
Szymon Jancc68fb7f2011-03-22 13:12:19 +0100128 void *param;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200129 struct sock *sk;
Johan Hedberge9a416b2011-02-19 12:05:56 -0300130 void *user_data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200131};
132
Johan Hedbergca69b792011-11-11 18:10:00 +0200133/* HCI to MGMT error code conversion table */
134static u8 mgmt_status_table[] = {
135 MGMT_STATUS_SUCCESS,
136 MGMT_STATUS_UNKNOWN_COMMAND, /* Unknown Command */
137 MGMT_STATUS_NOT_CONNECTED, /* No Connection */
138 MGMT_STATUS_FAILED, /* Hardware Failure */
139 MGMT_STATUS_CONNECT_FAILED, /* Page Timeout */
140 MGMT_STATUS_AUTH_FAILED, /* Authentication Failed */
141 MGMT_STATUS_NOT_PAIRED, /* PIN or Key Missing */
142 MGMT_STATUS_NO_RESOURCES, /* Memory Full */
143 MGMT_STATUS_TIMEOUT, /* Connection Timeout */
144 MGMT_STATUS_NO_RESOURCES, /* Max Number of Connections */
145 MGMT_STATUS_NO_RESOURCES, /* Max Number of SCO Connections */
146 MGMT_STATUS_ALREADY_CONNECTED, /* ACL Connection Exists */
147 MGMT_STATUS_BUSY, /* Command Disallowed */
148 MGMT_STATUS_NO_RESOURCES, /* Rejected Limited Resources */
149 MGMT_STATUS_REJECTED, /* Rejected Security */
150 MGMT_STATUS_REJECTED, /* Rejected Personal */
151 MGMT_STATUS_TIMEOUT, /* Host Timeout */
152 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Feature */
153 MGMT_STATUS_INVALID_PARAMS, /* Invalid Parameters */
154 MGMT_STATUS_DISCONNECTED, /* OE User Ended Connection */
155 MGMT_STATUS_NO_RESOURCES, /* OE Low Resources */
156 MGMT_STATUS_DISCONNECTED, /* OE Power Off */
157 MGMT_STATUS_DISCONNECTED, /* Connection Terminated */
158 MGMT_STATUS_BUSY, /* Repeated Attempts */
159 MGMT_STATUS_REJECTED, /* Pairing Not Allowed */
160 MGMT_STATUS_FAILED, /* Unknown LMP PDU */
161 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Remote Feature */
162 MGMT_STATUS_REJECTED, /* SCO Offset Rejected */
163 MGMT_STATUS_REJECTED, /* SCO Interval Rejected */
164 MGMT_STATUS_REJECTED, /* Air Mode Rejected */
165 MGMT_STATUS_INVALID_PARAMS, /* Invalid LMP Parameters */
166 MGMT_STATUS_FAILED, /* Unspecified Error */
167 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported LMP Parameter Value */
168 MGMT_STATUS_FAILED, /* Role Change Not Allowed */
169 MGMT_STATUS_TIMEOUT, /* LMP Response Timeout */
170 MGMT_STATUS_FAILED, /* LMP Error Transaction Collision */
171 MGMT_STATUS_FAILED, /* LMP PDU Not Allowed */
172 MGMT_STATUS_REJECTED, /* Encryption Mode Not Accepted */
173 MGMT_STATUS_FAILED, /* Unit Link Key Used */
174 MGMT_STATUS_NOT_SUPPORTED, /* QoS Not Supported */
175 MGMT_STATUS_TIMEOUT, /* Instant Passed */
176 MGMT_STATUS_NOT_SUPPORTED, /* Pairing Not Supported */
177 MGMT_STATUS_FAILED, /* Transaction Collision */
178 MGMT_STATUS_INVALID_PARAMS, /* Unacceptable Parameter */
179 MGMT_STATUS_REJECTED, /* QoS Rejected */
180 MGMT_STATUS_NOT_SUPPORTED, /* Classification Not Supported */
181 MGMT_STATUS_REJECTED, /* Insufficient Security */
182 MGMT_STATUS_INVALID_PARAMS, /* Parameter Out Of Range */
183 MGMT_STATUS_BUSY, /* Role Switch Pending */
184 MGMT_STATUS_FAILED, /* Slot Violation */
185 MGMT_STATUS_FAILED, /* Role Switch Failed */
186 MGMT_STATUS_INVALID_PARAMS, /* EIR Too Large */
187 MGMT_STATUS_NOT_SUPPORTED, /* Simple Pairing Not Supported */
188 MGMT_STATUS_BUSY, /* Host Busy Pairing */
189 MGMT_STATUS_REJECTED, /* Rejected, No Suitable Channel */
190 MGMT_STATUS_BUSY, /* Controller Busy */
191 MGMT_STATUS_INVALID_PARAMS, /* Unsuitable Connection Interval */
192 MGMT_STATUS_TIMEOUT, /* Directed Advertising Timeout */
193 MGMT_STATUS_AUTH_FAILED, /* Terminated Due to MIC Failure */
194 MGMT_STATUS_CONNECT_FAILED, /* Connection Establishment Failed */
195 MGMT_STATUS_CONNECT_FAILED, /* MAC Connection Failed */
196};
197
198static u8 mgmt_status(u8 hci_status)
199{
200 if (hci_status < ARRAY_SIZE(mgmt_status_table))
201 return mgmt_status_table[hci_status];
202
203 return MGMT_STATUS_FAILED;
204}
205
Szymon Janc4e51eae2011-02-25 19:05:48 +0100206static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200207{
208 struct sk_buff *skb;
209 struct mgmt_hdr *hdr;
210 struct mgmt_ev_cmd_status *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300211 int err;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200212
Szymon Janc34eb5252011-02-28 14:10:08 +0100213 BT_DBG("sock %p, index %u, cmd %u, status %u", sk, index, cmd, status);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200214
215 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_ATOMIC);
216 if (!skb)
217 return -ENOMEM;
218
219 hdr = (void *) skb_put(skb, sizeof(*hdr));
220
221 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_STATUS);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100222 hdr->index = cpu_to_le16(index);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200223 hdr->len = cpu_to_le16(sizeof(*ev));
224
225 ev = (void *) skb_put(skb, sizeof(*ev));
226 ev->status = status;
227 put_unaligned_le16(cmd, &ev->opcode);
228
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300229 err = sock_queue_rcv_skb(sk, skb);
230 if (err < 0)
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200231 kfree_skb(skb);
232
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300233 return err;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200234}
235
Johan Hedbergaee9b212012-02-18 15:07:59 +0200236static int cmd_complete(struct sock *sk, u16 index, u16 cmd, u8 status,
237 void *rp, size_t rp_len)
Johan Hedberg02d98122010-12-13 21:07:04 +0200238{
239 struct sk_buff *skb;
240 struct mgmt_hdr *hdr;
241 struct mgmt_ev_cmd_complete *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300242 int err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200243
244 BT_DBG("sock %p", sk);
245
Johan Hedberga38528f2011-01-22 06:46:43 +0200246 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + rp_len, GFP_ATOMIC);
Johan Hedberg02d98122010-12-13 21:07:04 +0200247 if (!skb)
248 return -ENOMEM;
249
250 hdr = (void *) skb_put(skb, sizeof(*hdr));
Johan Hedberga38528f2011-01-22 06:46:43 +0200251
Johan Hedberg02d98122010-12-13 21:07:04 +0200252 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100253 hdr->index = cpu_to_le16(index);
Johan Hedberga38528f2011-01-22 06:46:43 +0200254 hdr->len = cpu_to_le16(sizeof(*ev) + rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200255
Johan Hedberga38528f2011-01-22 06:46:43 +0200256 ev = (void *) skb_put(skb, sizeof(*ev) + rp_len);
257 put_unaligned_le16(cmd, &ev->opcode);
Johan Hedbergaee9b212012-02-18 15:07:59 +0200258 ev->status = status;
Szymon Janc8020c162011-02-28 14:09:50 +0100259
260 if (rp)
261 memcpy(ev->data, rp, rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200262
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300263 err = sock_queue_rcv_skb(sk, skb);
264 if (err < 0)
Johan Hedberg02d98122010-12-13 21:07:04 +0200265 kfree_skb(skb);
266
Marcel Holtmanne5f0e152012-02-22 11:59:01 +0100267 return err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200268}
269
Johan Hedberga38528f2011-01-22 06:46:43 +0200270static int read_version(struct sock *sk)
271{
272 struct mgmt_rp_read_version rp;
273
274 BT_DBG("sock %p", sk);
275
276 rp.version = MGMT_VERSION;
277 put_unaligned_le16(MGMT_REVISION, &rp.revision);
278
Johan Hedbergaee9b212012-02-18 15:07:59 +0200279 return cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, 0, &rp,
Szymon Janc4e51eae2011-02-25 19:05:48 +0100280 sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200281}
282
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200283static int read_commands(struct sock *sk)
284{
285 struct mgmt_rp_read_commands *rp;
286 u16 num_commands = ARRAY_SIZE(mgmt_commands);
287 u16 num_events = ARRAY_SIZE(mgmt_events);
288 u16 *opcode;
289 size_t rp_size;
290 int i, err;
291
292 BT_DBG("sock %p", sk);
293
294 rp_size = sizeof(*rp) + ((num_commands + num_events) * sizeof(u16));
295
296 rp = kmalloc(rp_size, GFP_KERNEL);
297 if (!rp)
298 return -ENOMEM;
299
300 put_unaligned_le16(num_commands, &rp->num_commands);
301 put_unaligned_le16(num_events, &rp->num_events);
302
303 for (i = 0, opcode = rp->opcodes; i < num_commands; i++, opcode++)
304 put_unaligned_le16(mgmt_commands[i], opcode);
305
306 for (i = 0; i < num_events; i++, opcode++)
307 put_unaligned_le16(mgmt_events[i], opcode);
308
Johan Hedbergaee9b212012-02-18 15:07:59 +0200309 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_COMMANDS, 0, rp,
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200310 rp_size);
311 kfree(rp);
312
313 return err;
314}
315
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200316static int read_index_list(struct sock *sk)
317{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200318 struct mgmt_rp_read_index_list *rp;
319 struct list_head *p;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200320 struct hci_dev *d;
Johan Hedberga38528f2011-01-22 06:46:43 +0200321 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200322 u16 count;
Johan Hedberga38528f2011-01-22 06:46:43 +0200323 int i, err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200324
325 BT_DBG("sock %p", sk);
326
327 read_lock(&hci_dev_list_lock);
328
329 count = 0;
330 list_for_each(p, &hci_dev_list) {
331 count++;
332 }
333
Johan Hedberga38528f2011-01-22 06:46:43 +0200334 rp_len = sizeof(*rp) + (2 * count);
335 rp = kmalloc(rp_len, GFP_ATOMIC);
336 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100337 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200338 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100339 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200340
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200341 put_unaligned_le16(count, &rp->num_controllers);
342
343 i = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200344 list_for_each_entry(d, &hci_dev_list, list) {
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200345 if (test_bit(HCI_SETUP, &d->dev_flags))
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200346 continue;
347
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200348 put_unaligned_le16(d->id, &rp->index[i++]);
349 BT_DBG("Added hci%u", d->id);
350 }
351
352 read_unlock(&hci_dev_list_lock);
353
Johan Hedbergaee9b212012-02-18 15:07:59 +0200354 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST, 0, rp,
Szymon Janc4e51eae2011-02-25 19:05:48 +0100355 rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200356
Johan Hedberga38528f2011-01-22 06:46:43 +0200357 kfree(rp);
358
359 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200360}
361
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200362static u32 get_supported_settings(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +0200363{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200364 u32 settings = 0;
Johan Hedberg03811012010-12-08 00:21:06 +0200365
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200366 settings |= MGMT_SETTING_POWERED;
367 settings |= MGMT_SETTING_CONNECTABLE;
368 settings |= MGMT_SETTING_FAST_CONNECTABLE;
369 settings |= MGMT_SETTING_DISCOVERABLE;
370 settings |= MGMT_SETTING_PAIRABLE;
Johan Hedberg03811012010-12-08 00:21:06 +0200371
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200372 if (hdev->features[6] & LMP_SIMPLE_PAIR)
373 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200374
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200375 if (!(hdev->features[4] & LMP_NO_BREDR)) {
376 settings |= MGMT_SETTING_BREDR;
377 settings |= MGMT_SETTING_LINK_SECURITY;
378 }
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200379
Marcel Holtmannd7b7e792012-02-20 21:47:49 +0100380 if (enable_hs)
381 settings |= MGMT_SETTING_HS;
382
383 if (enable_le) {
384 if (hdev->features[4] & LMP_LE)
385 settings |= MGMT_SETTING_LE;
386 }
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200387
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200388 return settings;
389}
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200390
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200391static u32 get_current_settings(struct hci_dev *hdev)
392{
393 u32 settings = 0;
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200394
Johan Hedbergf1f0eb02012-02-21 17:15:41 +0200395 if (hdev_is_powered(hdev))
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100396 settings |= MGMT_SETTING_POWERED;
397
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200398 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200399 settings |= MGMT_SETTING_CONNECTABLE;
400
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200401 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200402 settings |= MGMT_SETTING_DISCOVERABLE;
403
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200404 if (test_bit(HCI_PAIRABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200405 settings |= MGMT_SETTING_PAIRABLE;
406
407 if (!(hdev->features[4] & LMP_NO_BREDR))
408 settings |= MGMT_SETTING_BREDR;
409
Johan Hedberg06199cf2012-02-22 16:37:11 +0200410 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200411 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200412
Johan Hedberg47990ea2012-02-22 11:58:37 +0200413 if (test_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200414 settings |= MGMT_SETTING_LINK_SECURITY;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200415
Johan Hedberg84bde9d6c2012-01-25 14:21:06 +0200416 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200417 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200418
Johan Hedberg6d80dfd2012-02-20 23:50:38 +0200419 if (test_bit(HCI_HS_ENABLED, &hdev->dev_flags))
420 settings |= MGMT_SETTING_HS;
421
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200422 return settings;
Johan Hedbergc542a062011-01-26 13:11:03 +0200423}
424
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300425#define PNP_INFO_SVCLASS_ID 0x1200
426
427static u8 bluetooth_base_uuid[] = {
428 0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80,
429 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
430};
431
432static u16 get_uuid16(u8 *uuid128)
433{
434 u32 val;
435 int i;
436
437 for (i = 0; i < 12; i++) {
438 if (bluetooth_base_uuid[i] != uuid128[i])
439 return 0;
440 }
441
442 memcpy(&val, &uuid128[12], 4);
443
444 val = le32_to_cpu(val);
445 if (val > 0xffff)
446 return 0;
447
448 return (u16) val;
449}
450
451static void create_eir(struct hci_dev *hdev, u8 *data)
452{
453 u8 *ptr = data;
454 u16 eir_len = 0;
455 u16 uuid16_list[HCI_MAX_EIR_LENGTH / sizeof(u16)];
456 int i, truncated = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200457 struct bt_uuid *uuid;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300458 size_t name_len;
459
460 name_len = strlen(hdev->dev_name);
461
462 if (name_len > 0) {
463 /* EIR Data type */
464 if (name_len > 48) {
465 name_len = 48;
466 ptr[1] = EIR_NAME_SHORT;
467 } else
468 ptr[1] = EIR_NAME_COMPLETE;
469
470 /* EIR Data length */
471 ptr[0] = name_len + 1;
472
473 memcpy(ptr + 2, hdev->dev_name, name_len);
474
475 eir_len += (name_len + 2);
476 ptr += (name_len + 2);
477 }
478
479 memset(uuid16_list, 0, sizeof(uuid16_list));
480
481 /* Group all UUID16 types */
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200482 list_for_each_entry(uuid, &hdev->uuids, list) {
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300483 u16 uuid16;
484
485 uuid16 = get_uuid16(uuid->uuid);
486 if (uuid16 == 0)
487 return;
488
489 if (uuid16 < 0x1100)
490 continue;
491
492 if (uuid16 == PNP_INFO_SVCLASS_ID)
493 continue;
494
495 /* Stop if not enough space to put next UUID */
496 if (eir_len + 2 + sizeof(u16) > HCI_MAX_EIR_LENGTH) {
497 truncated = 1;
498 break;
499 }
500
501 /* Check for duplicates */
502 for (i = 0; uuid16_list[i] != 0; i++)
503 if (uuid16_list[i] == uuid16)
504 break;
505
506 if (uuid16_list[i] == 0) {
507 uuid16_list[i] = uuid16;
508 eir_len += sizeof(u16);
509 }
510 }
511
512 if (uuid16_list[0] != 0) {
513 u8 *length = ptr;
514
515 /* EIR Data type */
516 ptr[1] = truncated ? EIR_UUID16_SOME : EIR_UUID16_ALL;
517
518 ptr += 2;
519 eir_len += 2;
520
521 for (i = 0; uuid16_list[i] != 0; i++) {
522 *ptr++ = (uuid16_list[i] & 0x00ff);
523 *ptr++ = (uuid16_list[i] & 0xff00) >> 8;
524 }
525
526 /* EIR Data length */
527 *length = (i * sizeof(u16)) + 1;
528 }
529}
530
531static int update_eir(struct hci_dev *hdev)
532{
533 struct hci_cp_write_eir cp;
534
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200535 if (!hdev_is_powered(hdev))
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200536 return 0;
537
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300538 if (!(hdev->features[6] & LMP_EXT_INQ))
539 return 0;
540
Johan Hedberg84bde9d6c2012-01-25 14:21:06 +0200541 if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300542 return 0;
543
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200544 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300545 return 0;
546
547 memset(&cp, 0, sizeof(cp));
548
549 create_eir(hdev, cp.data);
550
551 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
552 return 0;
553
554 memcpy(hdev->eir, cp.data, sizeof(cp.data));
555
556 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
557}
558
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200559static u8 get_service_classes(struct hci_dev *hdev)
560{
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300561 struct bt_uuid *uuid;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200562 u8 val = 0;
563
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300564 list_for_each_entry(uuid, &hdev->uuids, list)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200565 val |= uuid->svc_hint;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200566
567 return val;
568}
569
570static int update_class(struct hci_dev *hdev)
571{
572 u8 cod[3];
573
574 BT_DBG("%s", hdev->name);
575
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200576 if (!hdev_is_powered(hdev))
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200577 return 0;
578
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200579 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200580 return 0;
581
582 cod[0] = hdev->minor_class;
583 cod[1] = hdev->major_class;
584 cod[2] = get_service_classes(hdev);
585
586 if (memcmp(cod, hdev->dev_class, 3) == 0)
587 return 0;
588
589 return hci_send_cmd(hdev, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
590}
591
Johan Hedberg7d785252011-12-15 00:47:39 +0200592static void service_cache_off(struct work_struct *work)
593{
594 struct hci_dev *hdev = container_of(work, struct hci_dev,
595 service_cache.work);
596
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200597 if (!test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200598 return;
599
600 hci_dev_lock(hdev);
601
602 update_eir(hdev);
603 update_class(hdev);
604
605 hci_dev_unlock(hdev);
606}
607
608static void mgmt_init_hdev(struct hci_dev *hdev)
609{
Johan Hedberg0cbf4ed2012-02-21 17:25:22 +0200610 if (!test_and_set_bit(HCI_MGMT, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +0200611 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
612
Johan Hedberg0cbf4ed2012-02-21 17:25:22 +0200613 /* Non-mgmt controlled devices get this bit set
614 * implicitly so that pairing works for them, however
615 * for mgmt we require user-space to explicitly enable
616 * it
617 */
618 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
619 }
Johan Hedberg7d785252011-12-15 00:47:39 +0200620}
621
Johan Hedberg03811012010-12-08 00:21:06 +0200622static int read_controller_info(struct sock *sk, u16 index)
623{
624 struct mgmt_rp_read_info rp;
625 struct hci_dev *hdev;
626
627 BT_DBG("sock %p hci%u", sk, index);
628
629 hdev = hci_dev_get(index);
630 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200631 return cmd_status(sk, index, MGMT_OP_READ_INFO,
632 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200633
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300634 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200635
Johan Hedberg7d785252011-12-15 00:47:39 +0200636 if (test_and_clear_bit(HCI_PI_MGMT_INIT, &hci_pi(sk)->flags))
637 mgmt_init_hdev(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200638
639 memset(&rp, 0, sizeof(rp));
640
Johan Hedberg03811012010-12-08 00:21:06 +0200641 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200642
643 rp.version = hdev->hci_ver;
644
Johan Hedberg03811012010-12-08 00:21:06 +0200645 put_unaligned_le16(hdev->manufacturer, &rp.manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200646
647 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
648 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
649
650 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedberg03811012010-12-08 00:21:06 +0200651
652 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
Johan Hedberg27fcc362012-02-22 21:46:22 +0200653 memcpy(rp.short_name, hdev->short_name, sizeof(hdev->short_name));
Johan Hedberg03811012010-12-08 00:21:06 +0200654
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300655 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200656 hci_dev_put(hdev);
657
Johan Hedbergaee9b212012-02-18 15:07:59 +0200658 return cmd_complete(sk, index, MGMT_OP_READ_INFO, 0, &rp, sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +0200659}
660
661static void mgmt_pending_free(struct pending_cmd *cmd)
662{
663 sock_put(cmd->sk);
664 kfree(cmd->param);
665 kfree(cmd);
666}
667
668static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
669 struct hci_dev *hdev,
670 void *data, u16 len)
671{
672 struct pending_cmd *cmd;
673
674 cmd = kmalloc(sizeof(*cmd), GFP_ATOMIC);
675 if (!cmd)
676 return NULL;
677
678 cmd->opcode = opcode;
679 cmd->index = hdev->id;
680
681 cmd->param = kmalloc(len, GFP_ATOMIC);
682 if (!cmd->param) {
683 kfree(cmd);
684 return NULL;
685 }
686
687 if (data)
688 memcpy(cmd->param, data, len);
689
690 cmd->sk = sk;
691 sock_hold(sk);
692
693 list_add(&cmd->list, &hdev->mgmt_pending);
694
695 return cmd;
696}
697
698static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
699 void (*cb)(struct pending_cmd *cmd, void *data),
700 void *data)
701{
702 struct list_head *p, *n;
703
704 list_for_each_safe(p, n, &hdev->mgmt_pending) {
705 struct pending_cmd *cmd;
706
707 cmd = list_entry(p, struct pending_cmd, list);
708
709 if (opcode > 0 && cmd->opcode != opcode)
710 continue;
711
712 cb(cmd, data);
713 }
714}
715
716static struct pending_cmd *mgmt_pending_find(u16 opcode, struct hci_dev *hdev)
717{
718 struct pending_cmd *cmd;
719
720 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
721 if (cmd->opcode == opcode)
722 return cmd;
723 }
724
725 return NULL;
726}
727
728static void mgmt_pending_remove(struct pending_cmd *cmd)
729{
730 list_del(&cmd->list);
731 mgmt_pending_free(cmd);
732}
733
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200734static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +0200735{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200736 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +0200737
Johan Hedbergaee9b212012-02-18 15:07:59 +0200738 return cmd_complete(sk, hdev->id, opcode, 0, &settings,
739 sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +0200740}
741
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300742static int set_powered(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200743{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300744 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200745 struct hci_dev *hdev;
746 struct pending_cmd *cmd;
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200747 int err;
Johan Hedberg03811012010-12-08 00:21:06 +0200748
Johan Hedberg03811012010-12-08 00:21:06 +0200749 BT_DBG("request for hci%u", index);
750
751 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200752 return cmd_status(sk, index, MGMT_OP_SET_POWERED,
753 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200754
755 hdev = hci_dev_get(index);
756 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200757 return cmd_status(sk, index, MGMT_OP_SET_POWERED,
758 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200759
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300760 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200761
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100762 if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) {
763 cancel_delayed_work(&hdev->power_off);
764
765 if (cp->val) {
766 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
767 mgmt_powered(hdev, 1);
768 goto failed;
769 }
770 }
771
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200772 if (!!cp->val == hdev_is_powered(hdev)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200773 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200774 goto failed;
775 }
776
777 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200778 err = cmd_status(sk, index, MGMT_OP_SET_POWERED,
779 MGMT_STATUS_BUSY);
Johan Hedberg03811012010-12-08 00:21:06 +0200780 goto failed;
781 }
782
783 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
784 if (!cmd) {
785 err = -ENOMEM;
786 goto failed;
787 }
788
789 if (cp->val)
Gustavo F. Padovan7f971042011-12-18 12:40:32 -0200790 schedule_work(&hdev->power_on);
Johan Hedberg03811012010-12-08 00:21:06 +0200791 else
Gustavo F. Padovan80b7ab32011-12-17 14:52:27 -0200792 schedule_work(&hdev->power_off.work);
Johan Hedberg03811012010-12-08 00:21:06 +0200793
794 err = 0;
795
796failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300797 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200798 hci_dev_put(hdev);
799 return err;
800}
801
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200802static int mgmt_event(u16 event, struct hci_dev *hdev, void *data,
803 u16 data_len, struct sock *skip_sk)
804{
805 struct sk_buff *skb;
806 struct mgmt_hdr *hdr;
807
808 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_ATOMIC);
809 if (!skb)
810 return -ENOMEM;
811
812 hdr = (void *) skb_put(skb, sizeof(*hdr));
813 hdr->opcode = cpu_to_le16(event);
814 if (hdev)
815 hdr->index = cpu_to_le16(hdev->id);
816 else
817 hdr->index = cpu_to_le16(MGMT_INDEX_NONE);
818 hdr->len = cpu_to_le16(data_len);
819
820 if (data)
821 memcpy(skb_put(skb, data_len), data, data_len);
822
Marcel Holtmann97e0bde2012-02-22 13:49:28 +0100823 /* Time stamp */
824 __net_timestamp(skb);
825
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200826 hci_send_to_control(skb, skip_sk);
827 kfree_skb(skb);
828
829 return 0;
830}
831
832static int new_settings(struct hci_dev *hdev, struct sock *skip)
833{
834 __le32 ev;
835
836 ev = cpu_to_le32(get_current_settings(hdev));
837
838 return mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), skip);
839}
840
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300841static int set_discoverable(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200842{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300843 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberge41d8b42010-12-13 21:07:03 +0200844 struct hci_dev *hdev;
Johan Hedberg03811012010-12-08 00:21:06 +0200845 struct pending_cmd *cmd;
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200846 u16 timeout;
Johan Hedberg03811012010-12-08 00:21:06 +0200847 u8 scan;
848 int err;
849
Johan Hedberg03811012010-12-08 00:21:06 +0200850 BT_DBG("request for hci%u", index);
851
852 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200853 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
854 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200855
Marcel Holtmann24c54a92012-02-22 18:06:34 +0100856 timeout = get_unaligned_le16(&cp->timeout);
857 if (!cp->val && timeout > 0)
858 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
859 MGMT_STATUS_INVALID_PARAMS);
860
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200861 hdev = hci_dev_get(index);
862 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200863 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
864 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200865
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300866 hci_dev_lock(hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200867
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200868 if (!hdev_is_powered(hdev) && timeout > 0) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200869 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
870 MGMT_STATUS_NOT_POWERED);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200871 goto failed;
872 }
873
874 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
875 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200876 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
877 MGMT_STATUS_BUSY);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200878 goto failed;
879 }
880
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200881 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) {
882 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
883 MGMT_STATUS_REJECTED);
884 goto failed;
885 }
886
887 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200888 bool changed = false;
889
890 if (!!cp->val != test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
891 change_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
892 changed = true;
893 }
894
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200895 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200896 if (err < 0)
897 goto failed;
898
899 if (changed)
900 err = new_settings(hdev, sk);
901
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200902 goto failed;
903 }
904
905 if (!!cp->val == test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
Marcel Holtmann955638e2012-02-22 18:21:00 +0100906 if (hdev->discov_timeout > 0) {
907 cancel_delayed_work(&hdev->discov_off);
908 hdev->discov_timeout = 0;
909 }
910
911 if (cp->val && timeout > 0) {
912 hdev->discov_timeout = timeout;
913 queue_delayed_work(hdev->workqueue, &hdev->discov_off,
914 msecs_to_jiffies(hdev->discov_timeout * 1000));
915 }
916
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200917 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200918 goto failed;
919 }
920
921 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
922 if (!cmd) {
923 err = -ENOMEM;
924 goto failed;
925 }
926
927 scan = SCAN_PAGE;
928
929 if (cp->val)
930 scan |= SCAN_INQUIRY;
931 else
932 cancel_delayed_work(&hdev->discov_off);
933
934 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
935 if (err < 0)
936 mgmt_pending_remove(cmd);
937
Johan Hedberg03811012010-12-08 00:21:06 +0200938 if (cp->val)
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200939 hdev->discov_timeout = timeout;
Johan Hedberg03811012010-12-08 00:21:06 +0200940
941failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300942 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200943 hci_dev_put(hdev);
944
945 return err;
946}
947
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300948static int set_connectable(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200949{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300950 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200951 struct hci_dev *hdev;
952 struct pending_cmd *cmd;
953 u8 scan;
954 int err;
955
Johan Hedberge41d8b42010-12-13 21:07:03 +0200956 BT_DBG("request for hci%u", index);
957
Johan Hedberg03811012010-12-08 00:21:06 +0200958 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200959 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
960 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200961
962 hdev = hci_dev_get(index);
963 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200964 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
965 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200966
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300967 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200968
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200969 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200970 bool changed = false;
971
972 if (!!cp->val != test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
973 changed = true;
974
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +0200975 if (cp->val) {
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200976 set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +0200977 } else {
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200978 clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
979 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
980 }
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200981
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200982 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200983 if (err < 0)
984 goto failed;
985
986 if (changed)
987 err = new_settings(hdev, sk);
988
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200989 goto failed;
990 }
991
992 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
993 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200994 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
995 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200996 goto failed;
997 }
998
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200999 if (!!cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001000 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001001 goto failed;
1002 }
1003
1004 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
1005 if (!cmd) {
1006 err = -ENOMEM;
1007 goto failed;
1008 }
1009
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001010 if (cp->val) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001011 scan = SCAN_PAGE;
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001012 } else {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001013 scan = 0;
1014
Johan Hedbergdf2c6c52012-02-21 19:15:49 +02001015 if (test_bit(HCI_ISCAN, &hdev->flags) &&
1016 hdev->discov_timeout > 0)
1017 cancel_delayed_work(&hdev->discov_off);
1018 }
1019
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001020 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1021 if (err < 0)
1022 mgmt_pending_remove(cmd);
1023
1024failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001025 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001026 hci_dev_put(hdev);
1027
1028 return err;
1029}
1030
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001031static int set_pairable(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001032{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001033 struct mgmt_mode *cp = data;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001034 struct hci_dev *hdev;
1035 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001036
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001037 BT_DBG("request for hci%u", index);
1038
1039 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001040 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE,
1041 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001042
1043 hdev = hci_dev_get(index);
1044 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001045 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE,
1046 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001047
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001048 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001049
1050 if (cp->val)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001051 set_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001052 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001053 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001054
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001055 err = send_settings_rsp(sk, MGMT_OP_SET_PAIRABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001056 if (err < 0)
1057 goto failed;
1058
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001059 err = new_settings(hdev, sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001060
1061failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001062 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001063 hci_dev_put(hdev);
1064
1065 return err;
1066}
Johan Hedberg72a734e2010-12-30 00:38:22 +02001067
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001068static int set_link_security(struct sock *sk, u16 index, void *data, u16 len)
1069{
1070 struct mgmt_mode *cp = data;
1071 struct pending_cmd *cmd;
1072 struct hci_dev *hdev;
1073 uint8_t val;
1074 int err;
1075
1076 BT_DBG("request for hci%u", index);
1077
1078 if (len != sizeof(*cp))
1079 return cmd_status(sk, index, MGMT_OP_SET_LINK_SECURITY,
1080 MGMT_STATUS_INVALID_PARAMS);
1081
1082 hdev = hci_dev_get(index);
1083 if (!hdev)
1084 return cmd_status(sk, index, MGMT_OP_SET_LINK_SECURITY,
1085 MGMT_STATUS_INVALID_PARAMS);
1086
1087 hci_dev_lock(hdev);
1088
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001089 if (!hdev_is_powered(hdev)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001090 bool changed = false;
1091
1092 if (!!cp->val != test_bit(HCI_LINK_SECURITY,
1093 &hdev->dev_flags)) {
1094 change_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
1095 changed = true;
1096 }
1097
1098 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1099 if (err < 0)
1100 goto failed;
1101
1102 if (changed)
1103 err = new_settings(hdev, sk);
1104
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001105 goto failed;
1106 }
1107
1108 if (mgmt_pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
1109 err = cmd_status(sk, index, MGMT_OP_SET_LINK_SECURITY,
1110 MGMT_STATUS_BUSY);
1111 goto failed;
1112 }
1113
1114 val = !!cp->val;
1115
1116 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1117 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1118 goto failed;
1119 }
1120
1121 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1122 if (!cmd) {
1123 err = -ENOMEM;
1124 goto failed;
1125 }
1126
1127 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1128 if (err < 0) {
1129 mgmt_pending_remove(cmd);
1130 goto failed;
1131 }
1132
1133failed:
1134 hci_dev_unlock(hdev);
1135 hci_dev_put(hdev);
1136
1137 return err;
1138}
1139
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001140static int set_ssp(struct sock *sk, u16 index, void *data, u16 len)
1141{
1142 struct mgmt_mode *cp = data;
1143 struct pending_cmd *cmd;
1144 struct hci_dev *hdev;
1145 uint8_t val;
1146 int err;
1147
1148 BT_DBG("request for hci%u", index);
1149
1150 if (len != sizeof(*cp))
1151 return cmd_status(sk, index, MGMT_OP_SET_SSP,
1152 MGMT_STATUS_INVALID_PARAMS);
1153
1154 hdev = hci_dev_get(index);
1155 if (!hdev)
1156 return cmd_status(sk, index, MGMT_OP_SET_SSP,
1157 MGMT_STATUS_INVALID_PARAMS);
1158
1159 hci_dev_lock(hdev);
1160
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001161 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
1162 err = cmd_status(sk, index, MGMT_OP_SET_SSP,
1163 MGMT_STATUS_NOT_SUPPORTED);
1164 goto failed;
1165 }
1166
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001167 val = !!cp->val;
1168
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001169 if (!hdev_is_powered(hdev)) {
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001170 bool changed = false;
1171
1172 if (val != test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) {
1173 change_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
1174 changed = true;
1175 }
1176
1177 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1178 if (err < 0)
1179 goto failed;
1180
1181 if (changed)
1182 err = new_settings(hdev, sk);
1183
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001184 goto failed;
1185 }
1186
1187 if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev)) {
1188 err = cmd_status(sk, index, MGMT_OP_SET_SSP, MGMT_STATUS_BUSY);
1189 goto failed;
1190 }
1191
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001192 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) == val) {
1193 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1194 goto failed;
1195 }
1196
1197 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1198 if (!cmd) {
1199 err = -ENOMEM;
1200 goto failed;
1201 }
1202
1203 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, sizeof(val), &val);
1204 if (err < 0) {
1205 mgmt_pending_remove(cmd);
1206 goto failed;
1207 }
1208
1209failed:
1210 hci_dev_unlock(hdev);
1211 hci_dev_put(hdev);
1212
1213 return err;
1214}
1215
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001216static int set_hs(struct sock *sk, u16 index, void *data, u16 len)
1217{
1218 struct mgmt_mode *cp = data;
1219 struct hci_dev *hdev;
1220 int err;
1221
1222 BT_DBG("request for hci%u", index);
1223
1224 if (len != sizeof(*cp))
1225 return cmd_status(sk, index, MGMT_OP_SET_HS,
1226 MGMT_STATUS_INVALID_PARAMS);
1227
1228 hdev = hci_dev_get(index);
1229 if (!hdev)
1230 return cmd_status(sk, index, MGMT_OP_SET_HS,
1231 MGMT_STATUS_INVALID_PARAMS);
1232
1233 if (!enable_hs) {
1234 err = cmd_status(sk, index, MGMT_OP_SET_HS,
1235 MGMT_STATUS_NOT_SUPPORTED);
1236 goto failed;
1237 }
1238
1239 if (cp->val)
1240 set_bit(HCI_HS_ENABLED, &hdev->dev_flags);
1241 else
1242 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
1243
1244 err = send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
1245
1246failed:
1247 hci_dev_put(hdev);
1248 return err;
1249}
1250
Johan Hedberg06199cf2012-02-22 16:37:11 +02001251static int set_le(struct sock *sk, u16 index, void *data, u16 len)
1252{
1253 struct mgmt_mode *cp = data;
1254 struct hci_cp_write_le_host_supported hci_cp;
1255 struct pending_cmd *cmd;
1256 struct hci_dev *hdev;
1257 int err;
1258 u8 val;
1259
1260 BT_DBG("request for hci%u", index);
1261
1262 if (len != sizeof(*cp))
1263 return cmd_status(sk, index, MGMT_OP_SET_LE,
1264 MGMT_STATUS_INVALID_PARAMS);
1265
1266 hdev = hci_dev_get(index);
1267 if (!hdev)
1268 return cmd_status(sk, index, MGMT_OP_SET_LE,
1269 MGMT_STATUS_INVALID_PARAMS);
1270
1271 if (!enable_le || !(hdev->features[4] & LMP_LE)) {
1272 err = cmd_status(sk, index, MGMT_OP_SET_LE,
1273 MGMT_STATUS_NOT_SUPPORTED);
1274 goto failed;
1275 }
1276
1277 val = !!cp->val;
1278
1279 if (!hdev_is_powered(hdev)) {
1280 bool changed = false;
1281
1282 if (val != test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
1283 change_bit(HCI_LE_ENABLED, &hdev->dev_flags);
1284 changed = true;
1285 }
1286
1287 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1288 if (err < 0)
1289 goto failed;
1290
1291 if (changed)
1292 err = new_settings(hdev, sk);
1293
1294 goto failed;
1295 }
1296
1297 if (mgmt_pending_find(MGMT_OP_SET_LE, hdev)) {
1298 err = cmd_status(sk, index, MGMT_OP_SET_LE, MGMT_STATUS_BUSY);
1299 goto failed;
1300 }
1301
1302 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
1303 if (!cmd) {
1304 err = -ENOMEM;
1305 goto failed;
1306 }
1307
1308 memset(&hci_cp, 0, sizeof(hci_cp));
1309
1310 if (val) {
1311 hci_cp.le = val;
1312 hci_cp.simul = !!(hdev->features[6] & LMP_SIMUL_LE_BR);
1313 }
1314
1315 err = hci_send_cmd(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED,
1316 sizeof(hci_cp), &hci_cp);
1317 if (err < 0) {
1318 mgmt_pending_remove(cmd);
1319 goto failed;
1320 }
1321
1322failed:
1323 hci_dev_put(hdev);
1324 return err;
1325}
1326
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001327static int add_uuid(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001328{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001329 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001330 struct hci_dev *hdev;
1331 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001332 int err;
1333
Szymon Janc4e51eae2011-02-25 19:05:48 +01001334 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001335
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001336 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001337 return cmd_status(sk, index, MGMT_OP_ADD_UUID,
1338 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001339
Szymon Janc4e51eae2011-02-25 19:05:48 +01001340 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001341 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001342 return cmd_status(sk, index, MGMT_OP_ADD_UUID,
1343 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001344
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001345 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001346
1347 uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC);
1348 if (!uuid) {
1349 err = -ENOMEM;
1350 goto failed;
1351 }
1352
1353 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001354 uuid->svc_hint = cp->svc_hint;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001355
1356 list_add(&uuid->list, &hdev->uuids);
1357
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001358 err = update_class(hdev);
1359 if (err < 0)
1360 goto failed;
1361
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001362 err = update_eir(hdev);
1363 if (err < 0)
1364 goto failed;
1365
Johan Hedberg9997a532012-02-23 15:57:46 +02001366 err = cmd_complete(sk, index, MGMT_OP_ADD_UUID, 0, hdev->dev_class, 3);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001367
1368failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001369 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001370 hci_dev_put(hdev);
1371
1372 return err;
1373}
1374
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001375static int remove_uuid(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001376{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001377 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001378 struct list_head *p, *n;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001379 struct hci_dev *hdev;
1380 u8 bt_uuid_any[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001381 int err, found;
1382
Szymon Janc4e51eae2011-02-25 19:05:48 +01001383 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001384
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001385 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001386 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
1387 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001388
Szymon Janc4e51eae2011-02-25 19:05:48 +01001389 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001390 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001391 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
1392 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001393
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001394 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001395
1396 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
1397 err = hci_uuids_clear(hdev);
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001398
1399 if (hdev_is_powered(hdev) &&
1400 !test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
1401 schedule_delayed_work(&hdev->service_cache,
1402 msecs_to_jiffies(SERVICE_CACHE_TIMEOUT));
1403
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001404 goto unlock;
1405 }
1406
1407 found = 0;
1408
1409 list_for_each_safe(p, n, &hdev->uuids) {
1410 struct bt_uuid *match = list_entry(p, struct bt_uuid, list);
1411
1412 if (memcmp(match->uuid, cp->uuid, 16) != 0)
1413 continue;
1414
1415 list_del(&match->list);
1416 found++;
1417 }
1418
1419 if (found == 0) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001420 err = cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
1421 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001422 goto unlock;
1423 }
1424
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001425 err = update_class(hdev);
1426 if (err < 0)
1427 goto unlock;
1428
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001429 err = update_eir(hdev);
1430 if (err < 0)
1431 goto unlock;
1432
Johan Hedberg9997a532012-02-23 15:57:46 +02001433 err = cmd_complete(sk, index, MGMT_OP_REMOVE_UUID, 0,
1434 hdev->dev_class, 3);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001435
1436unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001437 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001438 hci_dev_put(hdev);
1439
1440 return err;
1441}
1442
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001443static int set_dev_class(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001444{
1445 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001446 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001447 int err;
1448
Szymon Janc4e51eae2011-02-25 19:05:48 +01001449 BT_DBG("request for hci%u", index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001450
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001451 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001452 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS,
1453 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001454
Szymon Janc4e51eae2011-02-25 19:05:48 +01001455 hdev = hci_dev_get(index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001456 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001457 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS,
1458 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001459
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001460 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001461
1462 hdev->major_class = cp->major;
1463 hdev->minor_class = cp->minor;
1464
Johan Hedberg932f5ff2012-02-22 22:11:32 +02001465 if (!hdev_is_powered(hdev)) {
1466 err = cmd_complete(sk, index, MGMT_OP_SET_DEV_CLASS, 0,
1467 hdev->dev_class, 3);
1468 goto unlock;
1469 }
1470
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001471 if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02001472 hci_dev_unlock(hdev);
1473 cancel_delayed_work_sync(&hdev->service_cache);
1474 hci_dev_lock(hdev);
Johan Hedberg14c0b602011-12-15 00:47:37 +02001475 update_eir(hdev);
Johan Hedberg7d785252011-12-15 00:47:39 +02001476 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02001477
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001478 err = update_class(hdev);
1479
1480 if (err == 0)
Johan Hedbergaee9b212012-02-18 15:07:59 +02001481 err = cmd_complete(sk, index, MGMT_OP_SET_DEV_CLASS, 0,
Johan Hedberg8ec37032012-02-22 22:02:50 +02001482 hdev->dev_class, 3);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001483
Johan Hedbergb5235a62012-02-21 14:32:24 +02001484unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001485 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001486 hci_dev_put(hdev);
1487
1488 return err;
1489}
1490
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001491static int load_link_keys(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001492{
1493 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001494 struct mgmt_cp_load_link_keys *cp = data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001495 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001496 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001497
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001498 if (len < sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001499 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1500 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001501
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001502 key_count = get_unaligned_le16(&cp->key_count);
1503
Johan Hedberg86742e12011-11-07 23:13:38 +02001504 expected_len = sizeof(*cp) + key_count *
1505 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001506 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001507 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001508 len, expected_len);
Johan Hedbergca69b792011-11-11 18:10:00 +02001509 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1510 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001511 }
1512
Szymon Janc4e51eae2011-02-25 19:05:48 +01001513 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001514 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001515 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1516 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001517
Szymon Janc4e51eae2011-02-25 19:05:48 +01001518 BT_DBG("hci%u debug_keys %u key_count %u", index, cp->debug_keys,
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001519 key_count);
1520
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001521 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001522
1523 hci_link_keys_clear(hdev);
1524
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001525 set_bit(HCI_LINK_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001526
1527 if (cp->debug_keys)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001528 set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001529 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001530 clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001531
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001532 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001533 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001534
Johan Hedbergd753fdc2012-02-17 14:06:34 +02001535 hci_add_link_key(hdev, NULL, 0, &key->addr.bdaddr, key->val,
1536 key->type, key->pin_len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001537 }
1538
Johan Hedbergaee9b212012-02-18 15:07:59 +02001539 cmd_complete(sk, index, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02001540
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001541 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001542 hci_dev_put(hdev);
1543
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001544 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001545}
1546
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001547static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
1548 u8 addr_type, struct sock *skip_sk)
1549{
1550 struct mgmt_ev_device_unpaired ev;
1551
1552 bacpy(&ev.addr.bdaddr, bdaddr);
1553 ev.addr.type = addr_type;
1554
1555 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
1556 skip_sk);
1557}
1558
Johan Hedberg124f6e32012-02-09 13:50:12 +02001559static int unpair_device(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001560{
1561 struct hci_dev *hdev;
Johan Hedberg124f6e32012-02-09 13:50:12 +02001562 struct mgmt_cp_unpair_device *cp = data;
1563 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001564 struct hci_cp_disconnect dc;
1565 struct pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001566 struct hci_conn *conn;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001567 int err;
1568
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001569 if (len != sizeof(*cp))
Johan Hedberg124f6e32012-02-09 13:50:12 +02001570 return cmd_status(sk, index, MGMT_OP_UNPAIR_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02001571 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001572
Szymon Janc4e51eae2011-02-25 19:05:48 +01001573 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001574 if (!hdev)
Johan Hedberg124f6e32012-02-09 13:50:12 +02001575 return cmd_status(sk, index, MGMT_OP_UNPAIR_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02001576 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001577
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001578 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001579
Johan Hedberga8a1d192011-11-10 15:54:38 +02001580 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02001581 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1582 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001583
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001584 if (!hdev_is_powered(hdev)) {
1585 err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE,
1586 MGMT_STATUS_NOT_POWERED,
1587 &rp, sizeof(rp));
1588 goto unlock;
1589 }
1590
Johan Hedberg124f6e32012-02-09 13:50:12 +02001591 if (cp->addr.type == MGMT_ADDR_BREDR)
1592 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
1593 else
1594 err = hci_remove_ltk(hdev, &cp->addr.bdaddr);
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03001595
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001596 if (err < 0) {
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001597 err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE,
1598 MGMT_STATUS_NOT_PAIRED,
1599 &rp, sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001600 goto unlock;
1601 }
1602
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001603 if (cp->disconnect) {
1604 if (cp->addr.type == MGMT_ADDR_BREDR)
1605 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
1606 &cp->addr.bdaddr);
1607 else
1608 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
1609 &cp->addr.bdaddr);
1610 } else {
1611 conn = NULL;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001612 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001613
Johan Hedberga8a1d192011-11-10 15:54:38 +02001614 if (!conn) {
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001615 err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE, 0,
Johan Hedbergaee9b212012-02-18 15:07:59 +02001616 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001617 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001618 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001619 }
1620
Johan Hedberg124f6e32012-02-09 13:50:12 +02001621 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
1622 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02001623 if (!cmd) {
1624 err = -ENOMEM;
1625 goto unlock;
1626 }
1627
1628 put_unaligned_le16(conn->handle, &dc.handle);
1629 dc.reason = 0x13; /* Remote User Terminated Connection */
1630 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1631 if (err < 0)
1632 mgmt_pending_remove(cmd);
1633
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001634unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001635 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001636 hci_dev_put(hdev);
1637
1638 return err;
1639}
1640
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001641static int disconnect(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02001642{
1643 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001644 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001645 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03001646 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001647 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001648 int err;
1649
1650 BT_DBG("");
1651
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001652 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001653 return cmd_status(sk, index, MGMT_OP_DISCONNECT,
1654 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001655
Szymon Janc4e51eae2011-02-25 19:05:48 +01001656 hdev = hci_dev_get(index);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001657 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001658 return cmd_status(sk, index, MGMT_OP_DISCONNECT,
1659 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001660
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001661 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001662
1663 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001664 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1665 MGMT_STATUS_NOT_POWERED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001666 goto failed;
1667 }
1668
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001669 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001670 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1671 MGMT_STATUS_BUSY);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001672 goto failed;
1673 }
1674
Johan Hedberg88c3df12012-02-09 14:27:38 +02001675 if (cp->addr.type == MGMT_ADDR_BREDR)
1676 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
1677 else
1678 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03001679
Johan Hedberg8962ee72011-01-20 12:40:27 +02001680 if (!conn) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001681 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1682 MGMT_STATUS_NOT_CONNECTED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001683 goto failed;
1684 }
1685
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001686 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001687 if (!cmd) {
1688 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001689 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001690 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001691
1692 put_unaligned_le16(conn->handle, &dc.handle);
1693 dc.reason = 0x13; /* Remote User Terminated Connection */
1694
1695 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1696 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001697 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001698
1699failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001700 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001701 hci_dev_put(hdev);
1702
1703 return err;
1704}
1705
Johan Hedberg48264f02011-11-09 13:58:58 +02001706static u8 link_to_mgmt(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02001707{
1708 switch (link_type) {
1709 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02001710 switch (addr_type) {
1711 case ADDR_LE_DEV_PUBLIC:
1712 return MGMT_ADDR_LE_PUBLIC;
1713 case ADDR_LE_DEV_RANDOM:
1714 return MGMT_ADDR_LE_RANDOM;
1715 default:
1716 return MGMT_ADDR_INVALID;
1717 }
Johan Hedberg4c659c32011-11-07 23:13:39 +02001718 case ACL_LINK:
1719 return MGMT_ADDR_BREDR;
1720 default:
1721 return MGMT_ADDR_INVALID;
1722 }
1723}
1724
Szymon Janc8ce62842011-03-01 16:55:32 +01001725static int get_connections(struct sock *sk, u16 index)
Johan Hedberg2784eb42011-01-21 13:56:35 +02001726{
Johan Hedberg2784eb42011-01-21 13:56:35 +02001727 struct mgmt_rp_get_connections *rp;
1728 struct hci_dev *hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001729 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02001730 size_t rp_len;
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001731 int err;
1732 u16 i;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001733
1734 BT_DBG("");
1735
Szymon Janc4e51eae2011-02-25 19:05:48 +01001736 hdev = hci_dev_get(index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001737 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001738 return cmd_status(sk, index, MGMT_OP_GET_CONNECTIONS,
1739 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001740
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001741 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001742
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001743 if (!hdev_is_powered(hdev)) {
1744 err = cmd_status(sk, index, MGMT_OP_GET_CONNECTIONS,
1745 MGMT_STATUS_NOT_POWERED);
1746 goto unlock;
1747 }
1748
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001749 i = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02001750 list_for_each_entry(c, &hdev->conn_hash.list, list) {
1751 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001752 i++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001753 }
1754
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001755 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberga38528f2011-01-22 06:46:43 +02001756 rp = kmalloc(rp_len, GFP_ATOMIC);
1757 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02001758 err = -ENOMEM;
1759 goto unlock;
1760 }
1761
Johan Hedberg2784eb42011-01-21 13:56:35 +02001762 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001763 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02001764 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
1765 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001766 bacpy(&rp->addr[i].bdaddr, &c->dst);
Johan Hedberg48264f02011-11-09 13:58:58 +02001767 rp->addr[i].type = link_to_mgmt(c->type, c->dst_type);
Johan Hedberg4c659c32011-11-07 23:13:39 +02001768 if (rp->addr[i].type == MGMT_ADDR_INVALID)
1769 continue;
1770 i++;
1771 }
1772
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001773 put_unaligned_le16(i, &rp->conn_count);
1774
Johan Hedberg4c659c32011-11-07 23:13:39 +02001775 /* Recalculate length in case of filtered SCO connections, etc */
1776 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02001777
Johan Hedbergaee9b212012-02-18 15:07:59 +02001778 err = cmd_complete(sk, index, MGMT_OP_GET_CONNECTIONS, 0, rp, rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001779
Johan Hedberga38528f2011-01-22 06:46:43 +02001780 kfree(rp);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001781
1782unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001783 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001784 hci_dev_put(hdev);
1785 return err;
1786}
1787
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001788static int send_pin_code_neg_reply(struct sock *sk, u16 index,
1789 struct hci_dev *hdev, struct mgmt_cp_pin_code_neg_reply *cp)
1790{
1791 struct pending_cmd *cmd;
1792 int err;
1793
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001794 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001795 sizeof(*cp));
1796 if (!cmd)
1797 return -ENOMEM;
1798
Johan Hedbergd8457692012-02-17 14:24:57 +02001799 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
1800 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001801 if (err < 0)
1802 mgmt_pending_remove(cmd);
1803
1804 return err;
1805}
1806
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001807static int pin_code_reply(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001808{
1809 struct hci_dev *hdev;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001810 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001811 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001812 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03001813 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001814 int err;
1815
1816 BT_DBG("");
1817
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001818 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001819 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1820 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001821
Szymon Janc4e51eae2011-02-25 19:05:48 +01001822 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001823 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001824 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1825 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001826
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001827 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001828
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001829 if (!hdev_is_powered(hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001830 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1831 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001832 goto failed;
1833 }
1834
Johan Hedbergd8457692012-02-17 14:24:57 +02001835 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001836 if (!conn) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001837 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1838 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001839 goto failed;
1840 }
1841
1842 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02001843 struct mgmt_cp_pin_code_neg_reply ncp;
1844
1845 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001846
1847 BT_ERR("PIN code is not 16 bytes long");
1848
1849 err = send_pin_code_neg_reply(sk, index, hdev, &ncp);
1850 if (err >= 0)
1851 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001852 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001853
1854 goto failed;
1855 }
1856
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001857 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data,
1858 len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001859 if (!cmd) {
1860 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001861 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001862 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02001863
Johan Hedbergd8457692012-02-17 14:24:57 +02001864 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001865 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02001866 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02001867
1868 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
1869 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001870 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001871
1872failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001873 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001874 hci_dev_put(hdev);
1875
1876 return err;
1877}
1878
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001879static int pin_code_neg_reply(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001880{
1881 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001882 struct mgmt_cp_pin_code_neg_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001883 int err;
1884
1885 BT_DBG("");
1886
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001887 if (len != sizeof(*cp))
1888 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001889 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001890
Szymon Janc4e51eae2011-02-25 19:05:48 +01001891 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001892 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001893 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001894 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001895
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001896 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001897
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001898 if (!hdev_is_powered(hdev)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001899 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001900 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001901 goto failed;
1902 }
1903
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001904 err = send_pin_code_neg_reply(sk, index, hdev, cp);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001905
1906failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001907 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001908 hci_dev_put(hdev);
1909
1910 return err;
1911}
1912
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001913static int set_io_capability(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001914{
1915 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001916 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001917
1918 BT_DBG("");
1919
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001920 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001921 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY,
1922 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001923
Szymon Janc4e51eae2011-02-25 19:05:48 +01001924 hdev = hci_dev_get(index);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001925 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001926 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY,
1927 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001928
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001929 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001930
1931 hdev->io_capability = cp->io_capability;
1932
1933 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Szymon Jancb8534e02011-03-01 16:55:34 +01001934 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001935
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001936 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001937 hci_dev_put(hdev);
1938
Johan Hedbergaee9b212012-02-18 15:07:59 +02001939 return cmd_complete(sk, index, MGMT_OP_SET_IO_CAPABILITY, 0, NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001940}
1941
Johan Hedberge9a416b2011-02-19 12:05:56 -03001942static inline struct pending_cmd *find_pairing(struct hci_conn *conn)
1943{
1944 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001945 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001946
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001947 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03001948 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
1949 continue;
1950
Johan Hedberge9a416b2011-02-19 12:05:56 -03001951 if (cmd->user_data != conn)
1952 continue;
1953
1954 return cmd;
1955 }
1956
1957 return NULL;
1958}
1959
1960static void pairing_complete(struct pending_cmd *cmd, u8 status)
1961{
1962 struct mgmt_rp_pair_device rp;
1963 struct hci_conn *conn = cmd->user_data;
1964
Johan Hedbergba4e5642011-11-11 00:07:34 +02001965 bacpy(&rp.addr.bdaddr, &conn->dst);
1966 rp.addr.type = link_to_mgmt(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001967
Johan Hedbergaee9b212012-02-18 15:07:59 +02001968 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, status,
1969 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001970
1971 /* So we don't get further callbacks for this connection */
1972 conn->connect_cfm_cb = NULL;
1973 conn->security_cfm_cb = NULL;
1974 conn->disconn_cfm_cb = NULL;
1975
1976 hci_conn_put(conn);
1977
Johan Hedberga664b5b2011-02-19 12:06:02 -03001978 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001979}
1980
1981static void pairing_complete_cb(struct hci_conn *conn, u8 status)
1982{
1983 struct pending_cmd *cmd;
1984
1985 BT_DBG("status %u", status);
1986
Johan Hedberg56e5cb82011-11-08 20:40:16 +02001987 cmd = find_pairing(conn);
1988 if (!cmd)
1989 BT_DBG("Unable to find a pending command");
1990 else
Johan Hedberge2113262012-02-18 15:20:03 +02001991 pairing_complete(cmd, mgmt_status(status));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001992}
1993
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001994static int pair_device(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001995{
1996 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001997 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02001998 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001999 struct pending_cmd *cmd;
2000 u8 sec_level, auth_type;
2001 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002002 int err;
2003
2004 BT_DBG("");
2005
Szymon Jancbdce7ba2011-02-25 19:05:49 +01002006 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02002007 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE,
2008 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01002009
Szymon Janc4e51eae2011-02-25 19:05:48 +01002010 hdev = hci_dev_get(index);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002011 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002012 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE,
2013 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002014
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002015 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002016
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002017 if (!hdev_is_powered(hdev)) {
2018 err = cmd_status(sk, index, MGMT_OP_PAIR_DEVICE,
2019 MGMT_STATUS_NOT_POWERED);
2020 goto unlock;
2021 }
2022
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002023 sec_level = BT_SECURITY_MEDIUM;
2024 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002025 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002026 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03002027 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002028
Johan Hedbergba4e5642011-11-11 00:07:34 +02002029 if (cp->addr.type == MGMT_ADDR_BREDR)
2030 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr, sec_level,
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002031 auth_type);
2032 else
Johan Hedbergba4e5642011-11-11 00:07:34 +02002033 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr, sec_level,
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002034 auth_type);
2035
Johan Hedberg1425acb2011-11-11 00:07:35 +02002036 memset(&rp, 0, sizeof(rp));
2037 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2038 rp.addr.type = cp->addr.type;
2039
Ville Tervo30e76272011-02-22 16:10:53 -03002040 if (IS_ERR(conn)) {
Johan Hedberge2113262012-02-18 15:20:03 +02002041 err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE,
2042 MGMT_STATUS_CONNECT_FAILED,
2043 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002044 goto unlock;
2045 }
2046
2047 if (conn->connect_cfm_cb) {
2048 hci_conn_put(conn);
Johan Hedberge2113262012-02-18 15:20:03 +02002049 err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE,
2050 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002051 goto unlock;
2052 }
2053
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002054 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002055 if (!cmd) {
2056 err = -ENOMEM;
2057 hci_conn_put(conn);
2058 goto unlock;
2059 }
2060
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002061 /* For LE, just connecting isn't a proof that the pairing finished */
Johan Hedbergba4e5642011-11-11 00:07:34 +02002062 if (cp->addr.type == MGMT_ADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002063 conn->connect_cfm_cb = pairing_complete_cb;
2064
Johan Hedberge9a416b2011-02-19 12:05:56 -03002065 conn->security_cfm_cb = pairing_complete_cb;
2066 conn->disconn_cfm_cb = pairing_complete_cb;
2067 conn->io_capability = cp->io_cap;
2068 cmd->user_data = conn;
2069
2070 if (conn->state == BT_CONNECTED &&
2071 hci_conn_security(conn, sec_level, auth_type))
2072 pairing_complete(cmd, 0);
2073
2074 err = 0;
2075
2076unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002077 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002078 hci_dev_put(hdev);
2079
2080 return err;
2081}
2082
Johan Hedberg28424702012-02-02 04:02:29 +02002083static int cancel_pair_device(struct sock *sk, u16 index,
2084 unsigned char *data, u16 len)
2085{
2086 struct mgmt_addr_info *addr = (void *) data;
2087 struct hci_dev *hdev;
2088 struct pending_cmd *cmd;
2089 struct hci_conn *conn;
2090 int err;
2091
2092 BT_DBG("");
2093
2094 if (len != sizeof(*addr))
2095 return cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
2096 MGMT_STATUS_INVALID_PARAMS);
2097
2098 hdev = hci_dev_get(index);
2099 if (!hdev)
2100 return cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
2101 MGMT_STATUS_INVALID_PARAMS);
2102
2103 hci_dev_lock(hdev);
2104
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002105 if (!hdev_is_powered(hdev)) {
2106 err = cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
2107 MGMT_STATUS_NOT_POWERED);
2108 goto unlock;
2109 }
2110
Johan Hedberg28424702012-02-02 04:02:29 +02002111 cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
2112 if (!cmd) {
2113 err = cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
2114 MGMT_STATUS_INVALID_PARAMS);
2115 goto unlock;
2116 }
2117
2118 conn = cmd->user_data;
2119
2120 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
2121 err = cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
2122 MGMT_STATUS_INVALID_PARAMS);
2123 goto unlock;
2124 }
2125
2126 pairing_complete(cmd, MGMT_STATUS_CANCELLED);
2127
Johan Hedbergaee9b212012-02-18 15:07:59 +02002128 err = cmd_complete(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE, 0, addr,
Johan Hedberg28424702012-02-02 04:02:29 +02002129 sizeof(*addr));
2130unlock:
2131 hci_dev_unlock(hdev);
2132 hci_dev_put(hdev);
2133
2134 return err;
2135}
2136
Brian Gix0df4c182011-11-16 13:53:13 -08002137static int user_pairing_resp(struct sock *sk, u16 index, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02002138 u8 type, u16 mgmt_op, u16 hci_op,
2139 __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03002140{
Johan Hedberga5c29682011-02-19 12:05:57 -03002141 struct pending_cmd *cmd;
2142 struct hci_dev *hdev;
Brian Gix0df4c182011-11-16 13:53:13 -08002143 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03002144 int err;
2145
Szymon Janc4e51eae2011-02-25 19:05:48 +01002146 hdev = hci_dev_get(index);
Johan Hedberga5c29682011-02-19 12:05:57 -03002147 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002148 return cmd_status(sk, index, mgmt_op,
2149 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga5c29682011-02-19 12:05:57 -03002150
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002151 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02002152
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002153 if (!hdev_is_powered(hdev)) {
Brian Gix0df4c182011-11-16 13:53:13 -08002154 err = cmd_status(sk, index, mgmt_op, MGMT_STATUS_NOT_POWERED);
2155 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002156 }
2157
Johan Hedberg272d90d2012-02-09 15:26:12 +02002158 if (type == MGMT_ADDR_BREDR)
2159 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, bdaddr);
2160 else
Brian Gix47c15e22011-11-16 13:53:14 -08002161 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, bdaddr);
Brian Gix47c15e22011-11-16 13:53:14 -08002162
Johan Hedberg272d90d2012-02-09 15:26:12 +02002163 if (!conn) {
2164 err = cmd_status(sk, index, mgmt_op,
2165 MGMT_STATUS_NOT_CONNECTED);
2166 goto done;
2167 }
2168
2169 if (type == MGMT_ADDR_LE_PUBLIC || type == MGMT_ADDR_LE_RANDOM) {
Brian Gix47c15e22011-11-16 13:53:14 -08002170 /* Continue with pairing via SMP */
Brian Gix5fe57d92011-12-21 16:12:13 -08002171 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix47c15e22011-11-16 13:53:14 -08002172
Brian Gix5fe57d92011-12-21 16:12:13 -08002173 if (!err)
2174 err = cmd_status(sk, index, mgmt_op,
2175 MGMT_STATUS_SUCCESS);
2176 else
2177 err = cmd_status(sk, index, mgmt_op,
2178 MGMT_STATUS_FAILED);
2179
Brian Gix47c15e22011-11-16 13:53:14 -08002180 goto done;
2181 }
2182
Brian Gix0df4c182011-11-16 13:53:13 -08002183 cmd = mgmt_pending_add(sk, mgmt_op, hdev, bdaddr, sizeof(*bdaddr));
Johan Hedberga5c29682011-02-19 12:05:57 -03002184 if (!cmd) {
2185 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08002186 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002187 }
2188
Brian Gix0df4c182011-11-16 13:53:13 -08002189 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08002190 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
2191 struct hci_cp_user_passkey_reply cp;
2192
2193 bacpy(&cp.bdaddr, bdaddr);
2194 cp.passkey = passkey;
2195 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
2196 } else
2197 err = hci_send_cmd(hdev, hci_op, sizeof(*bdaddr), bdaddr);
2198
Johan Hedberga664b5b2011-02-19 12:06:02 -03002199 if (err < 0)
2200 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002201
Brian Gix0df4c182011-11-16 13:53:13 -08002202done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002203 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002204 hci_dev_put(hdev);
2205
2206 return err;
2207}
2208
Brian Gix0df4c182011-11-16 13:53:13 -08002209static int user_confirm_reply(struct sock *sk, u16 index, void *data, u16 len)
2210{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002211 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002212
2213 BT_DBG("");
2214
2215 if (len != sizeof(*cp))
2216 return cmd_status(sk, index, MGMT_OP_USER_CONFIRM_REPLY,
2217 MGMT_STATUS_INVALID_PARAMS);
2218
Johan Hedberg272d90d2012-02-09 15:26:12 +02002219 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
2220 MGMT_OP_USER_CONFIRM_REPLY,
2221 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002222}
2223
2224static int user_confirm_neg_reply(struct sock *sk, u16 index, void *data,
2225 u16 len)
2226{
Johan Hedbergc9c26592011-12-15 00:47:41 +02002227 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002228
2229 BT_DBG("");
2230
2231 if (len != sizeof(*cp))
2232 return cmd_status(sk, index, MGMT_OP_USER_CONFIRM_NEG_REPLY,
2233 MGMT_STATUS_INVALID_PARAMS);
2234
Johan Hedberg272d90d2012-02-09 15:26:12 +02002235 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
2236 MGMT_OP_USER_CONFIRM_NEG_REPLY,
2237 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002238}
2239
Brian Gix604086b2011-11-23 08:28:33 -08002240static int user_passkey_reply(struct sock *sk, u16 index, void *data, u16 len)
2241{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002242 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002243
2244 BT_DBG("");
2245
2246 if (len != sizeof(*cp))
2247 return cmd_status(sk, index, MGMT_OP_USER_PASSKEY_REPLY,
2248 EINVAL);
2249
Johan Hedberg272d90d2012-02-09 15:26:12 +02002250 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
2251 MGMT_OP_USER_PASSKEY_REPLY,
2252 HCI_OP_USER_PASSKEY_REPLY,
2253 cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08002254}
2255
2256static int user_passkey_neg_reply(struct sock *sk, u16 index, void *data,
2257 u16 len)
2258{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002259 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002260
2261 BT_DBG("");
2262
2263 if (len != sizeof(*cp))
2264 return cmd_status(sk, index, MGMT_OP_USER_PASSKEY_NEG_REPLY,
2265 EINVAL);
2266
Johan Hedberg272d90d2012-02-09 15:26:12 +02002267 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
2268 MGMT_OP_USER_PASSKEY_NEG_REPLY,
2269 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08002270}
2271
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002272static int set_local_name(struct sock *sk, u16 index, void *data,
Johan Hedbergb312b1612011-03-16 14:29:37 +02002273 u16 len)
2274{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002275 struct mgmt_cp_set_local_name *mgmt_cp = data;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002276 struct hci_cp_write_local_name hci_cp;
2277 struct hci_dev *hdev;
2278 struct pending_cmd *cmd;
2279 int err;
2280
2281 BT_DBG("");
2282
2283 if (len != sizeof(*mgmt_cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02002284 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME,
2285 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002286
2287 hdev = hci_dev_get(index);
2288 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002289 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME,
2290 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002291
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002292 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002293
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002294 memcpy(hdev->short_name, mgmt_cp->short_name,
2295 sizeof(hdev->short_name));
2296
Johan Hedbergb5235a62012-02-21 14:32:24 +02002297 if (!hdev_is_powered(hdev)) {
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002298 memcpy(hdev->dev_name, mgmt_cp->name, sizeof(hdev->dev_name));
2299
2300 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
2301 data, len);
2302 if (err < 0)
2303 goto failed;
2304
2305 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data, len,
2306 sk);
2307
Johan Hedbergb5235a62012-02-21 14:32:24 +02002308 goto failed;
2309 }
2310
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002311 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002312 if (!cmd) {
2313 err = -ENOMEM;
2314 goto failed;
2315 }
2316
2317 memcpy(hci_cp.name, mgmt_cp->name, sizeof(hci_cp.name));
2318 err = hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(hci_cp),
2319 &hci_cp);
2320 if (err < 0)
2321 mgmt_pending_remove(cmd);
2322
2323failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002324 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002325 hci_dev_put(hdev);
2326
2327 return err;
2328}
2329
Szymon Jancc35938b2011-03-22 13:12:21 +01002330static int read_local_oob_data(struct sock *sk, u16 index)
2331{
2332 struct hci_dev *hdev;
2333 struct pending_cmd *cmd;
2334 int err;
2335
2336 BT_DBG("hci%u", index);
2337
2338 hdev = hci_dev_get(index);
2339 if (!hdev)
2340 return cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002341 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancc35938b2011-03-22 13:12:21 +01002342
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002343 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002344
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002345 if (!hdev_is_powered(hdev)) {
Szymon Jancc35938b2011-03-22 13:12:21 +01002346 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002347 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002348 goto unlock;
2349 }
2350
2351 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
2352 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002353 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002354 goto unlock;
2355 }
2356
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002357 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02002358 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2359 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01002360 goto unlock;
2361 }
2362
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002363 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01002364 if (!cmd) {
2365 err = -ENOMEM;
2366 goto unlock;
2367 }
2368
2369 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
2370 if (err < 0)
2371 mgmt_pending_remove(cmd);
2372
2373unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002374 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002375 hci_dev_put(hdev);
2376
2377 return err;
2378}
2379
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002380static int add_remote_oob_data(struct sock *sk, u16 index, void *data,
2381 u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002382{
2383 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002384 struct mgmt_cp_add_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002385 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002386 int err;
2387
2388 BT_DBG("hci%u ", index);
2389
2390 if (len != sizeof(*cp))
2391 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002392 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01002393
2394 hdev = hci_dev_get(index);
2395 if (!hdev)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002396 return cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
2397 MGMT_STATUS_INVALID_PARAMS,
2398 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002399
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002400 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002401
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002402 if (!hdev_is_powered(hdev)) {
2403 err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
2404 MGMT_STATUS_NOT_POWERED,
2405 &cp->addr, sizeof(cp->addr));
2406 goto unlock;
2407 }
2408
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002409 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, cp->hash,
Szymon Janc2763eda2011-03-22 13:12:22 +01002410 cp->randomizer);
2411 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002412 status = MGMT_STATUS_FAILED;
Szymon Janc2763eda2011-03-22 13:12:22 +01002413 else
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002414 status = 0;
2415
2416 err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, status,
2417 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002418
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002419unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002420 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002421 hci_dev_put(hdev);
2422
2423 return err;
2424}
2425
2426static int remove_remote_oob_data(struct sock *sk, u16 index,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002427 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002428{
2429 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002430 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002431 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002432 int err;
2433
2434 BT_DBG("hci%u ", index);
2435
2436 if (len != sizeof(*cp))
2437 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002438 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01002439
2440 hdev = hci_dev_get(index);
2441 if (!hdev)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002442 return cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2443 MGMT_STATUS_INVALID_PARAMS,
2444 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002445
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002446 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002447
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002448 if (!hdev_is_powered(hdev)) {
2449 err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2450 MGMT_STATUS_NOT_POWERED,
2451 &cp->addr, sizeof(cp->addr));
2452 goto unlock;
2453 }
2454
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002455 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr);
Szymon Janc2763eda2011-03-22 13:12:22 +01002456 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002457 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01002458 else
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002459 status = 0;
2460
2461 err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA, status,
2462 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002463
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002464unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002465 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002466 hci_dev_put(hdev);
2467
2468 return err;
2469}
2470
Andre Guedes5e0452c2012-02-17 20:39:38 -03002471static int discovery(struct hci_dev *hdev)
2472{
2473 int err;
2474
2475 if (lmp_host_le_capable(hdev)) {
2476 if (lmp_bredr_capable(hdev)) {
2477 err = hci_le_scan(hdev, LE_SCAN_TYPE,
2478 LE_SCAN_INT, LE_SCAN_WIN,
2479 LE_SCAN_TIMEOUT_BREDR_LE);
2480 } else {
2481 hdev->discovery.type = DISCOV_TYPE_LE;
2482 err = hci_le_scan(hdev, LE_SCAN_TYPE,
2483 LE_SCAN_INT, LE_SCAN_WIN,
2484 LE_SCAN_TIMEOUT_LE_ONLY);
2485 }
2486 } else {
2487 hdev->discovery.type = DISCOV_TYPE_BREDR;
2488 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
2489 }
2490
2491 return err;
2492}
2493
2494int mgmt_interleaved_discovery(struct hci_dev *hdev)
2495{
2496 int err;
2497
2498 BT_DBG("%s", hdev->name);
2499
2500 hci_dev_lock(hdev);
2501
2502 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR_LE);
2503 if (err < 0)
2504 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2505
2506 hci_dev_unlock(hdev);
2507
2508 return err;
2509}
2510
Johan Hedberg450dfda2011-11-12 11:58:22 +02002511static int start_discovery(struct sock *sk, u16 index,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002512 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002513{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002514 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002515 struct pending_cmd *cmd;
2516 struct hci_dev *hdev;
2517 int err;
2518
2519 BT_DBG("hci%u", index);
2520
Johan Hedberg450dfda2011-11-12 11:58:22 +02002521 if (len != sizeof(*cp))
2522 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2523 MGMT_STATUS_INVALID_PARAMS);
2524
Johan Hedberg14a53662011-04-27 10:29:56 -04002525 hdev = hci_dev_get(index);
2526 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002527 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2528 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg14a53662011-04-27 10:29:56 -04002529
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002530 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002531
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002532 if (!hdev_is_powered(hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02002533 err = cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2534 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02002535 goto failed;
2536 }
2537
Johan Hedbergff9ef572012-01-04 14:23:45 +02002538 if (hdev->discovery.state != DISCOVERY_STOPPED) {
2539 err = cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2540 MGMT_STATUS_BUSY);
2541 goto failed;
2542 }
2543
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002544 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002545 if (!cmd) {
2546 err = -ENOMEM;
2547 goto failed;
2548 }
2549
Andre Guedes4aab14e2012-02-17 20:39:36 -03002550 hdev->discovery.type = cp->type;
2551
2552 switch (hdev->discovery.type) {
Andre Guedesf39799f2012-02-17 20:39:35 -03002553 case DISCOV_TYPE_BREDR:
Andre Guedes3fd24152012-02-03 17:48:01 -03002554 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
Andre Guedesf39799f2012-02-17 20:39:35 -03002555 break;
2556
2557 case DISCOV_TYPE_LE:
Andre Guedes3fd24152012-02-03 17:48:01 -03002558 err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT,
2559 LE_SCAN_WIN, LE_SCAN_TIMEOUT_LE_ONLY);
Andre Guedesf39799f2012-02-17 20:39:35 -03002560 break;
2561
Andre Guedes5e0452c2012-02-17 20:39:38 -03002562 case DISCOV_TYPE_INTERLEAVED:
2563 err = discovery(hdev);
2564 break;
2565
Andre Guedesf39799f2012-02-17 20:39:35 -03002566 default:
Andre Guedes3fd24152012-02-03 17:48:01 -03002567 err = -EINVAL;
Andre Guedesf39799f2012-02-17 20:39:35 -03002568 }
Andre Guedes3fd24152012-02-03 17:48:01 -03002569
Johan Hedberg14a53662011-04-27 10:29:56 -04002570 if (err < 0)
2571 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002572 else
2573 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002574
2575failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002576 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002577 hci_dev_put(hdev);
2578
2579 return err;
2580}
2581
Johan Hedbergd9306502012-02-20 23:25:18 +02002582static int stop_discovery(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002583{
Johan Hedbergd9306502012-02-20 23:25:18 +02002584 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002585 struct hci_dev *hdev;
2586 struct pending_cmd *cmd;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002587 struct hci_cp_remote_name_req_cancel cp;
2588 struct inquiry_entry *e;
Johan Hedberg14a53662011-04-27 10:29:56 -04002589 int err;
2590
2591 BT_DBG("hci%u", index);
2592
Johan Hedbergd9306502012-02-20 23:25:18 +02002593 if (len != sizeof(*mgmt_cp))
2594 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY,
2595 MGMT_STATUS_INVALID_PARAMS);
2596
Johan Hedberg14a53662011-04-27 10:29:56 -04002597 hdev = hci_dev_get(index);
2598 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002599 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY,
2600 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg14a53662011-04-27 10:29:56 -04002601
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002602 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002603
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002604 if (!hci_discovery_active(hdev)) {
Johan Hedbergd9306502012-02-20 23:25:18 +02002605 err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY,
2606 MGMT_STATUS_REJECTED,
2607 &mgmt_cp->type, sizeof(mgmt_cp->type));
2608 goto unlock;
2609 }
2610
2611 if (hdev->discovery.type != mgmt_cp->type) {
2612 err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY,
2613 MGMT_STATUS_INVALID_PARAMS,
2614 &mgmt_cp->type, sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002615 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02002616 }
2617
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002618 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002619 if (!cmd) {
2620 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002621 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04002622 }
2623
Andre Guedes343f9352012-02-17 20:39:37 -03002624 if (hdev->discovery.state == DISCOVERY_FINDING) {
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002625 err = hci_cancel_inquiry(hdev);
2626 if (err < 0)
2627 mgmt_pending_remove(cmd);
2628 else
2629 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
2630 goto unlock;
2631 }
2632
2633 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY, NAME_PENDING);
2634 if (!e) {
2635 mgmt_pending_remove(cmd);
Johan Hedbergaee9b212012-02-18 15:07:59 +02002636 err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY, 0,
Johan Hedbergd9306502012-02-20 23:25:18 +02002637 &mgmt_cp->type, sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002638 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2639 goto unlock;
2640 }
2641
2642 bacpy(&cp.bdaddr, &e->data.bdaddr);
2643 err = hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ_CANCEL,
2644 sizeof(cp), &cp);
Johan Hedberg14a53662011-04-27 10:29:56 -04002645 if (err < 0)
2646 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002647 else
2648 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002649
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002650unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002651 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002652 hci_dev_put(hdev);
2653
2654 return err;
2655}
2656
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002657static int confirm_name(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02002658{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002659 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002660 struct inquiry_entry *e;
2661 struct hci_dev *hdev;
2662 int err;
2663
2664 BT_DBG("hci%u", index);
2665
2666 if (len != sizeof(*cp))
2667 return cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2668 MGMT_STATUS_INVALID_PARAMS);
2669
2670 hdev = hci_dev_get(index);
2671 if (!hdev)
2672 return cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2673 MGMT_STATUS_INVALID_PARAMS);
2674
2675 hci_dev_lock(hdev);
2676
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002677 if (!hci_discovery_active(hdev)) {
2678 err = cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2679 MGMT_STATUS_FAILED);
2680 goto failed;
2681 }
2682
Johan Hedberga198e7b2012-02-17 14:27:06 +02002683 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002684 if (!e) {
Marcel Holtmanne5f0e152012-02-22 11:59:01 +01002685 err = cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
Johan Hedberg561aafb2012-01-04 13:31:59 +02002686 MGMT_STATUS_INVALID_PARAMS);
2687 goto failed;
2688 }
2689
2690 if (cp->name_known) {
2691 e->name_state = NAME_KNOWN;
2692 list_del(&e->list);
2693 } else {
2694 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e202012-01-09 00:53:02 +02002695 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002696 }
2697
2698 err = 0;
2699
2700failed:
2701 hci_dev_unlock(hdev);
2702
2703 return err;
2704}
2705
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002706static int block_device(struct sock *sk, u16 index, void *data, u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002707{
2708 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002709 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002710 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03002711 int err;
2712
2713 BT_DBG("hci%u", index);
2714
Antti Julku7fbec222011-06-15 12:01:15 +03002715 if (len != sizeof(*cp))
2716 return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002717 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002718
2719 hdev = hci_dev_get(index);
2720 if (!hdev)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002721 return cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE,
2722 MGMT_STATUS_INVALID_PARAMS,
2723 &cp->addr, sizeof(cp->addr));
Antti Julku7fbec222011-06-15 12:01:15 +03002724
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002725 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002726
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002727 err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002728 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002729 status = MGMT_STATUS_FAILED;
Antti Julku7fbec222011-06-15 12:01:15 +03002730 else
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002731 status = 0;
2732
2733 err = cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE, status,
2734 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03002735
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002736 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002737 hci_dev_put(hdev);
2738
2739 return err;
2740}
2741
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002742static int unblock_device(struct sock *sk, u16 index, void *data, u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002743{
2744 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002745 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002746 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03002747 int err;
2748
2749 BT_DBG("hci%u", index);
2750
Antti Julku7fbec222011-06-15 12:01:15 +03002751 if (len != sizeof(*cp))
2752 return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002753 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002754
2755 hdev = hci_dev_get(index);
2756 if (!hdev)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002757 return cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE,
2758 MGMT_STATUS_INVALID_PARAMS,
2759 &cp->addr, sizeof(cp->addr));
Antti Julku7fbec222011-06-15 12:01:15 +03002760
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002761 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002762
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002763 err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002764 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002765 status = MGMT_STATUS_INVALID_PARAMS;
Antti Julku7fbec222011-06-15 12:01:15 +03002766 else
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002767 status = 0;
2768
2769 err = cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE, status,
2770 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03002771
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002772 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002773 hci_dev_put(hdev);
2774
2775 return err;
2776}
2777
Antti Julkuf6422ec2011-06-22 13:11:56 +03002778static int set_fast_connectable(struct sock *sk, u16 index,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002779 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03002780{
2781 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002782 struct mgmt_mode *cp = data;
Antti Julkuf6422ec2011-06-22 13:11:56 +03002783 struct hci_cp_write_page_scan_activity acp;
2784 u8 type;
2785 int err;
2786
2787 BT_DBG("hci%u", index);
2788
2789 if (len != sizeof(*cp))
2790 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002791 MGMT_STATUS_INVALID_PARAMS);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002792
2793 hdev = hci_dev_get(index);
2794 if (!hdev)
2795 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002796 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg5400c042012-02-21 16:40:33 +02002797 if (!hdev_is_powered(hdev))
2798 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
2799 MGMT_STATUS_NOT_POWERED);
2800
2801 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
2802 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
2803 MGMT_STATUS_REJECTED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002804
2805 hci_dev_lock(hdev);
2806
Johan Hedbergf7c6869ce2011-12-15 00:47:36 +02002807 if (cp->val) {
Antti Julkuf6422ec2011-06-22 13:11:56 +03002808 type = PAGE_SCAN_TYPE_INTERLACED;
2809 acp.interval = 0x0024; /* 22.5 msec page scan interval */
2810 } else {
2811 type = PAGE_SCAN_TYPE_STANDARD; /* default */
2812 acp.interval = 0x0800; /* default 1.28 sec page scan */
2813 }
2814
2815 acp.window = 0x0012; /* default 11.25 msec page scan window */
2816
2817 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
2818 sizeof(acp), &acp);
2819 if (err < 0) {
2820 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002821 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002822 goto done;
2823 }
2824
2825 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
2826 if (err < 0) {
2827 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002828 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002829 goto done;
2830 }
2831
Johan Hedbergaee9b212012-02-18 15:07:59 +02002832 err = cmd_complete(sk, index, MGMT_OP_SET_FAST_CONNECTABLE, 0,
2833 NULL, 0);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002834done:
2835 hci_dev_unlock(hdev);
2836 hci_dev_put(hdev);
2837
2838 return err;
2839}
2840
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002841static int load_long_term_keys(struct sock *sk, u16 index,
2842 void *cp_data, u16 len)
2843{
2844 struct hci_dev *hdev;
2845 struct mgmt_cp_load_long_term_keys *cp = cp_data;
2846 u16 key_count, expected_len;
2847 int i;
2848
2849 if (len < sizeof(*cp))
2850 return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS,
2851 EINVAL);
2852
2853 key_count = get_unaligned_le16(&cp->key_count);
2854
2855 expected_len = sizeof(*cp) + key_count *
2856 sizeof(struct mgmt_ltk_info);
2857 if (expected_len != len) {
2858 BT_ERR("load_keys: expected %u bytes, got %u bytes",
2859 len, expected_len);
2860 return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS,
2861 EINVAL);
2862 }
2863
2864 hdev = hci_dev_get(index);
2865 if (!hdev)
2866 return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS,
2867 ENODEV);
2868
2869 BT_DBG("hci%u key_count %u", index, key_count);
2870
2871 hci_dev_lock(hdev);
2872
2873 hci_smp_ltks_clear(hdev);
2874
2875 for (i = 0; i < key_count; i++) {
2876 struct mgmt_ltk_info *key = &cp->keys[i];
2877 u8 type;
2878
2879 if (key->master)
2880 type = HCI_SMP_LTK;
2881 else
2882 type = HCI_SMP_LTK_SLAVE;
2883
2884 hci_add_ltk(hdev, &key->addr.bdaddr, key->addr.type,
2885 type, 0, key->authenticated, key->val,
2886 key->enc_size, key->ediv, key->rand);
2887 }
2888
2889 hci_dev_unlock(hdev);
2890 hci_dev_put(hdev);
2891
2892 return 0;
2893}
2894
Johan Hedberg03811012010-12-08 00:21:06 +02002895int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
2896{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002897 void *buf;
2898 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02002899 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002900 u16 opcode, index, len;
Johan Hedberg03811012010-12-08 00:21:06 +02002901 int err;
2902
2903 BT_DBG("got %zu bytes", msglen);
2904
2905 if (msglen < sizeof(*hdr))
2906 return -EINVAL;
2907
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03002908 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02002909 if (!buf)
2910 return -ENOMEM;
2911
2912 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
2913 err = -EFAULT;
2914 goto done;
2915 }
2916
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002917 hdr = buf;
Johan Hedberg03811012010-12-08 00:21:06 +02002918 opcode = get_unaligned_le16(&hdr->opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002919 index = get_unaligned_le16(&hdr->index);
Johan Hedberg03811012010-12-08 00:21:06 +02002920 len = get_unaligned_le16(&hdr->len);
2921
2922 if (len != msglen - sizeof(*hdr)) {
2923 err = -EINVAL;
2924 goto done;
2925 }
2926
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002927 cp = buf + sizeof(*hdr);
2928
Johan Hedberg03811012010-12-08 00:21:06 +02002929 switch (opcode) {
Johan Hedberg02d98122010-12-13 21:07:04 +02002930 case MGMT_OP_READ_VERSION:
2931 err = read_version(sk);
2932 break;
Johan Hedberge70bb2e2012-02-13 16:59:33 +02002933 case MGMT_OP_READ_COMMANDS:
2934 err = read_commands(sk);
2935 break;
Johan Hedbergfaba42e2010-12-13 21:07:05 +02002936 case MGMT_OP_READ_INDEX_LIST:
2937 err = read_index_list(sk);
2938 break;
Johan Hedbergf7b64e692010-12-13 21:07:06 +02002939 case MGMT_OP_READ_INFO:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002940 err = read_controller_info(sk, index);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02002941 break;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002942 case MGMT_OP_SET_POWERED:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002943 err = set_powered(sk, index, cp, len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002944 break;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002945 case MGMT_OP_SET_DISCOVERABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002946 err = set_discoverable(sk, index, cp, len);
Johan Hedberg73f22f62010-12-29 16:00:25 +02002947 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002948 case MGMT_OP_SET_CONNECTABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002949 err = set_connectable(sk, index, cp, len);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002950 break;
Johan Hedbergf7c6869ce2011-12-15 00:47:36 +02002951 case MGMT_OP_SET_FAST_CONNECTABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002952 err = set_fast_connectable(sk, index, cp, len);
Johan Hedbergf7c6869ce2011-12-15 00:47:36 +02002953 break;
Johan Hedbergc542a062011-01-26 13:11:03 +02002954 case MGMT_OP_SET_PAIRABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002955 err = set_pairable(sk, index, cp, len);
Johan Hedbergc542a062011-01-26 13:11:03 +02002956 break;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02002957 case MGMT_OP_SET_LINK_SECURITY:
2958 err = set_link_security(sk, index, cp, len);
2959 break;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02002960 case MGMT_OP_SET_SSP:
2961 err = set_ssp(sk, index, cp, len);
2962 break;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02002963 case MGMT_OP_SET_HS:
2964 err = set_hs(sk, index, cp, len);
2965 break;
Johan Hedberg06199cf2012-02-22 16:37:11 +02002966 case MGMT_OP_SET_LE:
2967 err = set_le(sk, index, cp, len);
2968 break;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002969 case MGMT_OP_ADD_UUID:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002970 err = add_uuid(sk, index, cp, len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002971 break;
2972 case MGMT_OP_REMOVE_UUID:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002973 err = remove_uuid(sk, index, cp, len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002974 break;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002975 case MGMT_OP_SET_DEV_CLASS:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002976 err = set_dev_class(sk, index, cp, len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002977 break;
Johan Hedberg86742e12011-11-07 23:13:38 +02002978 case MGMT_OP_LOAD_LINK_KEYS:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002979 err = load_link_keys(sk, index, cp, len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002980 break;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002981 case MGMT_OP_DISCONNECT:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002982 err = disconnect(sk, index, cp, len);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002983 break;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002984 case MGMT_OP_GET_CONNECTIONS:
Szymon Janc8ce62842011-03-01 16:55:32 +01002985 err = get_connections(sk, index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002986 break;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002987 case MGMT_OP_PIN_CODE_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002988 err = pin_code_reply(sk, index, cp, len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002989 break;
2990 case MGMT_OP_PIN_CODE_NEG_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002991 err = pin_code_neg_reply(sk, index, cp, len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002992 break;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002993 case MGMT_OP_SET_IO_CAPABILITY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002994 err = set_io_capability(sk, index, cp, len);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002995 break;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002996 case MGMT_OP_PAIR_DEVICE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002997 err = pair_device(sk, index, cp, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002998 break;
Johan Hedberg28424702012-02-02 04:02:29 +02002999 case MGMT_OP_CANCEL_PAIR_DEVICE:
3000 err = cancel_pair_device(sk, index, buf + sizeof(*hdr), len);
3001 break;
Johan Hedberg124f6e32012-02-09 13:50:12 +02003002 case MGMT_OP_UNPAIR_DEVICE:
3003 err = unpair_device(sk, index, cp, len);
3004 break;
Johan Hedberga5c29682011-02-19 12:05:57 -03003005 case MGMT_OP_USER_CONFIRM_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003006 err = user_confirm_reply(sk, index, cp, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03003007 break;
3008 case MGMT_OP_USER_CONFIRM_NEG_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003009 err = user_confirm_neg_reply(sk, index, cp, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03003010 break;
Brian Gix604086b2011-11-23 08:28:33 -08003011 case MGMT_OP_USER_PASSKEY_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003012 err = user_passkey_reply(sk, index, cp, len);
Brian Gix604086b2011-11-23 08:28:33 -08003013 break;
3014 case MGMT_OP_USER_PASSKEY_NEG_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003015 err = user_passkey_neg_reply(sk, index, cp, len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003016 break;
Johan Hedbergb312b1612011-03-16 14:29:37 +02003017 case MGMT_OP_SET_LOCAL_NAME:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003018 err = set_local_name(sk, index, cp, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003019 break;
Szymon Jancc35938b2011-03-22 13:12:21 +01003020 case MGMT_OP_READ_LOCAL_OOB_DATA:
3021 err = read_local_oob_data(sk, index);
3022 break;
Szymon Janc2763eda2011-03-22 13:12:22 +01003023 case MGMT_OP_ADD_REMOTE_OOB_DATA:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003024 err = add_remote_oob_data(sk, index, cp, len);
Szymon Janc2763eda2011-03-22 13:12:22 +01003025 break;
3026 case MGMT_OP_REMOVE_REMOTE_OOB_DATA:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003027 err = remove_remote_oob_data(sk, index, cp, len);
Szymon Janc2763eda2011-03-22 13:12:22 +01003028 break;
Johan Hedberg14a53662011-04-27 10:29:56 -04003029 case MGMT_OP_START_DISCOVERY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003030 err = start_discovery(sk, index, cp, len);
Johan Hedberg14a53662011-04-27 10:29:56 -04003031 break;
3032 case MGMT_OP_STOP_DISCOVERY:
Johan Hedbergd9306502012-02-20 23:25:18 +02003033 err = stop_discovery(sk, index, cp, len);
Johan Hedberg14a53662011-04-27 10:29:56 -04003034 break;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003035 case MGMT_OP_CONFIRM_NAME:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003036 err = confirm_name(sk, index, cp, len);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003037 break;
Antti Julku7fbec222011-06-15 12:01:15 +03003038 case MGMT_OP_BLOCK_DEVICE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003039 err = block_device(sk, index, cp, len);
Antti Julku7fbec222011-06-15 12:01:15 +03003040 break;
3041 case MGMT_OP_UNBLOCK_DEVICE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003042 err = unblock_device(sk, index, cp, len);
Antti Julku7fbec222011-06-15 12:01:15 +03003043 break;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003044 case MGMT_OP_LOAD_LONG_TERM_KEYS:
3045 err = load_long_term_keys(sk, index, cp, len);
3046 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003047 default:
Johan Hedberg72a734e2010-12-30 00:38:22 +02003048 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02003049 err = cmd_status(sk, index, opcode,
3050 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003051 break;
3052 }
Johan Hedberg72a734e2010-12-30 00:38:22 +02003053
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003054 if (err < 0)
Johan Hedberg72a734e2010-12-30 00:38:22 +02003055 goto done;
3056
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003057 err = msglen;
3058
3059done:
3060 kfree(buf);
3061 return err;
3062}
3063
Johan Hedbergb24752f2011-11-03 14:40:33 +02003064static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
3065{
3066 u8 *status = data;
3067
3068 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
3069 mgmt_pending_remove(cmd);
3070}
3071
Johan Hedberg744cf192011-11-08 20:40:14 +02003072int mgmt_index_added(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +02003073{
Johan Hedberg744cf192011-11-08 20:40:14 +02003074 return mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02003075}
3076
Johan Hedberg744cf192011-11-08 20:40:14 +02003077int mgmt_index_removed(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +02003078{
Johan Hedbergb24752f2011-11-03 14:40:33 +02003079 u8 status = ENODEV;
3080
Johan Hedberg744cf192011-11-08 20:40:14 +02003081 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02003082
Johan Hedberg744cf192011-11-08 20:40:14 +02003083 return mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02003084}
3085
3086struct cmd_lookup {
Johan Hedberg03811012010-12-08 00:21:06 +02003087 struct sock *sk;
Johan Hedberg69ab39e2011-12-15 00:47:35 +02003088 struct hci_dev *hdev;
Johan Hedberg03811012010-12-08 00:21:06 +02003089};
3090
Johan Hedberg69ab39e2011-12-15 00:47:35 +02003091static void settings_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberg03811012010-12-08 00:21:06 +02003092{
Johan Hedberg03811012010-12-08 00:21:06 +02003093 struct cmd_lookup *match = data;
3094
Johan Hedberg69ab39e2011-12-15 00:47:35 +02003095 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02003096
3097 list_del(&cmd->list);
3098
3099 if (match->sk == NULL) {
3100 match->sk = cmd->sk;
3101 sock_hold(match->sk);
3102 }
3103
3104 mgmt_pending_free(cmd);
3105}
3106
Johan Hedberg744cf192011-11-08 20:40:14 +02003107int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg03811012010-12-08 00:21:06 +02003108{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02003109 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003110 int err;
Johan Hedberg03811012010-12-08 00:21:06 +02003111
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003112 if (!test_bit(HCI_MGMT, &hdev->dev_flags))
3113 return 0;
3114
Johan Hedberg69ab39e2011-12-15 00:47:35 +02003115 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
Johan Hedberg03811012010-12-08 00:21:06 +02003116
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003117 if (powered) {
3118 u8 scan = 0;
3119
3120 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3121 scan |= SCAN_PAGE;
3122 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3123 scan |= SCAN_INQUIRY;
3124
3125 if (scan)
3126 hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
Johan Hedberg504c8dc2012-02-23 13:30:41 +02003127
3128 update_class(hdev);
3129 update_eir(hdev);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003130 } else {
Johan Hedbergb24752f2011-11-03 14:40:33 +02003131 u8 status = ENETDOWN;
Johan Hedberg744cf192011-11-08 20:40:14 +02003132 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02003133 }
3134
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003135 err = new_settings(hdev, match.sk);
Johan Hedberg03811012010-12-08 00:21:06 +02003136
3137 if (match.sk)
3138 sock_put(match.sk);
3139
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003140 return err;
Johan Hedberg03811012010-12-08 00:21:06 +02003141}
3142
Johan Hedberg744cf192011-11-08 20:40:14 +02003143int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg03811012010-12-08 00:21:06 +02003144{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02003145 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003146 bool changed = false;
3147 int err = 0;
Johan Hedberg03811012010-12-08 00:21:06 +02003148
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003149 if (discoverable) {
3150 if (!test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3151 changed = true;
3152 } else {
3153 if (test_and_clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3154 changed = true;
3155 }
Johan Hedberg03811012010-12-08 00:21:06 +02003156
Johan Hedberged9b5f22012-02-21 20:47:06 +02003157 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp,
3158 &match);
3159
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003160 if (changed)
3161 err = new_settings(hdev, match.sk);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003162
Johan Hedberg03811012010-12-08 00:21:06 +02003163 if (match.sk)
3164 sock_put(match.sk);
3165
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003166 return err;
Johan Hedberg03811012010-12-08 00:21:06 +02003167}
3168
Johan Hedberg744cf192011-11-08 20:40:14 +02003169int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg03811012010-12-08 00:21:06 +02003170{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02003171 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003172 bool changed = false;
3173 int err = 0;
Johan Hedberg03811012010-12-08 00:21:06 +02003174
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003175 if (connectable) {
3176 if (!test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3177 changed = true;
3178 } else {
3179 if (test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3180 changed = true;
3181 }
Johan Hedberg03811012010-12-08 00:21:06 +02003182
Johan Hedberged9b5f22012-02-21 20:47:06 +02003183 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev, settings_rsp,
3184 &match);
3185
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003186 if (changed)
3187 err = new_settings(hdev, match.sk);
Johan Hedberg03811012010-12-08 00:21:06 +02003188
3189 if (match.sk)
3190 sock_put(match.sk);
3191
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003192 return err;
Johan Hedberg03811012010-12-08 00:21:06 +02003193}
3194
Johan Hedberg744cf192011-11-08 20:40:14 +02003195int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003196{
Johan Hedbergca69b792011-11-11 18:10:00 +02003197 u8 mgmt_err = mgmt_status(status);
3198
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003199 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02003200 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Johan Hedbergca69b792011-11-11 18:10:00 +02003201 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003202
3203 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02003204 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Johan Hedbergca69b792011-11-11 18:10:00 +02003205 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003206
3207 return 0;
3208}
3209
Johan Hedberg744cf192011-11-08 20:40:14 +02003210int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
3211 u8 persistent)
Johan Hedberg03811012010-12-08 00:21:06 +02003212{
Johan Hedberg86742e12011-11-07 23:13:38 +02003213 struct mgmt_ev_new_link_key ev;
Johan Hedberg03811012010-12-08 00:21:06 +02003214
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003215 memset(&ev, 0, sizeof(ev));
Johan Hedberg03811012010-12-08 00:21:06 +02003216
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003217 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02003218 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
3219 ev.key.addr.type = MGMT_ADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003220 ev.key.type = key->type;
3221 memcpy(ev.key.val, key->val, 16);
3222 ev.key.pin_len = key->pin_len;
Johan Hedberg03811012010-12-08 00:21:06 +02003223
Johan Hedberg744cf192011-11-08 20:40:14 +02003224 return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02003225}
Johan Hedbergf7520542011-01-20 12:34:39 +02003226
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003227int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
3228{
3229 struct mgmt_ev_new_long_term_key ev;
3230
3231 memset(&ev, 0, sizeof(ev));
3232
3233 ev.store_hint = persistent;
3234 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
3235 ev.key.addr.type = key->bdaddr_type;
3236 ev.key.authenticated = key->authenticated;
3237 ev.key.enc_size = key->enc_size;
3238 ev.key.ediv = key->ediv;
3239
3240 if (key->type == HCI_SMP_LTK)
3241 ev.key.master = 1;
3242
3243 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
3244 memcpy(ev.key.val, key->val, sizeof(key->val));
3245
3246 return mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev,
3247 &ev, sizeof(ev), NULL);
3248}
3249
Johan Hedbergafc747a2012-01-15 18:11:07 +02003250int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Johan Hedbergb644ba32012-01-17 21:48:47 +02003251 u8 addr_type, u8 *name, u8 name_len,
3252 u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02003253{
Johan Hedbergb644ba32012-01-17 21:48:47 +02003254 char buf[512];
3255 struct mgmt_ev_device_connected *ev = (void *) buf;
3256 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02003257
Johan Hedbergb644ba32012-01-17 21:48:47 +02003258 bacpy(&ev->addr.bdaddr, bdaddr);
3259 ev->addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02003260
Johan Hedbergb644ba32012-01-17 21:48:47 +02003261 if (name_len > 0)
3262 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
3263 name, name_len);
3264
3265 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
3266 eir_len = eir_append_data(&ev->eir[eir_len], eir_len,
3267 EIR_CLASS_OF_DEV, dev_class, 3);
3268
3269 put_unaligned_le16(eir_len, &ev->eir_len);
3270
3271 return mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
3272 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02003273}
3274
Johan Hedberg8962ee72011-01-20 12:40:27 +02003275static void disconnect_rsp(struct pending_cmd *cmd, void *data)
3276{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01003277 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003278 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02003279 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003280
Johan Hedberg88c3df12012-02-09 14:27:38 +02003281 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3282 rp.addr.type = cp->addr.type;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003283
Johan Hedbergaee9b212012-02-18 15:07:59 +02003284 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, 0, &rp,
3285 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003286
3287 *sk = cmd->sk;
3288 sock_hold(*sk);
3289
Johan Hedberga664b5b2011-02-19 12:06:02 -03003290 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003291}
3292
Johan Hedberg124f6e32012-02-09 13:50:12 +02003293static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02003294{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003295 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02003296 struct mgmt_cp_unpair_device *cp = cmd->param;
3297 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02003298
3299 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02003300 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3301 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02003302
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003303 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
3304
Johan Hedbergaee9b212012-02-18 15:07:59 +02003305 cmd_complete(cmd->sk, cmd->index, cmd->opcode, 0, &rp, sizeof(rp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02003306
3307 mgmt_pending_remove(cmd);
3308}
3309
Johan Hedbergafc747a2012-01-15 18:11:07 +02003310int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
3311 u8 link_type, u8 addr_type)
Johan Hedbergf7520542011-01-20 12:34:39 +02003312{
Johan Hedberg4c659c32011-11-07 23:13:39 +02003313 struct mgmt_addr_info ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003314 struct sock *sk = NULL;
3315 int err;
3316
Johan Hedberg744cf192011-11-08 20:40:14 +02003317 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02003318
Johan Hedbergf7520542011-01-20 12:34:39 +02003319 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02003320 ev.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02003321
Johan Hedbergafc747a2012-01-15 18:11:07 +02003322 err = mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev),
3323 sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003324
3325 if (sk)
3326 sock_put(sk);
3327
Johan Hedberg124f6e32012-02-09 13:50:12 +02003328 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003329 hdev);
Johan Hedberga8a1d192011-11-10 15:54:38 +02003330
Johan Hedberg8962ee72011-01-20 12:40:27 +02003331 return err;
3332}
3333
Johan Hedberg88c3df12012-02-09 14:27:38 +02003334int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
3335 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02003336{
Johan Hedberg88c3df12012-02-09 14:27:38 +02003337 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003338 struct pending_cmd *cmd;
3339 int err;
3340
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003341 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003342 if (!cmd)
3343 return -ENOENT;
3344
Johan Hedberg88c3df12012-02-09 14:27:38 +02003345 bacpy(&rp.addr.bdaddr, bdaddr);
3346 rp.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02003347
Johan Hedberg88c3df12012-02-09 14:27:38 +02003348 err = cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
Johan Hedbergaee9b212012-02-18 15:07:59 +02003349 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003350
Johan Hedberga664b5b2011-02-19 12:06:02 -03003351 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003352
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003353 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
3354 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003355 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02003356}
Johan Hedberg17d5c042011-01-22 06:09:08 +02003357
Johan Hedberg48264f02011-11-09 13:58:58 +02003358int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
3359 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02003360{
3361 struct mgmt_ev_connect_failed ev;
3362
Johan Hedberg4c659c32011-11-07 23:13:39 +02003363 bacpy(&ev.addr.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02003364 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003365 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003366
Johan Hedberg744cf192011-11-08 20:40:14 +02003367 return mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003368}
Johan Hedberg980e1a52011-01-22 06:10:07 +02003369
Johan Hedberg744cf192011-11-08 20:40:14 +02003370int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003371{
3372 struct mgmt_ev_pin_code_request ev;
3373
Johan Hedbergd8457692012-02-17 14:24:57 +02003374 bacpy(&ev.addr.bdaddr, bdaddr);
3375 ev.addr.type = MGMT_ADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02003376 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003377
Johan Hedberg744cf192011-11-08 20:40:14 +02003378 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01003379 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003380}
3381
Johan Hedberg744cf192011-11-08 20:40:14 +02003382int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3383 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003384{
3385 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003386 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003387 int err;
3388
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003389 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003390 if (!cmd)
3391 return -ENOENT;
3392
Johan Hedbergd8457692012-02-17 14:24:57 +02003393 bacpy(&rp.addr.bdaddr, bdaddr);
3394 rp.addr.type = MGMT_ADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003395
Johan Hedbergaee9b212012-02-18 15:07:59 +02003396 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
3397 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003398
Johan Hedberga664b5b2011-02-19 12:06:02 -03003399 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003400
3401 return err;
3402}
3403
Johan Hedberg744cf192011-11-08 20:40:14 +02003404int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3405 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003406{
3407 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003408 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003409 int err;
3410
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003411 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003412 if (!cmd)
3413 return -ENOENT;
3414
Johan Hedbergd8457692012-02-17 14:24:57 +02003415 bacpy(&rp.addr.bdaddr, bdaddr);
3416 rp.addr.type = MGMT_ADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003417
Johan Hedbergaee9b212012-02-18 15:07:59 +02003418 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
3419 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003420
Johan Hedberga664b5b2011-02-19 12:06:02 -03003421 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003422
3423 return err;
3424}
Johan Hedberga5c29682011-02-19 12:05:57 -03003425
Johan Hedberg744cf192011-11-08 20:40:14 +02003426int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003427 u8 link_type, u8 addr_type, __le32 value,
3428 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03003429{
3430 struct mgmt_ev_user_confirm_request ev;
3431
Johan Hedberg744cf192011-11-08 20:40:14 +02003432 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03003433
Johan Hedberg272d90d2012-02-09 15:26:12 +02003434 bacpy(&ev.addr.bdaddr, bdaddr);
3435 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07003436 ev.confirm_hint = confirm_hint;
Johan Hedberga5c29682011-02-19 12:05:57 -03003437 put_unaligned_le32(value, &ev.value);
3438
Johan Hedberg744cf192011-11-08 20:40:14 +02003439 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01003440 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03003441}
3442
Johan Hedberg272d90d2012-02-09 15:26:12 +02003443int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
3444 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08003445{
3446 struct mgmt_ev_user_passkey_request ev;
3447
3448 BT_DBG("%s", hdev->name);
3449
Johan Hedberg272d90d2012-02-09 15:26:12 +02003450 bacpy(&ev.addr.bdaddr, bdaddr);
3451 ev.addr.type = link_to_mgmt(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08003452
3453 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
3454 NULL);
3455}
3456
Brian Gix0df4c182011-11-16 13:53:13 -08003457static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003458 u8 link_type, u8 addr_type, u8 status,
3459 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03003460{
3461 struct pending_cmd *cmd;
3462 struct mgmt_rp_user_confirm_reply rp;
3463 int err;
3464
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003465 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03003466 if (!cmd)
3467 return -ENOENT;
3468
Johan Hedberg272d90d2012-02-09 15:26:12 +02003469 bacpy(&rp.addr.bdaddr, bdaddr);
3470 rp.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergaee9b212012-02-18 15:07:59 +02003471 err = cmd_complete(cmd->sk, hdev->id, opcode, mgmt_status(status),
3472 &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03003473
Johan Hedberga664b5b2011-02-19 12:06:02 -03003474 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03003475
3476 return err;
3477}
3478
Johan Hedberg744cf192011-11-08 20:40:14 +02003479int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003480 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003481{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003482 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3483 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003484}
3485
Johan Hedberg272d90d2012-02-09 15:26:12 +02003486int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3487 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003488{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003489 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3490 status, MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003491}
Johan Hedberg2a611692011-02-19 12:06:00 -03003492
Brian Gix604086b2011-11-23 08:28:33 -08003493int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003494 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003495{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003496 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3497 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003498}
3499
Johan Hedberg272d90d2012-02-09 15:26:12 +02003500int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3501 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003502{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003503 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3504 status, MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003505}
3506
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003507int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
3508 u8 addr_type, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03003509{
3510 struct mgmt_ev_auth_failed ev;
3511
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003512 bacpy(&ev.addr.bdaddr, bdaddr);
3513 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003514 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03003515
Johan Hedberg744cf192011-11-08 20:40:14 +02003516 return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03003517}
Johan Hedbergb312b1612011-03-16 14:29:37 +02003518
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003519int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
3520{
3521 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg47990ea2012-02-22 11:58:37 +02003522 bool changed = false;
3523 int err = 0;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003524
3525 if (status) {
3526 u8 mgmt_err = mgmt_status(status);
3527 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
3528 cmd_status_rsp, &mgmt_err);
3529 return 0;
3530 }
3531
Johan Hedberg47990ea2012-02-22 11:58:37 +02003532 if (test_bit(HCI_AUTH, &hdev->flags)) {
3533 if (!test_and_set_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
3534 changed = true;
3535 } else {
3536 if (test_and_clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
3537 changed = true;
3538 }
3539
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003540 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
3541 &match);
3542
Johan Hedberg47990ea2012-02-22 11:58:37 +02003543 if (changed)
3544 err = new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003545
3546 if (match.sk)
3547 sock_put(match.sk);
3548
3549 return err;
3550}
3551
Johan Hedbergcacaf522012-02-21 00:52:42 +02003552static int clear_eir(struct hci_dev *hdev)
3553{
3554 struct hci_cp_write_eir cp;
3555
3556 if (!(hdev->features[6] & LMP_EXT_INQ))
3557 return 0;
3558
Johan Hedbergc80da272012-02-22 15:38:48 +02003559 memset(hdev->eir, 0, sizeof(hdev->eir));
3560
Johan Hedbergcacaf522012-02-21 00:52:42 +02003561 memset(&cp, 0, sizeof(cp));
3562
3563 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
3564}
3565
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003566int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003567{
3568 struct cmd_lookup match = { NULL, hdev };
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003569 bool changed = false;
3570 int err = 0;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003571
3572 if (status) {
3573 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003574
3575 if (enable && test_and_clear_bit(HCI_SSP_ENABLED,
3576 &hdev->dev_flags))
3577 err = new_settings(hdev, NULL);
3578
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003579 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev,
3580 cmd_status_rsp, &mgmt_err);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003581
3582 return err;
3583 }
3584
3585 if (enable) {
3586 if (!test_and_set_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3587 changed = true;
3588 } else {
3589 if (test_and_clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3590 changed = true;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003591 }
3592
3593 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
3594
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003595 if (changed)
3596 err = new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003597
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02003598 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003599 sock_put(match.sk);
3600
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02003601 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3602 update_eir(hdev);
3603 else
3604 clear_eir(hdev);
Johan Hedbergcacaf522012-02-21 00:52:42 +02003605
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003606 return err;
3607}
3608
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003609int mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
3610 u8 status)
3611{
3612 int err;
3613
3614 err = mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class, 3, NULL);
3615
3616 return err;
3617}
3618
Johan Hedberg744cf192011-11-08 20:40:14 +02003619int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02003620{
3621 struct pending_cmd *cmd;
3622 struct mgmt_cp_set_local_name ev;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003623 bool changed = false;
3624 int err = 0;
3625
3626 if (memcmp(name, hdev->dev_name, sizeof(hdev->dev_name)) != 0) {
3627 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
3628 changed = true;
3629 }
Johan Hedbergb312b1612011-03-16 14:29:37 +02003630
3631 memset(&ev, 0, sizeof(ev));
3632 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003633 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003634
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003635 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003636 if (!cmd)
3637 goto send_event;
3638
Johan Hedberg7bdaae42012-02-22 21:39:58 +02003639 /* Always assume that either the short or the complete name has
3640 * changed if there was a pending mgmt command */
3641 changed = true;
3642
Johan Hedbergb312b1612011-03-16 14:29:37 +02003643 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02003644 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
Johan Hedbergca69b792011-11-11 18:10:00 +02003645 mgmt_status(status));
Johan Hedbergb312b1612011-03-16 14:29:37 +02003646 goto failed;
3647 }
3648
Johan Hedbergaee9b212012-02-18 15:07:59 +02003649 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0, &ev,
Johan Hedbergb312b1612011-03-16 14:29:37 +02003650 sizeof(ev));
3651 if (err < 0)
3652 goto failed;
3653
3654send_event:
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003655 if (changed)
3656 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev,
3657 sizeof(ev), cmd ? cmd->sk : NULL);
3658
Johan Hedbergf51d5b22012-02-22 18:17:32 +02003659 update_eir(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003660
3661failed:
3662 if (cmd)
3663 mgmt_pending_remove(cmd);
3664 return err;
3665}
Szymon Jancc35938b2011-03-22 13:12:21 +01003666
Johan Hedberg744cf192011-11-08 20:40:14 +02003667int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
3668 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01003669{
3670 struct pending_cmd *cmd;
3671 int err;
3672
Johan Hedberg744cf192011-11-08 20:40:14 +02003673 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01003674
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003675 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003676 if (!cmd)
3677 return -ENOENT;
3678
3679 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02003680 err = cmd_status(cmd->sk, hdev->id,
Johan Hedbergca69b792011-11-11 18:10:00 +02003681 MGMT_OP_READ_LOCAL_OOB_DATA,
3682 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01003683 } else {
3684 struct mgmt_rp_read_local_oob_data rp;
3685
3686 memcpy(rp.hash, hash, sizeof(rp.hash));
3687 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
3688
Johan Hedberg744cf192011-11-08 20:40:14 +02003689 err = cmd_complete(cmd->sk, hdev->id,
3690 MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergaee9b212012-02-18 15:07:59 +02003691 0, &rp, sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01003692 }
3693
3694 mgmt_pending_remove(cmd);
3695
3696 return err;
3697}
Johan Hedberge17acd42011-03-30 23:57:16 +03003698
Johan Hedberg06199cf2012-02-22 16:37:11 +02003699int mgmt_le_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
3700{
3701 struct cmd_lookup match = { NULL, hdev };
3702 bool changed = false;
3703 int err = 0;
3704
3705 if (status) {
3706 u8 mgmt_err = mgmt_status(status);
3707
3708 if (enable && test_and_clear_bit(HCI_LE_ENABLED,
3709 &hdev->dev_flags))
3710 err = new_settings(hdev, NULL);
3711
3712 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev,
3713 cmd_status_rsp, &mgmt_err);
3714
3715 return err;
3716 }
3717
3718 if (enable) {
3719 if (!test_and_set_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3720 changed = true;
3721 } else {
3722 if (test_and_clear_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3723 changed = true;
3724 }
3725
3726 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
3727
3728 if (changed)
3729 err = new_settings(hdev, match.sk);
3730
3731 if (match.sk)
3732 sock_put(match.sk);
3733
3734 return err;
3735}
3736
Johan Hedberg48264f02011-11-09 13:58:58 +02003737int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Johan Hedberg561aafb2012-01-04 13:31:59 +02003738 u8 addr_type, u8 *dev_class, s8 rssi,
Johan Hedberg388fc8f2012-02-23 00:38:59 +02003739 u8 cfm_name, u8 ssp, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03003740{
Johan Hedberge319d2e2012-01-15 19:51:59 +02003741 char buf[512];
3742 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02003743 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03003744
Johan Hedberg1dc06092012-01-15 21:01:23 +02003745 /* Leave 5 bytes for a potential CoD field */
3746 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Andre Guedes7d262f82012-01-10 18:20:49 -03003747 return -EINVAL;
3748
Johan Hedberg1dc06092012-01-15 21:01:23 +02003749 memset(buf, 0, sizeof(buf));
3750
Johan Hedberge319d2e2012-01-15 19:51:59 +02003751 bacpy(&ev->addr.bdaddr, bdaddr);
3752 ev->addr.type = link_to_mgmt(link_type, addr_type);
3753 ev->rssi = rssi;
Johan Hedberg9a395a82012-02-23 00:00:32 +02003754 if (cfm_name)
3755 ev->flags[0] |= MGMT_DEV_FOUND_CONFIRM_NAME;
Johan Hedberg388fc8f2012-02-23 00:38:59 +02003756 if (!ssp)
3757 ev->flags[0] |= MGMT_DEV_FOUND_LEGACY_PAIRING;
Johan Hedberge17acd42011-03-30 23:57:16 +03003758
Johan Hedberg1dc06092012-01-15 21:01:23 +02003759 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02003760 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03003761
Johan Hedberg1dc06092012-01-15 21:01:23 +02003762 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
3763 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
3764 dev_class, 3);
3765
3766 put_unaligned_le16(eir_len, &ev->eir_len);
3767
3768 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03003769
Johan Hedberge319d2e2012-01-15 19:51:59 +02003770 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03003771}
Johan Hedberga88a9652011-03-30 13:18:12 +03003772
Johan Hedbergb644ba32012-01-17 21:48:47 +02003773int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
3774 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03003775{
Johan Hedbergb644ba32012-01-17 21:48:47 +02003776 struct mgmt_ev_device_found *ev;
3777 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
3778 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03003779
Johan Hedbergb644ba32012-01-17 21:48:47 +02003780 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03003781
Johan Hedbergb644ba32012-01-17 21:48:47 +02003782 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03003783
Johan Hedbergb644ba32012-01-17 21:48:47 +02003784 bacpy(&ev->addr.bdaddr, bdaddr);
3785 ev->addr.type = link_to_mgmt(link_type, addr_type);
3786 ev->rssi = rssi;
3787
3788 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
3789 name_len);
3790
3791 put_unaligned_le16(eir_len, &ev->eir_len);
3792
Johan Hedberg053c7e02012-02-04 00:06:00 +02003793 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev,
3794 sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03003795}
Johan Hedberg314b2382011-04-27 10:29:57 -04003796
Andre Guedes7a135102011-11-09 17:14:25 -03003797int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
Johan Hedberg164a6e72011-11-01 17:06:44 +02003798{
3799 struct pending_cmd *cmd;
Johan Hedbergf808e162012-02-19 12:52:07 +02003800 u8 type;
Johan Hedberg164a6e72011-11-01 17:06:44 +02003801 int err;
3802
Andre Guedes203159d2012-02-13 15:41:01 -03003803 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3804
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003805 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003806 if (!cmd)
3807 return -ENOENT;
3808
Johan Hedbergf808e162012-02-19 12:52:07 +02003809 type = hdev->discovery.type;
3810
3811 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
3812 &type, sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02003813 mgmt_pending_remove(cmd);
3814
3815 return err;
3816}
3817
Andre Guedese6d465c2011-11-09 17:14:26 -03003818int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
3819{
3820 struct pending_cmd *cmd;
3821 int err;
3822
3823 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
3824 if (!cmd)
3825 return -ENOENT;
3826
Johan Hedbergd9306502012-02-20 23:25:18 +02003827 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
3828 &hdev->discovery.type,
3829 sizeof(hdev->discovery.type));
Johan Hedberg03811012010-12-08 00:21:06 +02003830 mgmt_pending_remove(cmd);
3831
3832 return err;
3833}
Johan Hedberg314b2382011-04-27 10:29:57 -04003834
Johan Hedberg744cf192011-11-08 20:40:14 +02003835int mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04003836{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02003837 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02003838 struct pending_cmd *cmd;
3839
Andre Guedes343fb142011-11-22 17:14:19 -03003840 BT_DBG("%s discovering %u", hdev->name, discovering);
3841
Johan Hedberg164a6e72011-11-01 17:06:44 +02003842 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003843 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003844 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003845 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003846
3847 if (cmd != NULL) {
Johan Hedbergf808e162012-02-19 12:52:07 +02003848 u8 type = hdev->discovery.type;
3849
Johan Hedbergd9306502012-02-20 23:25:18 +02003850 cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0,
Johan Hedbergf808e162012-02-19 12:52:07 +02003851 &type, sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02003852 mgmt_pending_remove(cmd);
3853 }
3854
Johan Hedbergf963e8e2012-02-20 23:30:44 +02003855 memset(&ev, 0, sizeof(ev));
3856 ev.type = hdev->discovery.type;
3857 ev.discovering = discovering;
3858
3859 return mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04003860}
Antti Julku5e762442011-08-25 16:48:02 +03003861
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003862int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003863{
3864 struct pending_cmd *cmd;
3865 struct mgmt_ev_device_blocked ev;
3866
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003867 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003868
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003869 bacpy(&ev.addr.bdaddr, bdaddr);
3870 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003871
Johan Hedberg744cf192011-11-08 20:40:14 +02003872 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
3873 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003874}
3875
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003876int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003877{
3878 struct pending_cmd *cmd;
3879 struct mgmt_ev_device_unblocked ev;
3880
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003881 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003882
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003883 bacpy(&ev.addr.bdaddr, bdaddr);
3884 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003885
Johan Hedberg744cf192011-11-08 20:40:14 +02003886 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
3887 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003888}
Marcel Holtmannd7b7e792012-02-20 21:47:49 +01003889
3890module_param(enable_hs, bool, 0644);
3891MODULE_PARM_DESC(enable_hs, "Enable High Speed support");
3892
3893module_param(enable_le, bool, 0644);
3894MODULE_PARM_DESC(enable_le, "Enable Low Energy support");