blob: 27830f4016989f512278f07be069f5937a8bd8fe [file] [log] [blame]
Johan Hedberg03811012010-12-08 00:21:06 +02001/*
2 BlueZ - Bluetooth protocol stack for Linux
Johan Hedbergea585ab2012-02-17 14:50:39 +02003
Johan Hedberg03811012010-12-08 00:21:06 +02004 Copyright (C) 2010 Nokia Corporation
Johan Hedbergea585ab2012-02-17 14:50:39 +02005 Copyright (C) 2011-2012 Intel Corporation
Johan Hedberg03811012010-12-08 00:21:06 +02006
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License version 2 as
9 published by the Free Software Foundation;
10
11 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
12 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
13 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
14 IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
15 CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
16 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19
20 ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
21 COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
22 SOFTWARE IS DISCLAIMED.
23*/
24
25/* Bluetooth HCI Management interface */
26
Johan Hedbergca69b792011-11-11 18:10:00 +020027#include <linux/kernel.h>
Szymon Janc72359752011-02-17 14:16:32 +010028#include <linux/uaccess.h>
Paul Gortmaker3a9a2312011-05-27 09:12:25 -040029#include <linux/module.h>
Johan Hedberg03811012010-12-08 00:21:06 +020030#include <asm/unaligned.h>
31
32#include <net/bluetooth/bluetooth.h>
33#include <net/bluetooth/hci_core.h>
34#include <net/bluetooth/mgmt.h>
Brian Gix5fe57d92011-12-21 16:12:13 -080035#include <net/bluetooth/smp.h>
Johan Hedberg03811012010-12-08 00:21:06 +020036
Marcel Holtmannd7b7e792012-02-20 21:47:49 +010037bool enable_hs;
38bool enable_le;
39
Johan Hedberg2da9c552012-02-17 14:39:28 +020040#define MGMT_VERSION 1
41#define MGMT_REVISION 0
Johan Hedberg02d98122010-12-13 21:07:04 +020042
Johan Hedberge70bb2e2012-02-13 16:59:33 +020043static const u16 mgmt_commands[] = {
44 MGMT_OP_READ_INDEX_LIST,
45 MGMT_OP_READ_INFO,
46 MGMT_OP_SET_POWERED,
47 MGMT_OP_SET_DISCOVERABLE,
48 MGMT_OP_SET_CONNECTABLE,
49 MGMT_OP_SET_FAST_CONNECTABLE,
50 MGMT_OP_SET_PAIRABLE,
51 MGMT_OP_SET_LINK_SECURITY,
52 MGMT_OP_SET_SSP,
53 MGMT_OP_SET_HS,
54 MGMT_OP_SET_LE,
55 MGMT_OP_SET_DEV_CLASS,
56 MGMT_OP_SET_LOCAL_NAME,
57 MGMT_OP_ADD_UUID,
58 MGMT_OP_REMOVE_UUID,
59 MGMT_OP_LOAD_LINK_KEYS,
60 MGMT_OP_LOAD_LONG_TERM_KEYS,
61 MGMT_OP_DISCONNECT,
62 MGMT_OP_GET_CONNECTIONS,
63 MGMT_OP_PIN_CODE_REPLY,
64 MGMT_OP_PIN_CODE_NEG_REPLY,
65 MGMT_OP_SET_IO_CAPABILITY,
66 MGMT_OP_PAIR_DEVICE,
67 MGMT_OP_CANCEL_PAIR_DEVICE,
68 MGMT_OP_UNPAIR_DEVICE,
69 MGMT_OP_USER_CONFIRM_REPLY,
70 MGMT_OP_USER_CONFIRM_NEG_REPLY,
71 MGMT_OP_USER_PASSKEY_REPLY,
72 MGMT_OP_USER_PASSKEY_NEG_REPLY,
73 MGMT_OP_READ_LOCAL_OOB_DATA,
74 MGMT_OP_ADD_REMOTE_OOB_DATA,
75 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
76 MGMT_OP_START_DISCOVERY,
77 MGMT_OP_STOP_DISCOVERY,
78 MGMT_OP_CONFIRM_NAME,
79 MGMT_OP_BLOCK_DEVICE,
80 MGMT_OP_UNBLOCK_DEVICE,
81};
82
83static const u16 mgmt_events[] = {
84 MGMT_EV_CONTROLLER_ERROR,
85 MGMT_EV_INDEX_ADDED,
86 MGMT_EV_INDEX_REMOVED,
87 MGMT_EV_NEW_SETTINGS,
88 MGMT_EV_CLASS_OF_DEV_CHANGED,
89 MGMT_EV_LOCAL_NAME_CHANGED,
90 MGMT_EV_NEW_LINK_KEY,
91 MGMT_EV_NEW_LONG_TERM_KEY,
92 MGMT_EV_DEVICE_CONNECTED,
93 MGMT_EV_DEVICE_DISCONNECTED,
94 MGMT_EV_CONNECT_FAILED,
95 MGMT_EV_PIN_CODE_REQUEST,
96 MGMT_EV_USER_CONFIRM_REQUEST,
97 MGMT_EV_USER_PASSKEY_REQUEST,
98 MGMT_EV_AUTH_FAILED,
99 MGMT_EV_DEVICE_FOUND,
100 MGMT_EV_DISCOVERING,
101 MGMT_EV_DEVICE_BLOCKED,
102 MGMT_EV_DEVICE_UNBLOCKED,
103 MGMT_EV_DEVICE_UNPAIRED,
104};
105
Andre Guedes3fd24152012-02-03 17:48:01 -0300106/*
107 * These LE scan and inquiry parameters were chosen according to LE General
108 * Discovery Procedure specification.
109 */
110#define LE_SCAN_TYPE 0x01
111#define LE_SCAN_WIN 0x12
112#define LE_SCAN_INT 0x12
113#define LE_SCAN_TIMEOUT_LE_ONLY 10240 /* TGAP(gen_disc_scan_min) */
Andre Guedes5e0452c2012-02-17 20:39:38 -0300114#define LE_SCAN_TIMEOUT_BREDR_LE 5120 /* TGAP(100)/2 */
Andre Guedes3fd24152012-02-03 17:48:01 -0300115
Andre Guedese8777522012-02-03 17:48:02 -0300116#define INQUIRY_LEN_BREDR 0x08 /* TGAP(100) */
Andre Guedes5e0452c2012-02-17 20:39:38 -0300117#define INQUIRY_LEN_BREDR_LE 0x04 /* TGAP(100)/2 */
Andre Guedes2519a1f2011-11-07 11:45:24 -0300118
Johan Hedberg7d785252011-12-15 00:47:39 +0200119#define SERVICE_CACHE_TIMEOUT (5 * 1000)
120
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200121#define hdev_is_powered(hdev) (test_bit(HCI_UP, &hdev->flags) && \
122 !test_bit(HCI_AUTO_OFF, &hdev->dev_flags))
123
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200124struct pending_cmd {
125 struct list_head list;
Johan Hedbergfc2f4b12011-11-09 13:58:56 +0200126 u16 opcode;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200127 int index;
Szymon Jancc68fb7f2011-03-22 13:12:19 +0100128 void *param;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200129 struct sock *sk;
Johan Hedberge9a416b2011-02-19 12:05:56 -0300130 void *user_data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200131};
132
Johan Hedbergca69b792011-11-11 18:10:00 +0200133/* HCI to MGMT error code conversion table */
134static u8 mgmt_status_table[] = {
135 MGMT_STATUS_SUCCESS,
136 MGMT_STATUS_UNKNOWN_COMMAND, /* Unknown Command */
137 MGMT_STATUS_NOT_CONNECTED, /* No Connection */
138 MGMT_STATUS_FAILED, /* Hardware Failure */
139 MGMT_STATUS_CONNECT_FAILED, /* Page Timeout */
140 MGMT_STATUS_AUTH_FAILED, /* Authentication Failed */
141 MGMT_STATUS_NOT_PAIRED, /* PIN or Key Missing */
142 MGMT_STATUS_NO_RESOURCES, /* Memory Full */
143 MGMT_STATUS_TIMEOUT, /* Connection Timeout */
144 MGMT_STATUS_NO_RESOURCES, /* Max Number of Connections */
145 MGMT_STATUS_NO_RESOURCES, /* Max Number of SCO Connections */
146 MGMT_STATUS_ALREADY_CONNECTED, /* ACL Connection Exists */
147 MGMT_STATUS_BUSY, /* Command Disallowed */
148 MGMT_STATUS_NO_RESOURCES, /* Rejected Limited Resources */
149 MGMT_STATUS_REJECTED, /* Rejected Security */
150 MGMT_STATUS_REJECTED, /* Rejected Personal */
151 MGMT_STATUS_TIMEOUT, /* Host Timeout */
152 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Feature */
153 MGMT_STATUS_INVALID_PARAMS, /* Invalid Parameters */
154 MGMT_STATUS_DISCONNECTED, /* OE User Ended Connection */
155 MGMT_STATUS_NO_RESOURCES, /* OE Low Resources */
156 MGMT_STATUS_DISCONNECTED, /* OE Power Off */
157 MGMT_STATUS_DISCONNECTED, /* Connection Terminated */
158 MGMT_STATUS_BUSY, /* Repeated Attempts */
159 MGMT_STATUS_REJECTED, /* Pairing Not Allowed */
160 MGMT_STATUS_FAILED, /* Unknown LMP PDU */
161 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Remote Feature */
162 MGMT_STATUS_REJECTED, /* SCO Offset Rejected */
163 MGMT_STATUS_REJECTED, /* SCO Interval Rejected */
164 MGMT_STATUS_REJECTED, /* Air Mode Rejected */
165 MGMT_STATUS_INVALID_PARAMS, /* Invalid LMP Parameters */
166 MGMT_STATUS_FAILED, /* Unspecified Error */
167 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported LMP Parameter Value */
168 MGMT_STATUS_FAILED, /* Role Change Not Allowed */
169 MGMT_STATUS_TIMEOUT, /* LMP Response Timeout */
170 MGMT_STATUS_FAILED, /* LMP Error Transaction Collision */
171 MGMT_STATUS_FAILED, /* LMP PDU Not Allowed */
172 MGMT_STATUS_REJECTED, /* Encryption Mode Not Accepted */
173 MGMT_STATUS_FAILED, /* Unit Link Key Used */
174 MGMT_STATUS_NOT_SUPPORTED, /* QoS Not Supported */
175 MGMT_STATUS_TIMEOUT, /* Instant Passed */
176 MGMT_STATUS_NOT_SUPPORTED, /* Pairing Not Supported */
177 MGMT_STATUS_FAILED, /* Transaction Collision */
178 MGMT_STATUS_INVALID_PARAMS, /* Unacceptable Parameter */
179 MGMT_STATUS_REJECTED, /* QoS Rejected */
180 MGMT_STATUS_NOT_SUPPORTED, /* Classification Not Supported */
181 MGMT_STATUS_REJECTED, /* Insufficient Security */
182 MGMT_STATUS_INVALID_PARAMS, /* Parameter Out Of Range */
183 MGMT_STATUS_BUSY, /* Role Switch Pending */
184 MGMT_STATUS_FAILED, /* Slot Violation */
185 MGMT_STATUS_FAILED, /* Role Switch Failed */
186 MGMT_STATUS_INVALID_PARAMS, /* EIR Too Large */
187 MGMT_STATUS_NOT_SUPPORTED, /* Simple Pairing Not Supported */
188 MGMT_STATUS_BUSY, /* Host Busy Pairing */
189 MGMT_STATUS_REJECTED, /* Rejected, No Suitable Channel */
190 MGMT_STATUS_BUSY, /* Controller Busy */
191 MGMT_STATUS_INVALID_PARAMS, /* Unsuitable Connection Interval */
192 MGMT_STATUS_TIMEOUT, /* Directed Advertising Timeout */
193 MGMT_STATUS_AUTH_FAILED, /* Terminated Due to MIC Failure */
194 MGMT_STATUS_CONNECT_FAILED, /* Connection Establishment Failed */
195 MGMT_STATUS_CONNECT_FAILED, /* MAC Connection Failed */
196};
197
198static u8 mgmt_status(u8 hci_status)
199{
200 if (hci_status < ARRAY_SIZE(mgmt_status_table))
201 return mgmt_status_table[hci_status];
202
203 return MGMT_STATUS_FAILED;
204}
205
Szymon Janc4e51eae2011-02-25 19:05:48 +0100206static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200207{
208 struct sk_buff *skb;
209 struct mgmt_hdr *hdr;
210 struct mgmt_ev_cmd_status *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300211 int err;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200212
Szymon Janc34eb5252011-02-28 14:10:08 +0100213 BT_DBG("sock %p, index %u, cmd %u, status %u", sk, index, cmd, status);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200214
215 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_ATOMIC);
216 if (!skb)
217 return -ENOMEM;
218
219 hdr = (void *) skb_put(skb, sizeof(*hdr));
220
221 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_STATUS);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100222 hdr->index = cpu_to_le16(index);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200223 hdr->len = cpu_to_le16(sizeof(*ev));
224
225 ev = (void *) skb_put(skb, sizeof(*ev));
226 ev->status = status;
227 put_unaligned_le16(cmd, &ev->opcode);
228
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300229 err = sock_queue_rcv_skb(sk, skb);
230 if (err < 0)
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200231 kfree_skb(skb);
232
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300233 return err;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200234}
235
Johan Hedbergaee9b2182012-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 Hedbergaee9b2182012-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 Hedbergaee9b2182012-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 Hedbergaee9b2182012-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 Hedbergaee9b2182012-02-18 15:07:59 +0200354 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST, 0, rp,
Szymon Janc4e51eae2011-02-25 19:05:48 +0100355 rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200356
Johan Hedberga38528f2011-01-22 06:46:43 +0200357 kfree(rp);
358
359 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200360}
361
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200362static u32 get_supported_settings(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +0200363{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200364 u32 settings = 0;
Johan Hedberg03811012010-12-08 00:21:06 +0200365
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200366 settings |= MGMT_SETTING_POWERED;
367 settings |= MGMT_SETTING_CONNECTABLE;
368 settings |= MGMT_SETTING_FAST_CONNECTABLE;
369 settings |= MGMT_SETTING_DISCOVERABLE;
370 settings |= MGMT_SETTING_PAIRABLE;
Johan Hedberg03811012010-12-08 00:21:06 +0200371
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200372 if (hdev->features[6] & LMP_SIMPLE_PAIR)
373 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200374
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200375 if (!(hdev->features[4] & LMP_NO_BREDR)) {
376 settings |= MGMT_SETTING_BREDR;
377 settings |= MGMT_SETTING_LINK_SECURITY;
378 }
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200379
Marcel Holtmannd7b7e792012-02-20 21:47:49 +0100380 if (enable_hs)
381 settings |= MGMT_SETTING_HS;
382
383 if (enable_le) {
384 if (hdev->features[4] & LMP_LE)
385 settings |= MGMT_SETTING_LE;
386 }
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200387
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200388 return settings;
389}
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200390
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200391static u32 get_current_settings(struct hci_dev *hdev)
392{
393 u32 settings = 0;
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200394
Johan Hedbergf1f0eb02012-02-21 17:15:41 +0200395 if (hdev_is_powered(hdev))
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100396 settings |= MGMT_SETTING_POWERED;
397
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200398 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200399 settings |= MGMT_SETTING_CONNECTABLE;
400
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200401 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200402 settings |= MGMT_SETTING_DISCOVERABLE;
403
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200404 if (test_bit(HCI_PAIRABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200405 settings |= MGMT_SETTING_PAIRABLE;
406
407 if (!(hdev->features[4] & LMP_NO_BREDR))
408 settings |= MGMT_SETTING_BREDR;
409
Johan Hedberg06199cf2012-02-22 16:37:11 +0200410 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200411 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200412
Johan Hedberg47990ea2012-02-22 11:58:37 +0200413 if (test_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200414 settings |= MGMT_SETTING_LINK_SECURITY;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200415
Johan Hedberg84bde9d2012-01-25 14:21:06 +0200416 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200417 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200418
Johan Hedberg6d80dfd2012-02-20 23:50:38 +0200419 if (test_bit(HCI_HS_ENABLED, &hdev->dev_flags))
420 settings |= MGMT_SETTING_HS;
421
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200422 return settings;
Johan Hedbergc542a062011-01-26 13:11:03 +0200423}
424
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300425#define PNP_INFO_SVCLASS_ID 0x1200
426
427static u8 bluetooth_base_uuid[] = {
428 0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80,
429 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
430};
431
432static u16 get_uuid16(u8 *uuid128)
433{
434 u32 val;
435 int i;
436
437 for (i = 0; i < 12; i++) {
438 if (bluetooth_base_uuid[i] != uuid128[i])
439 return 0;
440 }
441
442 memcpy(&val, &uuid128[12], 4);
443
444 val = le32_to_cpu(val);
445 if (val > 0xffff)
446 return 0;
447
448 return (u16) val;
449}
450
451static void create_eir(struct hci_dev *hdev, u8 *data)
452{
453 u8 *ptr = data;
454 u16 eir_len = 0;
455 u16 uuid16_list[HCI_MAX_EIR_LENGTH / sizeof(u16)];
456 int i, truncated = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200457 struct bt_uuid *uuid;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300458 size_t name_len;
459
460 name_len = strlen(hdev->dev_name);
461
462 if (name_len > 0) {
463 /* EIR Data type */
464 if (name_len > 48) {
465 name_len = 48;
466 ptr[1] = EIR_NAME_SHORT;
467 } else
468 ptr[1] = EIR_NAME_COMPLETE;
469
470 /* EIR Data length */
471 ptr[0] = name_len + 1;
472
473 memcpy(ptr + 2, hdev->dev_name, name_len);
474
475 eir_len += (name_len + 2);
476 ptr += (name_len + 2);
477 }
478
479 memset(uuid16_list, 0, sizeof(uuid16_list));
480
481 /* Group all UUID16 types */
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200482 list_for_each_entry(uuid, &hdev->uuids, list) {
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300483 u16 uuid16;
484
485 uuid16 = get_uuid16(uuid->uuid);
486 if (uuid16 == 0)
487 return;
488
489 if (uuid16 < 0x1100)
490 continue;
491
492 if (uuid16 == PNP_INFO_SVCLASS_ID)
493 continue;
494
495 /* Stop if not enough space to put next UUID */
496 if (eir_len + 2 + sizeof(u16) > HCI_MAX_EIR_LENGTH) {
497 truncated = 1;
498 break;
499 }
500
501 /* Check for duplicates */
502 for (i = 0; uuid16_list[i] != 0; i++)
503 if (uuid16_list[i] == uuid16)
504 break;
505
506 if (uuid16_list[i] == 0) {
507 uuid16_list[i] = uuid16;
508 eir_len += sizeof(u16);
509 }
510 }
511
512 if (uuid16_list[0] != 0) {
513 u8 *length = ptr;
514
515 /* EIR Data type */
516 ptr[1] = truncated ? EIR_UUID16_SOME : EIR_UUID16_ALL;
517
518 ptr += 2;
519 eir_len += 2;
520
521 for (i = 0; uuid16_list[i] != 0; i++) {
522 *ptr++ = (uuid16_list[i] & 0x00ff);
523 *ptr++ = (uuid16_list[i] & 0xff00) >> 8;
524 }
525
526 /* EIR Data length */
527 *length = (i * sizeof(u16)) + 1;
528 }
529}
530
531static int update_eir(struct hci_dev *hdev)
532{
533 struct hci_cp_write_eir cp;
534
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200535 if (!hdev_is_powered(hdev))
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200536 return 0;
537
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300538 if (!(hdev->features[6] & LMP_EXT_INQ))
539 return 0;
540
Johan Hedberg84bde9d2012-01-25 14:21:06 +0200541 if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300542 return 0;
543
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200544 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300545 return 0;
546
547 memset(&cp, 0, sizeof(cp));
548
549 create_eir(hdev, cp.data);
550
551 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
552 return 0;
553
554 memcpy(hdev->eir, cp.data, sizeof(cp.data));
555
556 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
557}
558
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200559static u8 get_service_classes(struct hci_dev *hdev)
560{
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300561 struct bt_uuid *uuid;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200562 u8 val = 0;
563
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300564 list_for_each_entry(uuid, &hdev->uuids, list)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200565 val |= uuid->svc_hint;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200566
567 return val;
568}
569
570static int update_class(struct hci_dev *hdev)
571{
572 u8 cod[3];
Johan Hedbergc95f0ba2012-02-23 22:54:38 +0200573 int err;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200574
575 BT_DBG("%s", hdev->name);
576
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200577 if (!hdev_is_powered(hdev))
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200578 return 0;
579
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200580 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200581 return 0;
582
583 cod[0] = hdev->minor_class;
584 cod[1] = hdev->major_class;
585 cod[2] = get_service_classes(hdev);
586
587 if (memcmp(cod, hdev->dev_class, 3) == 0)
588 return 0;
589
Johan Hedbergc95f0ba2012-02-23 22:54:38 +0200590 err = hci_send_cmd(hdev, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
591 if (err == 0)
592 set_bit(HCI_PENDING_CLASS, &hdev->dev_flags);
593
594 return err;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200595}
596
Johan Hedberg7d785252011-12-15 00:47:39 +0200597static void service_cache_off(struct work_struct *work)
598{
599 struct hci_dev *hdev = container_of(work, struct hci_dev,
600 service_cache.work);
601
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200602 if (!test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200603 return;
604
605 hci_dev_lock(hdev);
606
607 update_eir(hdev);
608 update_class(hdev);
609
610 hci_dev_unlock(hdev);
611}
612
613static void mgmt_init_hdev(struct hci_dev *hdev)
614{
Johan Hedberg0cbf4ed62012-02-21 17:25:22 +0200615 if (!test_and_set_bit(HCI_MGMT, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +0200616 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
617
Johan Hedberg0cbf4ed62012-02-21 17:25:22 +0200618 /* Non-mgmt controlled devices get this bit set
619 * implicitly so that pairing works for them, however
620 * for mgmt we require user-space to explicitly enable
621 * it
622 */
623 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
624 }
Johan Hedberg7d785252011-12-15 00:47:39 +0200625}
626
Johan Hedberg03811012010-12-08 00:21:06 +0200627static int read_controller_info(struct sock *sk, u16 index)
628{
629 struct mgmt_rp_read_info rp;
630 struct hci_dev *hdev;
631
632 BT_DBG("sock %p hci%u", sk, index);
633
634 hdev = hci_dev_get(index);
635 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200636 return cmd_status(sk, index, MGMT_OP_READ_INFO,
637 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200638
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300639 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200640
Johan Hedberg7d785252011-12-15 00:47:39 +0200641 if (test_and_clear_bit(HCI_PI_MGMT_INIT, &hci_pi(sk)->flags))
642 mgmt_init_hdev(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200643
644 memset(&rp, 0, sizeof(rp));
645
Johan Hedberg03811012010-12-08 00:21:06 +0200646 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200647
648 rp.version = hdev->hci_ver;
649
Johan Hedberg03811012010-12-08 00:21:06 +0200650 put_unaligned_le16(hdev->manufacturer, &rp.manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200651
652 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
653 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
654
655 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedberg03811012010-12-08 00:21:06 +0200656
657 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
Johan Hedberg27fcc362012-02-22 21:46:22 +0200658 memcpy(rp.short_name, hdev->short_name, sizeof(hdev->short_name));
Johan Hedberg03811012010-12-08 00:21:06 +0200659
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300660 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200661 hci_dev_put(hdev);
662
Johan Hedbergaee9b2182012-02-18 15:07:59 +0200663 return cmd_complete(sk, index, MGMT_OP_READ_INFO, 0, &rp, sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +0200664}
665
666static void mgmt_pending_free(struct pending_cmd *cmd)
667{
668 sock_put(cmd->sk);
669 kfree(cmd->param);
670 kfree(cmd);
671}
672
673static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
674 struct hci_dev *hdev,
675 void *data, u16 len)
676{
677 struct pending_cmd *cmd;
678
679 cmd = kmalloc(sizeof(*cmd), GFP_ATOMIC);
680 if (!cmd)
681 return NULL;
682
683 cmd->opcode = opcode;
684 cmd->index = hdev->id;
685
686 cmd->param = kmalloc(len, GFP_ATOMIC);
687 if (!cmd->param) {
688 kfree(cmd);
689 return NULL;
690 }
691
692 if (data)
693 memcpy(cmd->param, data, len);
694
695 cmd->sk = sk;
696 sock_hold(sk);
697
698 list_add(&cmd->list, &hdev->mgmt_pending);
699
700 return cmd;
701}
702
703static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
704 void (*cb)(struct pending_cmd *cmd, void *data),
705 void *data)
706{
707 struct list_head *p, *n;
708
709 list_for_each_safe(p, n, &hdev->mgmt_pending) {
710 struct pending_cmd *cmd;
711
712 cmd = list_entry(p, struct pending_cmd, list);
713
714 if (opcode > 0 && cmd->opcode != opcode)
715 continue;
716
717 cb(cmd, data);
718 }
719}
720
721static struct pending_cmd *mgmt_pending_find(u16 opcode, struct hci_dev *hdev)
722{
723 struct pending_cmd *cmd;
724
725 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
726 if (cmd->opcode == opcode)
727 return cmd;
728 }
729
730 return NULL;
731}
732
733static void mgmt_pending_remove(struct pending_cmd *cmd)
734{
735 list_del(&cmd->list);
736 mgmt_pending_free(cmd);
737}
738
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200739static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +0200740{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200741 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +0200742
Johan Hedbergaee9b2182012-02-18 15:07:59 +0200743 return cmd_complete(sk, hdev->id, opcode, 0, &settings,
744 sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +0200745}
746
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300747static int set_powered(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200748{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300749 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200750 struct hci_dev *hdev;
751 struct pending_cmd *cmd;
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200752 int err;
Johan Hedberg03811012010-12-08 00:21:06 +0200753
Johan Hedberg03811012010-12-08 00:21:06 +0200754 BT_DBG("request for hci%u", index);
755
756 if (len != sizeof(*cp))
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
760 hdev = hci_dev_get(index);
761 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200762 return cmd_status(sk, index, MGMT_OP_SET_POWERED,
763 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200764
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300765 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200766
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100767 if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) {
768 cancel_delayed_work(&hdev->power_off);
769
770 if (cp->val) {
771 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
772 mgmt_powered(hdev, 1);
773 goto failed;
774 }
775 }
776
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200777 if (!!cp->val == hdev_is_powered(hdev)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200778 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200779 goto failed;
780 }
781
782 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200783 err = cmd_status(sk, index, MGMT_OP_SET_POWERED,
784 MGMT_STATUS_BUSY);
Johan Hedberg03811012010-12-08 00:21:06 +0200785 goto failed;
786 }
787
788 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
789 if (!cmd) {
790 err = -ENOMEM;
791 goto failed;
792 }
793
794 if (cp->val)
Gustavo F. Padovan7f971042011-12-18 12:40:32 -0200795 schedule_work(&hdev->power_on);
Johan Hedberg03811012010-12-08 00:21:06 +0200796 else
Gustavo F. Padovan80b7ab32011-12-17 14:52:27 -0200797 schedule_work(&hdev->power_off.work);
Johan Hedberg03811012010-12-08 00:21:06 +0200798
799 err = 0;
800
801failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300802 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200803 hci_dev_put(hdev);
804 return err;
805}
806
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200807static int mgmt_event(u16 event, struct hci_dev *hdev, void *data,
808 u16 data_len, struct sock *skip_sk)
809{
810 struct sk_buff *skb;
811 struct mgmt_hdr *hdr;
812
813 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_ATOMIC);
814 if (!skb)
815 return -ENOMEM;
816
817 hdr = (void *) skb_put(skb, sizeof(*hdr));
818 hdr->opcode = cpu_to_le16(event);
819 if (hdev)
820 hdr->index = cpu_to_le16(hdev->id);
821 else
822 hdr->index = cpu_to_le16(MGMT_INDEX_NONE);
823 hdr->len = cpu_to_le16(data_len);
824
825 if (data)
826 memcpy(skb_put(skb, data_len), data, data_len);
827
Marcel Holtmann97e0bde2012-02-22 13:49:28 +0100828 /* Time stamp */
829 __net_timestamp(skb);
830
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200831 hci_send_to_control(skb, skip_sk);
832 kfree_skb(skb);
833
834 return 0;
835}
836
837static int new_settings(struct hci_dev *hdev, struct sock *skip)
838{
839 __le32 ev;
840
841 ev = cpu_to_le32(get_current_settings(hdev));
842
843 return mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), skip);
844}
845
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300846static int set_discoverable(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200847{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300848 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberge41d8b42010-12-13 21:07:03 +0200849 struct hci_dev *hdev;
Johan Hedberg03811012010-12-08 00:21:06 +0200850 struct pending_cmd *cmd;
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200851 u16 timeout;
Johan Hedberg03811012010-12-08 00:21:06 +0200852 u8 scan;
853 int err;
854
Johan Hedberg03811012010-12-08 00:21:06 +0200855 BT_DBG("request for hci%u", index);
856
857 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200858 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
859 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200860
Marcel Holtmann24c54a92012-02-22 18:06:34 +0100861 timeout = get_unaligned_le16(&cp->timeout);
862 if (!cp->val && timeout > 0)
863 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
864 MGMT_STATUS_INVALID_PARAMS);
865
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200866 hdev = hci_dev_get(index);
867 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200868 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
869 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200870
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300871 hci_dev_lock(hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200872
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200873 if (!hdev_is_powered(hdev) && timeout > 0) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200874 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
875 MGMT_STATUS_NOT_POWERED);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200876 goto failed;
877 }
878
879 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
880 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200881 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
882 MGMT_STATUS_BUSY);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200883 goto failed;
884 }
885
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200886 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) {
887 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
888 MGMT_STATUS_REJECTED);
889 goto failed;
890 }
891
892 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200893 bool changed = false;
894
895 if (!!cp->val != test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
896 change_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
897 changed = true;
898 }
899
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200900 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200901 if (err < 0)
902 goto failed;
903
904 if (changed)
905 err = new_settings(hdev, sk);
906
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200907 goto failed;
908 }
909
910 if (!!cp->val == test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
Marcel Holtmann955638e2012-02-22 18:21:00 +0100911 if (hdev->discov_timeout > 0) {
912 cancel_delayed_work(&hdev->discov_off);
913 hdev->discov_timeout = 0;
914 }
915
916 if (cp->val && timeout > 0) {
917 hdev->discov_timeout = timeout;
918 queue_delayed_work(hdev->workqueue, &hdev->discov_off,
919 msecs_to_jiffies(hdev->discov_timeout * 1000));
920 }
921
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200922 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200923 goto failed;
924 }
925
926 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
927 if (!cmd) {
928 err = -ENOMEM;
929 goto failed;
930 }
931
932 scan = SCAN_PAGE;
933
934 if (cp->val)
935 scan |= SCAN_INQUIRY;
936 else
937 cancel_delayed_work(&hdev->discov_off);
938
939 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
940 if (err < 0)
941 mgmt_pending_remove(cmd);
942
Johan Hedberg03811012010-12-08 00:21:06 +0200943 if (cp->val)
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200944 hdev->discov_timeout = timeout;
Johan Hedberg03811012010-12-08 00:21:06 +0200945
946failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300947 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200948 hci_dev_put(hdev);
949
950 return err;
951}
952
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300953static int set_connectable(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200954{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300955 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200956 struct hci_dev *hdev;
957 struct pending_cmd *cmd;
958 u8 scan;
959 int err;
960
Johan Hedberge41d8b42010-12-13 21:07:03 +0200961 BT_DBG("request for hci%u", index);
962
Johan Hedberg03811012010-12-08 00:21:06 +0200963 if (len != sizeof(*cp))
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
967 hdev = hci_dev_get(index);
968 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200969 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
970 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200971
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300972 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200973
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200974 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200975 bool changed = false;
976
977 if (!!cp->val != test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
978 changed = true;
979
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +0200980 if (cp->val) {
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200981 set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +0200982 } else {
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200983 clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
984 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
985 }
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200986
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200987 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200988 if (err < 0)
989 goto failed;
990
991 if (changed)
992 err = new_settings(hdev, sk);
993
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200994 goto failed;
995 }
996
997 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
998 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200999 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
1000 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001001 goto failed;
1002 }
1003
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001004 if (!!cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001005 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001006 goto failed;
1007 }
1008
1009 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
1010 if (!cmd) {
1011 err = -ENOMEM;
1012 goto failed;
1013 }
1014
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001015 if (cp->val) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001016 scan = SCAN_PAGE;
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001017 } else {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001018 scan = 0;
1019
Johan Hedbergdf2c6c52012-02-21 19:15:49 +02001020 if (test_bit(HCI_ISCAN, &hdev->flags) &&
1021 hdev->discov_timeout > 0)
1022 cancel_delayed_work(&hdev->discov_off);
1023 }
1024
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001025 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1026 if (err < 0)
1027 mgmt_pending_remove(cmd);
1028
1029failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001030 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001031 hci_dev_put(hdev);
1032
1033 return err;
1034}
1035
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001036static int set_pairable(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001037{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001038 struct mgmt_mode *cp = data;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001039 struct hci_dev *hdev;
1040 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001041
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001042 BT_DBG("request for hci%u", index);
1043
1044 if (len != sizeof(*cp))
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
1048 hdev = hci_dev_get(index);
1049 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001050 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE,
1051 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001052
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001053 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001054
1055 if (cp->val)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001056 set_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001057 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001058 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001059
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001060 err = send_settings_rsp(sk, MGMT_OP_SET_PAIRABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001061 if (err < 0)
1062 goto failed;
1063
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001064 err = new_settings(hdev, sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001065
1066failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001067 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001068 hci_dev_put(hdev);
1069
1070 return err;
1071}
Johan Hedberg72a734e2010-12-30 00:38:22 +02001072
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001073static int set_link_security(struct sock *sk, u16 index, void *data, u16 len)
1074{
1075 struct mgmt_mode *cp = data;
1076 struct pending_cmd *cmd;
1077 struct hci_dev *hdev;
Johan Hedberg816a11d2012-02-26 13:04:52 +02001078 u8 val;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001079 int err;
1080
1081 BT_DBG("request for hci%u", index);
1082
1083 if (len != sizeof(*cp))
1084 return cmd_status(sk, index, MGMT_OP_SET_LINK_SECURITY,
1085 MGMT_STATUS_INVALID_PARAMS);
1086
1087 hdev = hci_dev_get(index);
1088 if (!hdev)
1089 return cmd_status(sk, index, MGMT_OP_SET_LINK_SECURITY,
1090 MGMT_STATUS_INVALID_PARAMS);
1091
1092 hci_dev_lock(hdev);
1093
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001094 if (!hdev_is_powered(hdev)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001095 bool changed = false;
1096
1097 if (!!cp->val != test_bit(HCI_LINK_SECURITY,
1098 &hdev->dev_flags)) {
1099 change_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
1100 changed = true;
1101 }
1102
1103 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1104 if (err < 0)
1105 goto failed;
1106
1107 if (changed)
1108 err = new_settings(hdev, sk);
1109
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001110 goto failed;
1111 }
1112
1113 if (mgmt_pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
1114 err = cmd_status(sk, index, MGMT_OP_SET_LINK_SECURITY,
1115 MGMT_STATUS_BUSY);
1116 goto failed;
1117 }
1118
1119 val = !!cp->val;
1120
1121 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1122 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1123 goto failed;
1124 }
1125
1126 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1127 if (!cmd) {
1128 err = -ENOMEM;
1129 goto failed;
1130 }
1131
1132 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1133 if (err < 0) {
1134 mgmt_pending_remove(cmd);
1135 goto failed;
1136 }
1137
1138failed:
1139 hci_dev_unlock(hdev);
1140 hci_dev_put(hdev);
1141
1142 return err;
1143}
1144
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001145static int set_ssp(struct sock *sk, u16 index, void *data, u16 len)
1146{
1147 struct mgmt_mode *cp = data;
1148 struct pending_cmd *cmd;
1149 struct hci_dev *hdev;
Johan Hedberg816a11d2012-02-26 13:04:52 +02001150 u8 val;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001151 int err;
1152
1153 BT_DBG("request for hci%u", index);
1154
1155 if (len != sizeof(*cp))
1156 return cmd_status(sk, index, MGMT_OP_SET_SSP,
1157 MGMT_STATUS_INVALID_PARAMS);
1158
1159 hdev = hci_dev_get(index);
1160 if (!hdev)
1161 return cmd_status(sk, index, MGMT_OP_SET_SSP,
1162 MGMT_STATUS_INVALID_PARAMS);
1163
1164 hci_dev_lock(hdev);
1165
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001166 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
1167 err = cmd_status(sk, index, MGMT_OP_SET_SSP,
1168 MGMT_STATUS_NOT_SUPPORTED);
1169 goto failed;
1170 }
1171
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001172 val = !!cp->val;
1173
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001174 if (!hdev_is_powered(hdev)) {
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001175 bool changed = false;
1176
1177 if (val != test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) {
1178 change_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
1179 changed = true;
1180 }
1181
1182 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1183 if (err < 0)
1184 goto failed;
1185
1186 if (changed)
1187 err = new_settings(hdev, sk);
1188
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001189 goto failed;
1190 }
1191
1192 if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev)) {
1193 err = cmd_status(sk, index, MGMT_OP_SET_SSP, MGMT_STATUS_BUSY);
1194 goto failed;
1195 }
1196
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001197 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) == val) {
1198 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1199 goto failed;
1200 }
1201
1202 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1203 if (!cmd) {
1204 err = -ENOMEM;
1205 goto failed;
1206 }
1207
1208 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, sizeof(val), &val);
1209 if (err < 0) {
1210 mgmt_pending_remove(cmd);
1211 goto failed;
1212 }
1213
1214failed:
1215 hci_dev_unlock(hdev);
1216 hci_dev_put(hdev);
1217
1218 return err;
1219}
1220
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001221static int set_hs(struct sock *sk, u16 index, void *data, u16 len)
1222{
1223 struct mgmt_mode *cp = data;
1224 struct hci_dev *hdev;
1225 int err;
1226
1227 BT_DBG("request for hci%u", index);
1228
1229 if (len != sizeof(*cp))
1230 return cmd_status(sk, index, MGMT_OP_SET_HS,
1231 MGMT_STATUS_INVALID_PARAMS);
1232
1233 hdev = hci_dev_get(index);
1234 if (!hdev)
1235 return cmd_status(sk, index, MGMT_OP_SET_HS,
1236 MGMT_STATUS_INVALID_PARAMS);
1237
1238 if (!enable_hs) {
1239 err = cmd_status(sk, index, MGMT_OP_SET_HS,
1240 MGMT_STATUS_NOT_SUPPORTED);
1241 goto failed;
1242 }
1243
1244 if (cp->val)
1245 set_bit(HCI_HS_ENABLED, &hdev->dev_flags);
1246 else
1247 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
1248
1249 err = send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
1250
1251failed:
1252 hci_dev_put(hdev);
1253 return err;
1254}
1255
Johan Hedberg06199cf2012-02-22 16:37:11 +02001256static int set_le(struct sock *sk, u16 index, void *data, u16 len)
1257{
1258 struct mgmt_mode *cp = data;
1259 struct hci_cp_write_le_host_supported hci_cp;
1260 struct pending_cmd *cmd;
1261 struct hci_dev *hdev;
1262 int err;
1263 u8 val;
1264
1265 BT_DBG("request for hci%u", index);
1266
1267 if (len != sizeof(*cp))
1268 return cmd_status(sk, index, MGMT_OP_SET_LE,
1269 MGMT_STATUS_INVALID_PARAMS);
1270
1271 hdev = hci_dev_get(index);
1272 if (!hdev)
1273 return cmd_status(sk, index, MGMT_OP_SET_LE,
1274 MGMT_STATUS_INVALID_PARAMS);
1275
1276 if (!enable_le || !(hdev->features[4] & LMP_LE)) {
1277 err = cmd_status(sk, index, MGMT_OP_SET_LE,
1278 MGMT_STATUS_NOT_SUPPORTED);
1279 goto failed;
1280 }
1281
1282 val = !!cp->val;
1283
1284 if (!hdev_is_powered(hdev)) {
1285 bool changed = false;
1286
1287 if (val != test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
1288 change_bit(HCI_LE_ENABLED, &hdev->dev_flags);
1289 changed = true;
1290 }
1291
1292 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1293 if (err < 0)
1294 goto failed;
1295
1296 if (changed)
1297 err = new_settings(hdev, sk);
1298
1299 goto failed;
1300 }
1301
1302 if (mgmt_pending_find(MGMT_OP_SET_LE, hdev)) {
1303 err = cmd_status(sk, index, MGMT_OP_SET_LE, MGMT_STATUS_BUSY);
1304 goto failed;
1305 }
1306
1307 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
1308 if (!cmd) {
1309 err = -ENOMEM;
1310 goto failed;
1311 }
1312
1313 memset(&hci_cp, 0, sizeof(hci_cp));
1314
1315 if (val) {
1316 hci_cp.le = val;
1317 hci_cp.simul = !!(hdev->features[6] & LMP_SIMUL_LE_BR);
1318 }
1319
1320 err = hci_send_cmd(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED,
1321 sizeof(hci_cp), &hci_cp);
1322 if (err < 0) {
1323 mgmt_pending_remove(cmd);
1324 goto failed;
1325 }
1326
1327failed:
1328 hci_dev_put(hdev);
1329 return err;
1330}
1331
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001332static int add_uuid(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001333{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001334 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001335 struct pending_cmd *cmd;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001336 struct hci_dev *hdev;
1337 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001338 int err;
1339
Szymon Janc4e51eae2011-02-25 19:05:48 +01001340 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001341
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001342 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001343 return cmd_status(sk, index, MGMT_OP_ADD_UUID,
1344 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001345
Szymon Janc4e51eae2011-02-25 19:05:48 +01001346 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001347 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001348 return cmd_status(sk, index, MGMT_OP_ADD_UUID,
1349 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001350
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001351 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001352
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001353 if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
1354 err = cmd_status(sk, index, MGMT_OP_ADD_UUID,
1355 MGMT_STATUS_BUSY);
1356 goto failed;
1357 }
1358
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001359 uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC);
1360 if (!uuid) {
1361 err = -ENOMEM;
1362 goto failed;
1363 }
1364
1365 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001366 uuid->svc_hint = cp->svc_hint;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001367
1368 list_add(&uuid->list, &hdev->uuids);
1369
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001370 err = update_class(hdev);
1371 if (err < 0)
1372 goto failed;
1373
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001374 err = update_eir(hdev);
1375 if (err < 0)
1376 goto failed;
1377
Johan Hedberg90e70452012-02-23 23:09:40 +02001378 if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
1379 err = cmd_complete(sk, index, MGMT_OP_ADD_UUID, 0,
1380 hdev->dev_class, 3);
1381 goto failed;
1382 }
1383
1384 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len);
1385 if (!cmd) {
1386 err = -ENOMEM;
1387 goto failed;
1388 }
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001389
1390failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001391 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001392 hci_dev_put(hdev);
1393
1394 return err;
1395}
1396
Johan Hedberg24b78d02012-02-23 23:24:30 +02001397static bool enable_service_cache(struct hci_dev *hdev)
1398{
1399 if (!hdev_is_powered(hdev))
1400 return false;
1401
1402 if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
1403 schedule_delayed_work(&hdev->service_cache,
1404 msecs_to_jiffies(SERVICE_CACHE_TIMEOUT));
1405 return true;
1406 }
1407
1408 return false;
1409}
1410
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001411static int remove_uuid(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001412{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001413 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001414 struct pending_cmd *cmd;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001415 struct list_head *p, *n;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001416 struct hci_dev *hdev;
1417 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 +02001418 int err, found;
1419
Szymon Janc4e51eae2011-02-25 19:05:48 +01001420 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001421
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001422 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001423 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
1424 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001425
Szymon Janc4e51eae2011-02-25 19:05:48 +01001426 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001427 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001428 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
1429 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001430
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001431 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001432
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001433 if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
1434 err = cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
1435 MGMT_STATUS_BUSY);
1436 goto unlock;
1437 }
1438
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001439 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
1440 err = hci_uuids_clear(hdev);
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001441
Johan Hedberg24b78d02012-02-23 23:24:30 +02001442 if (enable_service_cache(hdev)) {
1443 err = cmd_complete(sk, index, MGMT_OP_REMOVE_UUID, 0,
1444 hdev->dev_class, 3);
1445 goto unlock;
1446 }
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001447
Johan Hedberg9246a862012-02-23 21:33:16 +02001448 goto update_class;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001449 }
1450
1451 found = 0;
1452
1453 list_for_each_safe(p, n, &hdev->uuids) {
1454 struct bt_uuid *match = list_entry(p, struct bt_uuid, list);
1455
1456 if (memcmp(match->uuid, cp->uuid, 16) != 0)
1457 continue;
1458
1459 list_del(&match->list);
1460 found++;
1461 }
1462
1463 if (found == 0) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001464 err = cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
1465 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001466 goto unlock;
1467 }
1468
Johan Hedberg9246a862012-02-23 21:33:16 +02001469update_class:
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001470 err = update_class(hdev);
1471 if (err < 0)
1472 goto unlock;
1473
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001474 err = update_eir(hdev);
1475 if (err < 0)
1476 goto unlock;
1477
Johan Hedberg90e70452012-02-23 23:09:40 +02001478 if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
1479 err = cmd_complete(sk, index, MGMT_OP_REMOVE_UUID, 0,
Johan Hedberg9997a532012-02-23 15:57:46 +02001480 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001481 goto unlock;
1482 }
1483
1484 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
1485 if (!cmd) {
1486 err = -ENOMEM;
1487 goto unlock;
1488 }
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001489
1490unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001491 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001492 hci_dev_put(hdev);
1493
1494 return err;
1495}
1496
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001497static int set_dev_class(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001498{
1499 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001500 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001501 struct pending_cmd *cmd;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001502 int err;
1503
Szymon Janc4e51eae2011-02-25 19:05:48 +01001504 BT_DBG("request for hci%u", index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001505
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001506 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001507 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS,
1508 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001509
Szymon Janc4e51eae2011-02-25 19:05:48 +01001510 hdev = hci_dev_get(index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001511 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001512 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS,
1513 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001514
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001515 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001516
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001517 if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
1518 err = cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS,
1519 MGMT_STATUS_BUSY);
1520 goto unlock;
1521 }
1522
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001523 hdev->major_class = cp->major;
1524 hdev->minor_class = cp->minor;
1525
Johan Hedberg932f5ff2012-02-22 22:11:32 +02001526 if (!hdev_is_powered(hdev)) {
1527 err = cmd_complete(sk, index, MGMT_OP_SET_DEV_CLASS, 0,
1528 hdev->dev_class, 3);
1529 goto unlock;
1530 }
1531
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001532 if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02001533 hci_dev_unlock(hdev);
1534 cancel_delayed_work_sync(&hdev->service_cache);
1535 hci_dev_lock(hdev);
Johan Hedberg14c0b602011-12-15 00:47:37 +02001536 update_eir(hdev);
Johan Hedberg7d785252011-12-15 00:47:39 +02001537 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02001538
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001539 err = update_class(hdev);
Johan Hedberg90e70452012-02-23 23:09:40 +02001540 if (err < 0)
1541 goto unlock;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001542
Johan Hedberg90e70452012-02-23 23:09:40 +02001543 if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergaee9b2182012-02-18 15:07:59 +02001544 err = cmd_complete(sk, index, MGMT_OP_SET_DEV_CLASS, 0,
Johan Hedberg8ec37032012-02-22 22:02:50 +02001545 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001546 goto unlock;
1547 }
1548
1549 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
1550 if (!cmd) {
1551 err = -ENOMEM;
1552 goto unlock;
1553 }
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001554
Johan Hedbergb5235a62012-02-21 14:32:24 +02001555unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001556 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001557 hci_dev_put(hdev);
1558
1559 return err;
1560}
1561
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001562static int load_link_keys(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001563{
1564 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001565 struct mgmt_cp_load_link_keys *cp = data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001566 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001567 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001568
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001569 if (len < sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001570 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1571 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001572
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001573 key_count = get_unaligned_le16(&cp->key_count);
1574
Johan Hedberg86742e12011-11-07 23:13:38 +02001575 expected_len = sizeof(*cp) + key_count *
1576 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001577 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001578 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001579 len, expected_len);
Johan Hedbergca69b792011-11-11 18:10:00 +02001580 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1581 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001582 }
1583
Szymon Janc4e51eae2011-02-25 19:05:48 +01001584 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001585 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001586 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1587 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001588
Szymon Janc4e51eae2011-02-25 19:05:48 +01001589 BT_DBG("hci%u debug_keys %u key_count %u", index, cp->debug_keys,
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001590 key_count);
1591
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001592 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001593
1594 hci_link_keys_clear(hdev);
1595
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001596 set_bit(HCI_LINK_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001597
1598 if (cp->debug_keys)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001599 set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001600 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001601 clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001602
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001603 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001604 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001605
Johan Hedbergd753fdc2012-02-17 14:06:34 +02001606 hci_add_link_key(hdev, NULL, 0, &key->addr.bdaddr, key->val,
1607 key->type, key->pin_len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001608 }
1609
Johan Hedbergaee9b2182012-02-18 15:07:59 +02001610 cmd_complete(sk, index, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02001611
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001612 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001613 hci_dev_put(hdev);
1614
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001615 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001616}
1617
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001618static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
1619 u8 addr_type, struct sock *skip_sk)
1620{
1621 struct mgmt_ev_device_unpaired ev;
1622
1623 bacpy(&ev.addr.bdaddr, bdaddr);
1624 ev.addr.type = addr_type;
1625
1626 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
1627 skip_sk);
1628}
1629
Johan Hedberg124f6e32012-02-09 13:50:12 +02001630static int unpair_device(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001631{
1632 struct hci_dev *hdev;
Johan Hedberg124f6e32012-02-09 13:50:12 +02001633 struct mgmt_cp_unpair_device *cp = data;
1634 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001635 struct hci_cp_disconnect dc;
1636 struct pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001637 struct hci_conn *conn;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001638 int err;
1639
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001640 if (len != sizeof(*cp))
Johan Hedberg124f6e32012-02-09 13:50:12 +02001641 return cmd_status(sk, index, MGMT_OP_UNPAIR_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02001642 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001643
Szymon Janc4e51eae2011-02-25 19:05:48 +01001644 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001645 if (!hdev)
Johan Hedberg124f6e32012-02-09 13:50:12 +02001646 return cmd_status(sk, index, MGMT_OP_UNPAIR_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02001647 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001648
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001649 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001650
Johan Hedberga8a1d192011-11-10 15:54:38 +02001651 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02001652 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1653 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001654
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001655 if (!hdev_is_powered(hdev)) {
1656 err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE,
1657 MGMT_STATUS_NOT_POWERED,
1658 &rp, sizeof(rp));
1659 goto unlock;
1660 }
1661
Johan Hedberg124f6e32012-02-09 13:50:12 +02001662 if (cp->addr.type == MGMT_ADDR_BREDR)
1663 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
1664 else
1665 err = hci_remove_ltk(hdev, &cp->addr.bdaddr);
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03001666
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001667 if (err < 0) {
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001668 err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE,
1669 MGMT_STATUS_NOT_PAIRED,
1670 &rp, sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001671 goto unlock;
1672 }
1673
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001674 if (cp->disconnect) {
1675 if (cp->addr.type == MGMT_ADDR_BREDR)
1676 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
1677 &cp->addr.bdaddr);
1678 else
1679 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
1680 &cp->addr.bdaddr);
1681 } else {
1682 conn = NULL;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001683 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001684
Johan Hedberga8a1d192011-11-10 15:54:38 +02001685 if (!conn) {
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001686 err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE, 0,
Johan Hedbergaee9b2182012-02-18 15:07:59 +02001687 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001688 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001689 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001690 }
1691
Johan Hedberg124f6e32012-02-09 13:50:12 +02001692 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
1693 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02001694 if (!cmd) {
1695 err = -ENOMEM;
1696 goto unlock;
1697 }
1698
1699 put_unaligned_le16(conn->handle, &dc.handle);
1700 dc.reason = 0x13; /* Remote User Terminated Connection */
1701 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1702 if (err < 0)
1703 mgmt_pending_remove(cmd);
1704
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001705unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001706 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001707 hci_dev_put(hdev);
1708
1709 return err;
1710}
1711
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001712static int disconnect(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02001713{
1714 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001715 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001716 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03001717 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001718 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001719 int err;
1720
1721 BT_DBG("");
1722
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001723 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001724 return cmd_status(sk, index, MGMT_OP_DISCONNECT,
1725 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001726
Szymon Janc4e51eae2011-02-25 19:05:48 +01001727 hdev = hci_dev_get(index);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001728 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001729 return cmd_status(sk, index, MGMT_OP_DISCONNECT,
1730 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001731
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001732 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001733
1734 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001735 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1736 MGMT_STATUS_NOT_POWERED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001737 goto failed;
1738 }
1739
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001740 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001741 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1742 MGMT_STATUS_BUSY);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001743 goto failed;
1744 }
1745
Johan Hedberg88c3df12012-02-09 14:27:38 +02001746 if (cp->addr.type == MGMT_ADDR_BREDR)
1747 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
1748 else
1749 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03001750
Johan Hedberg8962ee72011-01-20 12:40:27 +02001751 if (!conn) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001752 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1753 MGMT_STATUS_NOT_CONNECTED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001754 goto failed;
1755 }
1756
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001757 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001758 if (!cmd) {
1759 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001760 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001761 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001762
1763 put_unaligned_le16(conn->handle, &dc.handle);
1764 dc.reason = 0x13; /* Remote User Terminated Connection */
1765
1766 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1767 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001768 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001769
1770failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001771 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001772 hci_dev_put(hdev);
1773
1774 return err;
1775}
1776
Johan Hedberg48264f02011-11-09 13:58:58 +02001777static u8 link_to_mgmt(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02001778{
1779 switch (link_type) {
1780 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02001781 switch (addr_type) {
1782 case ADDR_LE_DEV_PUBLIC:
1783 return MGMT_ADDR_LE_PUBLIC;
1784 case ADDR_LE_DEV_RANDOM:
1785 return MGMT_ADDR_LE_RANDOM;
1786 default:
1787 return MGMT_ADDR_INVALID;
1788 }
Johan Hedberg4c659c32011-11-07 23:13:39 +02001789 case ACL_LINK:
1790 return MGMT_ADDR_BREDR;
1791 default:
1792 return MGMT_ADDR_INVALID;
1793 }
1794}
1795
Szymon Janc8ce62842011-03-01 16:55:32 +01001796static int get_connections(struct sock *sk, u16 index)
Johan Hedberg2784eb42011-01-21 13:56:35 +02001797{
Johan Hedberg2784eb42011-01-21 13:56:35 +02001798 struct mgmt_rp_get_connections *rp;
1799 struct hci_dev *hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001800 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02001801 size_t rp_len;
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001802 int err;
1803 u16 i;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001804
1805 BT_DBG("");
1806
Szymon Janc4e51eae2011-02-25 19:05:48 +01001807 hdev = hci_dev_get(index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001808 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001809 return cmd_status(sk, index, MGMT_OP_GET_CONNECTIONS,
1810 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001811
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001812 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001813
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001814 if (!hdev_is_powered(hdev)) {
1815 err = cmd_status(sk, index, MGMT_OP_GET_CONNECTIONS,
1816 MGMT_STATUS_NOT_POWERED);
1817 goto unlock;
1818 }
1819
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001820 i = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02001821 list_for_each_entry(c, &hdev->conn_hash.list, list) {
1822 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001823 i++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001824 }
1825
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001826 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberga38528f2011-01-22 06:46:43 +02001827 rp = kmalloc(rp_len, GFP_ATOMIC);
1828 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02001829 err = -ENOMEM;
1830 goto unlock;
1831 }
1832
Johan Hedberg2784eb42011-01-21 13:56:35 +02001833 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001834 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02001835 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
1836 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001837 bacpy(&rp->addr[i].bdaddr, &c->dst);
Johan Hedberg48264f02011-11-09 13:58:58 +02001838 rp->addr[i].type = link_to_mgmt(c->type, c->dst_type);
Johan Hedberg4c659c32011-11-07 23:13:39 +02001839 if (rp->addr[i].type == MGMT_ADDR_INVALID)
1840 continue;
1841 i++;
1842 }
1843
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001844 put_unaligned_le16(i, &rp->conn_count);
1845
Johan Hedberg4c659c32011-11-07 23:13:39 +02001846 /* Recalculate length in case of filtered SCO connections, etc */
1847 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02001848
Johan Hedbergaee9b2182012-02-18 15:07:59 +02001849 err = cmd_complete(sk, index, MGMT_OP_GET_CONNECTIONS, 0, rp, rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001850
Johan Hedberga38528f2011-01-22 06:46:43 +02001851 kfree(rp);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001852
1853unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001854 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001855 hci_dev_put(hdev);
1856 return err;
1857}
1858
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001859static int send_pin_code_neg_reply(struct sock *sk, u16 index,
1860 struct hci_dev *hdev, struct mgmt_cp_pin_code_neg_reply *cp)
1861{
1862 struct pending_cmd *cmd;
1863 int err;
1864
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001865 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001866 sizeof(*cp));
1867 if (!cmd)
1868 return -ENOMEM;
1869
Johan Hedbergd8457692012-02-17 14:24:57 +02001870 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
1871 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001872 if (err < 0)
1873 mgmt_pending_remove(cmd);
1874
1875 return err;
1876}
1877
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001878static int pin_code_reply(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001879{
1880 struct hci_dev *hdev;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001881 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001882 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001883 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03001884 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001885 int err;
1886
1887 BT_DBG("");
1888
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001889 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001890 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1891 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001892
Szymon Janc4e51eae2011-02-25 19:05:48 +01001893 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001894 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001895 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1896 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001897
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001898 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001899
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001900 if (!hdev_is_powered(hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001901 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1902 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001903 goto failed;
1904 }
1905
Johan Hedbergd8457692012-02-17 14:24:57 +02001906 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001907 if (!conn) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001908 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1909 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001910 goto failed;
1911 }
1912
1913 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02001914 struct mgmt_cp_pin_code_neg_reply ncp;
1915
1916 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001917
1918 BT_ERR("PIN code is not 16 bytes long");
1919
1920 err = send_pin_code_neg_reply(sk, index, hdev, &ncp);
1921 if (err >= 0)
1922 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001923 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001924
1925 goto failed;
1926 }
1927
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001928 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data,
1929 len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001930 if (!cmd) {
1931 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001932 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001933 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02001934
Johan Hedbergd8457692012-02-17 14:24:57 +02001935 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001936 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02001937 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02001938
1939 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
1940 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001941 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001942
1943failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001944 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001945 hci_dev_put(hdev);
1946
1947 return err;
1948}
1949
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001950static int pin_code_neg_reply(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001951{
1952 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001953 struct mgmt_cp_pin_code_neg_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001954 int err;
1955
1956 BT_DBG("");
1957
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001958 if (len != sizeof(*cp))
1959 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001960 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001961
Szymon Janc4e51eae2011-02-25 19:05:48 +01001962 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001963 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001964 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001965 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001966
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001967 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001968
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001969 if (!hdev_is_powered(hdev)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001970 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001971 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001972 goto failed;
1973 }
1974
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001975 err = send_pin_code_neg_reply(sk, index, hdev, cp);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001976
1977failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001978 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001979 hci_dev_put(hdev);
1980
1981 return err;
1982}
1983
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001984static int set_io_capability(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001985{
1986 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001987 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001988
1989 BT_DBG("");
1990
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001991 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001992 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY,
1993 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001994
Szymon Janc4e51eae2011-02-25 19:05:48 +01001995 hdev = hci_dev_get(index);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001996 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001997 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY,
1998 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001999
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002000 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002001
2002 hdev->io_capability = cp->io_capability;
2003
2004 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Szymon Jancb8534e02011-03-01 16:55:34 +01002005 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002006
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002007 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002008 hci_dev_put(hdev);
2009
Johan Hedbergaee9b2182012-02-18 15:07:59 +02002010 return cmd_complete(sk, index, MGMT_OP_SET_IO_CAPABILITY, 0, NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002011}
2012
Johan Hedberge9a416b2011-02-19 12:05:56 -03002013static inline struct pending_cmd *find_pairing(struct hci_conn *conn)
2014{
2015 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002016 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002017
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002018 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03002019 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
2020 continue;
2021
Johan Hedberge9a416b2011-02-19 12:05:56 -03002022 if (cmd->user_data != conn)
2023 continue;
2024
2025 return cmd;
2026 }
2027
2028 return NULL;
2029}
2030
2031static void pairing_complete(struct pending_cmd *cmd, u8 status)
2032{
2033 struct mgmt_rp_pair_device rp;
2034 struct hci_conn *conn = cmd->user_data;
2035
Johan Hedbergba4e5642011-11-11 00:07:34 +02002036 bacpy(&rp.addr.bdaddr, &conn->dst);
2037 rp.addr.type = link_to_mgmt(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002038
Johan Hedbergaee9b2182012-02-18 15:07:59 +02002039 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, status,
2040 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002041
2042 /* So we don't get further callbacks for this connection */
2043 conn->connect_cfm_cb = NULL;
2044 conn->security_cfm_cb = NULL;
2045 conn->disconn_cfm_cb = NULL;
2046
2047 hci_conn_put(conn);
2048
Johan Hedberga664b5b2011-02-19 12:06:02 -03002049 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002050}
2051
2052static void pairing_complete_cb(struct hci_conn *conn, u8 status)
2053{
2054 struct pending_cmd *cmd;
2055
2056 BT_DBG("status %u", status);
2057
Johan Hedberg56e5cb82011-11-08 20:40:16 +02002058 cmd = find_pairing(conn);
2059 if (!cmd)
2060 BT_DBG("Unable to find a pending command");
2061 else
Johan Hedberge2113262012-02-18 15:20:03 +02002062 pairing_complete(cmd, mgmt_status(status));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002063}
2064
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002065static int pair_device(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002066{
2067 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002068 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02002069 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002070 struct pending_cmd *cmd;
2071 u8 sec_level, auth_type;
2072 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002073 int err;
2074
2075 BT_DBG("");
2076
Szymon Jancbdce7ba2011-02-25 19:05:49 +01002077 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02002078 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE,
2079 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01002080
Szymon Janc4e51eae2011-02-25 19:05:48 +01002081 hdev = hci_dev_get(index);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002082 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002083 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE,
2084 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002085
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002086 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002087
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002088 if (!hdev_is_powered(hdev)) {
2089 err = cmd_status(sk, index, MGMT_OP_PAIR_DEVICE,
2090 MGMT_STATUS_NOT_POWERED);
2091 goto unlock;
2092 }
2093
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002094 sec_level = BT_SECURITY_MEDIUM;
2095 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002096 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002097 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03002098 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002099
Johan Hedbergba4e5642011-11-11 00:07:34 +02002100 if (cp->addr.type == MGMT_ADDR_BREDR)
2101 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr, sec_level,
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002102 auth_type);
2103 else
Johan Hedbergba4e5642011-11-11 00:07:34 +02002104 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr, sec_level,
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002105 auth_type);
2106
Johan Hedberg1425acb2011-11-11 00:07:35 +02002107 memset(&rp, 0, sizeof(rp));
2108 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2109 rp.addr.type = cp->addr.type;
2110
Ville Tervo30e76272011-02-22 16:10:53 -03002111 if (IS_ERR(conn)) {
Johan Hedberge2113262012-02-18 15:20:03 +02002112 err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE,
2113 MGMT_STATUS_CONNECT_FAILED,
2114 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002115 goto unlock;
2116 }
2117
2118 if (conn->connect_cfm_cb) {
2119 hci_conn_put(conn);
Johan Hedberge2113262012-02-18 15:20:03 +02002120 err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE,
2121 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002122 goto unlock;
2123 }
2124
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002125 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002126 if (!cmd) {
2127 err = -ENOMEM;
2128 hci_conn_put(conn);
2129 goto unlock;
2130 }
2131
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002132 /* For LE, just connecting isn't a proof that the pairing finished */
Johan Hedbergba4e5642011-11-11 00:07:34 +02002133 if (cp->addr.type == MGMT_ADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002134 conn->connect_cfm_cb = pairing_complete_cb;
2135
Johan Hedberge9a416b2011-02-19 12:05:56 -03002136 conn->security_cfm_cb = pairing_complete_cb;
2137 conn->disconn_cfm_cb = pairing_complete_cb;
2138 conn->io_capability = cp->io_cap;
2139 cmd->user_data = conn;
2140
2141 if (conn->state == BT_CONNECTED &&
2142 hci_conn_security(conn, sec_level, auth_type))
2143 pairing_complete(cmd, 0);
2144
2145 err = 0;
2146
2147unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002148 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002149 hci_dev_put(hdev);
2150
2151 return err;
2152}
2153
Johan Hedberg28424702012-02-02 04:02:29 +02002154static int cancel_pair_device(struct sock *sk, u16 index,
2155 unsigned char *data, u16 len)
2156{
2157 struct mgmt_addr_info *addr = (void *) data;
2158 struct hci_dev *hdev;
2159 struct pending_cmd *cmd;
2160 struct hci_conn *conn;
2161 int err;
2162
2163 BT_DBG("");
2164
2165 if (len != sizeof(*addr))
2166 return cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
2167 MGMT_STATUS_INVALID_PARAMS);
2168
2169 hdev = hci_dev_get(index);
2170 if (!hdev)
2171 return cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
2172 MGMT_STATUS_INVALID_PARAMS);
2173
2174 hci_dev_lock(hdev);
2175
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002176 if (!hdev_is_powered(hdev)) {
2177 err = cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
2178 MGMT_STATUS_NOT_POWERED);
2179 goto unlock;
2180 }
2181
Johan Hedberg28424702012-02-02 04:02:29 +02002182 cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
2183 if (!cmd) {
2184 err = cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
2185 MGMT_STATUS_INVALID_PARAMS);
2186 goto unlock;
2187 }
2188
2189 conn = cmd->user_data;
2190
2191 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
2192 err = cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
2193 MGMT_STATUS_INVALID_PARAMS);
2194 goto unlock;
2195 }
2196
2197 pairing_complete(cmd, MGMT_STATUS_CANCELLED);
2198
Johan Hedbergaee9b2182012-02-18 15:07:59 +02002199 err = cmd_complete(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE, 0, addr,
Johan Hedberg28424702012-02-02 04:02:29 +02002200 sizeof(*addr));
2201unlock:
2202 hci_dev_unlock(hdev);
2203 hci_dev_put(hdev);
2204
2205 return err;
2206}
2207
Brian Gix0df4c182011-11-16 13:53:13 -08002208static int user_pairing_resp(struct sock *sk, u16 index, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02002209 u8 type, u16 mgmt_op, u16 hci_op,
2210 __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03002211{
Johan Hedberga5c29682011-02-19 12:05:57 -03002212 struct pending_cmd *cmd;
2213 struct hci_dev *hdev;
Brian Gix0df4c182011-11-16 13:53:13 -08002214 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03002215 int err;
2216
Szymon Janc4e51eae2011-02-25 19:05:48 +01002217 hdev = hci_dev_get(index);
Johan Hedberga5c29682011-02-19 12:05:57 -03002218 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002219 return cmd_status(sk, index, mgmt_op,
2220 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga5c29682011-02-19 12:05:57 -03002221
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002222 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02002223
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002224 if (!hdev_is_powered(hdev)) {
Brian Gix0df4c182011-11-16 13:53:13 -08002225 err = cmd_status(sk, index, mgmt_op, MGMT_STATUS_NOT_POWERED);
2226 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002227 }
2228
Johan Hedberg272d90d2012-02-09 15:26:12 +02002229 if (type == MGMT_ADDR_BREDR)
2230 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, bdaddr);
2231 else
Brian Gix47c15e22011-11-16 13:53:14 -08002232 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, bdaddr);
Brian Gix47c15e22011-11-16 13:53:14 -08002233
Johan Hedberg272d90d2012-02-09 15:26:12 +02002234 if (!conn) {
2235 err = cmd_status(sk, index, mgmt_op,
2236 MGMT_STATUS_NOT_CONNECTED);
2237 goto done;
2238 }
2239
2240 if (type == MGMT_ADDR_LE_PUBLIC || type == MGMT_ADDR_LE_RANDOM) {
Brian Gix47c15e22011-11-16 13:53:14 -08002241 /* Continue with pairing via SMP */
Brian Gix5fe57d92011-12-21 16:12:13 -08002242 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix47c15e22011-11-16 13:53:14 -08002243
Brian Gix5fe57d92011-12-21 16:12:13 -08002244 if (!err)
2245 err = cmd_status(sk, index, mgmt_op,
2246 MGMT_STATUS_SUCCESS);
2247 else
2248 err = cmd_status(sk, index, mgmt_op,
2249 MGMT_STATUS_FAILED);
2250
Brian Gix47c15e22011-11-16 13:53:14 -08002251 goto done;
2252 }
2253
Brian Gix0df4c182011-11-16 13:53:13 -08002254 cmd = mgmt_pending_add(sk, mgmt_op, hdev, bdaddr, sizeof(*bdaddr));
Johan Hedberga5c29682011-02-19 12:05:57 -03002255 if (!cmd) {
2256 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08002257 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002258 }
2259
Brian Gix0df4c182011-11-16 13:53:13 -08002260 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08002261 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
2262 struct hci_cp_user_passkey_reply cp;
2263
2264 bacpy(&cp.bdaddr, bdaddr);
2265 cp.passkey = passkey;
2266 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
2267 } else
2268 err = hci_send_cmd(hdev, hci_op, sizeof(*bdaddr), bdaddr);
2269
Johan Hedberga664b5b2011-02-19 12:06:02 -03002270 if (err < 0)
2271 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002272
Brian Gix0df4c182011-11-16 13:53:13 -08002273done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002274 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002275 hci_dev_put(hdev);
2276
2277 return err;
2278}
2279
Brian Gix0df4c182011-11-16 13:53:13 -08002280static int user_confirm_reply(struct sock *sk, u16 index, void *data, u16 len)
2281{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002282 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002283
2284 BT_DBG("");
2285
2286 if (len != sizeof(*cp))
2287 return cmd_status(sk, index, MGMT_OP_USER_CONFIRM_REPLY,
2288 MGMT_STATUS_INVALID_PARAMS);
2289
Johan Hedberg272d90d2012-02-09 15:26:12 +02002290 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
2291 MGMT_OP_USER_CONFIRM_REPLY,
2292 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002293}
2294
2295static int user_confirm_neg_reply(struct sock *sk, u16 index, void *data,
2296 u16 len)
2297{
Johan Hedbergc9c26592011-12-15 00:47:41 +02002298 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002299
2300 BT_DBG("");
2301
2302 if (len != sizeof(*cp))
2303 return cmd_status(sk, index, MGMT_OP_USER_CONFIRM_NEG_REPLY,
2304 MGMT_STATUS_INVALID_PARAMS);
2305
Johan Hedberg272d90d2012-02-09 15:26:12 +02002306 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
2307 MGMT_OP_USER_CONFIRM_NEG_REPLY,
2308 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002309}
2310
Brian Gix604086b2011-11-23 08:28:33 -08002311static int user_passkey_reply(struct sock *sk, u16 index, void *data, u16 len)
2312{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002313 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002314
2315 BT_DBG("");
2316
2317 if (len != sizeof(*cp))
2318 return cmd_status(sk, index, MGMT_OP_USER_PASSKEY_REPLY,
2319 EINVAL);
2320
Johan Hedberg272d90d2012-02-09 15:26:12 +02002321 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
2322 MGMT_OP_USER_PASSKEY_REPLY,
2323 HCI_OP_USER_PASSKEY_REPLY,
2324 cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08002325}
2326
2327static int user_passkey_neg_reply(struct sock *sk, u16 index, void *data,
2328 u16 len)
2329{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002330 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002331
2332 BT_DBG("");
2333
2334 if (len != sizeof(*cp))
2335 return cmd_status(sk, index, MGMT_OP_USER_PASSKEY_NEG_REPLY,
2336 EINVAL);
2337
Johan Hedberg272d90d2012-02-09 15:26:12 +02002338 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
2339 MGMT_OP_USER_PASSKEY_NEG_REPLY,
2340 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08002341}
2342
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002343static int set_local_name(struct sock *sk, u16 index, void *data,
Johan Hedbergb312b1612011-03-16 14:29:37 +02002344 u16 len)
2345{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002346 struct mgmt_cp_set_local_name *mgmt_cp = data;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002347 struct hci_cp_write_local_name hci_cp;
2348 struct hci_dev *hdev;
2349 struct pending_cmd *cmd;
2350 int err;
2351
2352 BT_DBG("");
2353
2354 if (len != sizeof(*mgmt_cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02002355 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME,
2356 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002357
2358 hdev = hci_dev_get(index);
2359 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002360 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME,
2361 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002362
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002363 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002364
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002365 memcpy(hdev->short_name, mgmt_cp->short_name,
2366 sizeof(hdev->short_name));
2367
Johan Hedbergb5235a62012-02-21 14:32:24 +02002368 if (!hdev_is_powered(hdev)) {
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002369 memcpy(hdev->dev_name, mgmt_cp->name, sizeof(hdev->dev_name));
2370
2371 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
2372 data, len);
2373 if (err < 0)
2374 goto failed;
2375
2376 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data, len,
2377 sk);
2378
Johan Hedbergb5235a62012-02-21 14:32:24 +02002379 goto failed;
2380 }
2381
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002382 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002383 if (!cmd) {
2384 err = -ENOMEM;
2385 goto failed;
2386 }
2387
2388 memcpy(hci_cp.name, mgmt_cp->name, sizeof(hci_cp.name));
2389 err = hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(hci_cp),
2390 &hci_cp);
2391 if (err < 0)
2392 mgmt_pending_remove(cmd);
2393
2394failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002395 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002396 hci_dev_put(hdev);
2397
2398 return err;
2399}
2400
Szymon Jancc35938b2011-03-22 13:12:21 +01002401static int read_local_oob_data(struct sock *sk, u16 index)
2402{
2403 struct hci_dev *hdev;
2404 struct pending_cmd *cmd;
2405 int err;
2406
2407 BT_DBG("hci%u", index);
2408
2409 hdev = hci_dev_get(index);
2410 if (!hdev)
2411 return cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002412 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancc35938b2011-03-22 13:12:21 +01002413
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002414 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002415
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002416 if (!hdev_is_powered(hdev)) {
Szymon Jancc35938b2011-03-22 13:12:21 +01002417 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002418 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002419 goto unlock;
2420 }
2421
2422 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
2423 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002424 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002425 goto unlock;
2426 }
2427
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002428 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02002429 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2430 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01002431 goto unlock;
2432 }
2433
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002434 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01002435 if (!cmd) {
2436 err = -ENOMEM;
2437 goto unlock;
2438 }
2439
2440 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
2441 if (err < 0)
2442 mgmt_pending_remove(cmd);
2443
2444unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002445 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002446 hci_dev_put(hdev);
2447
2448 return err;
2449}
2450
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002451static int add_remote_oob_data(struct sock *sk, u16 index, void *data,
2452 u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002453{
2454 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002455 struct mgmt_cp_add_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002456 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002457 int err;
2458
2459 BT_DBG("hci%u ", index);
2460
2461 if (len != sizeof(*cp))
2462 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002463 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01002464
2465 hdev = hci_dev_get(index);
2466 if (!hdev)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002467 return cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
2468 MGMT_STATUS_INVALID_PARAMS,
2469 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002470
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002471 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002472
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002473 if (!hdev_is_powered(hdev)) {
2474 err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
2475 MGMT_STATUS_NOT_POWERED,
2476 &cp->addr, sizeof(cp->addr));
2477 goto unlock;
2478 }
2479
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002480 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, cp->hash,
Szymon Janc2763eda2011-03-22 13:12:22 +01002481 cp->randomizer);
2482 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002483 status = MGMT_STATUS_FAILED;
Szymon Janc2763eda2011-03-22 13:12:22 +01002484 else
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002485 status = 0;
2486
2487 err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, status,
2488 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002489
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002490unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002491 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002492 hci_dev_put(hdev);
2493
2494 return err;
2495}
2496
2497static int remove_remote_oob_data(struct sock *sk, u16 index,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002498 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002499{
2500 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002501 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002502 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002503 int err;
2504
2505 BT_DBG("hci%u ", index);
2506
2507 if (len != sizeof(*cp))
2508 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002509 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01002510
2511 hdev = hci_dev_get(index);
2512 if (!hdev)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002513 return cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2514 MGMT_STATUS_INVALID_PARAMS,
2515 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002516
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002517 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002518
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002519 if (!hdev_is_powered(hdev)) {
2520 err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2521 MGMT_STATUS_NOT_POWERED,
2522 &cp->addr, sizeof(cp->addr));
2523 goto unlock;
2524 }
2525
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002526 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr);
Szymon Janc2763eda2011-03-22 13:12:22 +01002527 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002528 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01002529 else
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002530 status = 0;
2531
2532 err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA, status,
2533 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002534
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002535unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002536 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002537 hci_dev_put(hdev);
2538
2539 return err;
2540}
2541
Andre Guedes5e0452c2012-02-17 20:39:38 -03002542static int discovery(struct hci_dev *hdev)
2543{
2544 int err;
2545
2546 if (lmp_host_le_capable(hdev)) {
2547 if (lmp_bredr_capable(hdev)) {
2548 err = hci_le_scan(hdev, LE_SCAN_TYPE,
2549 LE_SCAN_INT, LE_SCAN_WIN,
2550 LE_SCAN_TIMEOUT_BREDR_LE);
2551 } else {
2552 hdev->discovery.type = DISCOV_TYPE_LE;
2553 err = hci_le_scan(hdev, LE_SCAN_TYPE,
2554 LE_SCAN_INT, LE_SCAN_WIN,
2555 LE_SCAN_TIMEOUT_LE_ONLY);
2556 }
2557 } else {
2558 hdev->discovery.type = DISCOV_TYPE_BREDR;
2559 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
2560 }
2561
2562 return err;
2563}
2564
2565int mgmt_interleaved_discovery(struct hci_dev *hdev)
2566{
2567 int err;
2568
2569 BT_DBG("%s", hdev->name);
2570
2571 hci_dev_lock(hdev);
2572
2573 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR_LE);
2574 if (err < 0)
2575 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2576
2577 hci_dev_unlock(hdev);
2578
2579 return err;
2580}
2581
Johan Hedberg450dfda2011-11-12 11:58:22 +02002582static int start_discovery(struct sock *sk, u16 index,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002583 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002584{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002585 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002586 struct pending_cmd *cmd;
2587 struct hci_dev *hdev;
2588 int err;
2589
2590 BT_DBG("hci%u", index);
2591
Johan Hedberg450dfda2011-11-12 11:58:22 +02002592 if (len != sizeof(*cp))
2593 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2594 MGMT_STATUS_INVALID_PARAMS);
2595
Johan Hedberg14a53662011-04-27 10:29:56 -04002596 hdev = hci_dev_get(index);
2597 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002598 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2599 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg14a53662011-04-27 10:29:56 -04002600
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002601 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002602
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002603 if (!hdev_is_powered(hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02002604 err = cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2605 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02002606 goto failed;
2607 }
2608
Johan Hedbergff9ef572012-01-04 14:23:45 +02002609 if (hdev->discovery.state != DISCOVERY_STOPPED) {
2610 err = cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2611 MGMT_STATUS_BUSY);
2612 goto failed;
2613 }
2614
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002615 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002616 if (!cmd) {
2617 err = -ENOMEM;
2618 goto failed;
2619 }
2620
Andre Guedes4aab14e2012-02-17 20:39:36 -03002621 hdev->discovery.type = cp->type;
2622
2623 switch (hdev->discovery.type) {
Andre Guedesf39799f2012-02-17 20:39:35 -03002624 case DISCOV_TYPE_BREDR:
Andre Guedes3fd24152012-02-03 17:48:01 -03002625 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
Andre Guedesf39799f2012-02-17 20:39:35 -03002626 break;
2627
2628 case DISCOV_TYPE_LE:
Andre Guedes3fd24152012-02-03 17:48:01 -03002629 err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT,
2630 LE_SCAN_WIN, LE_SCAN_TIMEOUT_LE_ONLY);
Andre Guedesf39799f2012-02-17 20:39:35 -03002631 break;
2632
Andre Guedes5e0452c2012-02-17 20:39:38 -03002633 case DISCOV_TYPE_INTERLEAVED:
2634 err = discovery(hdev);
2635 break;
2636
Andre Guedesf39799f2012-02-17 20:39:35 -03002637 default:
Andre Guedes3fd24152012-02-03 17:48:01 -03002638 err = -EINVAL;
Andre Guedesf39799f2012-02-17 20:39:35 -03002639 }
Andre Guedes3fd24152012-02-03 17:48:01 -03002640
Johan Hedberg14a53662011-04-27 10:29:56 -04002641 if (err < 0)
2642 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002643 else
2644 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002645
2646failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002647 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002648 hci_dev_put(hdev);
2649
2650 return err;
2651}
2652
Johan Hedbergd9306502012-02-20 23:25:18 +02002653static int stop_discovery(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002654{
Johan Hedbergd9306502012-02-20 23:25:18 +02002655 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002656 struct hci_dev *hdev;
2657 struct pending_cmd *cmd;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002658 struct hci_cp_remote_name_req_cancel cp;
2659 struct inquiry_entry *e;
Johan Hedberg14a53662011-04-27 10:29:56 -04002660 int err;
2661
2662 BT_DBG("hci%u", index);
2663
Johan Hedbergd9306502012-02-20 23:25:18 +02002664 if (len != sizeof(*mgmt_cp))
2665 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY,
2666 MGMT_STATUS_INVALID_PARAMS);
2667
Johan Hedberg14a53662011-04-27 10:29:56 -04002668 hdev = hci_dev_get(index);
2669 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002670 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY,
2671 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg14a53662011-04-27 10:29:56 -04002672
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002673 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002674
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002675 if (!hci_discovery_active(hdev)) {
Johan Hedbergd9306502012-02-20 23:25:18 +02002676 err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY,
2677 MGMT_STATUS_REJECTED,
2678 &mgmt_cp->type, sizeof(mgmt_cp->type));
2679 goto unlock;
2680 }
2681
2682 if (hdev->discovery.type != mgmt_cp->type) {
2683 err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY,
2684 MGMT_STATUS_INVALID_PARAMS,
2685 &mgmt_cp->type, sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002686 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02002687 }
2688
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002689 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002690 if (!cmd) {
2691 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002692 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04002693 }
2694
Andre Guedes343f9352012-02-17 20:39:37 -03002695 if (hdev->discovery.state == DISCOVERY_FINDING) {
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002696 err = hci_cancel_inquiry(hdev);
2697 if (err < 0)
2698 mgmt_pending_remove(cmd);
2699 else
2700 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
2701 goto unlock;
2702 }
2703
2704 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY, NAME_PENDING);
2705 if (!e) {
2706 mgmt_pending_remove(cmd);
Johan Hedbergaee9b2182012-02-18 15:07:59 +02002707 err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY, 0,
Johan Hedbergd9306502012-02-20 23:25:18 +02002708 &mgmt_cp->type, sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002709 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2710 goto unlock;
2711 }
2712
2713 bacpy(&cp.bdaddr, &e->data.bdaddr);
2714 err = hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ_CANCEL,
2715 sizeof(cp), &cp);
Johan Hedberg14a53662011-04-27 10:29:56 -04002716 if (err < 0)
2717 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002718 else
2719 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002720
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002721unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002722 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002723 hci_dev_put(hdev);
2724
2725 return err;
2726}
2727
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002728static int confirm_name(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02002729{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002730 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002731 struct inquiry_entry *e;
2732 struct hci_dev *hdev;
2733 int err;
2734
2735 BT_DBG("hci%u", index);
2736
2737 if (len != sizeof(*cp))
2738 return cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2739 MGMT_STATUS_INVALID_PARAMS);
2740
2741 hdev = hci_dev_get(index);
2742 if (!hdev)
2743 return cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2744 MGMT_STATUS_INVALID_PARAMS);
2745
2746 hci_dev_lock(hdev);
2747
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002748 if (!hci_discovery_active(hdev)) {
2749 err = cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2750 MGMT_STATUS_FAILED);
2751 goto failed;
2752 }
2753
Johan Hedberga198e7b2012-02-17 14:27:06 +02002754 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002755 if (!e) {
Marcel Holtmanne5f0e152012-02-22 11:59:01 +01002756 err = cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
Johan Hedberg561aafb2012-01-04 13:31:59 +02002757 MGMT_STATUS_INVALID_PARAMS);
2758 goto failed;
2759 }
2760
2761 if (cp->name_known) {
2762 e->name_state = NAME_KNOWN;
2763 list_del(&e->list);
2764 } else {
2765 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e202012-01-09 00:53:02 +02002766 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002767 }
2768
2769 err = 0;
2770
2771failed:
2772 hci_dev_unlock(hdev);
2773
2774 return err;
2775}
2776
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002777static int block_device(struct sock *sk, u16 index, void *data, u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002778{
2779 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002780 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002781 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03002782 int err;
2783
2784 BT_DBG("hci%u", index);
2785
Antti Julku7fbec222011-06-15 12:01:15 +03002786 if (len != sizeof(*cp))
2787 return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002788 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002789
2790 hdev = hci_dev_get(index);
2791 if (!hdev)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002792 return cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE,
2793 MGMT_STATUS_INVALID_PARAMS,
2794 &cp->addr, sizeof(cp->addr));
Antti Julku7fbec222011-06-15 12:01:15 +03002795
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002796 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002797
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002798 err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002799 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002800 status = MGMT_STATUS_FAILED;
Antti Julku7fbec222011-06-15 12:01:15 +03002801 else
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002802 status = 0;
2803
2804 err = cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE, status,
2805 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03002806
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002807 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002808 hci_dev_put(hdev);
2809
2810 return err;
2811}
2812
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002813static int unblock_device(struct sock *sk, u16 index, void *data, u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002814{
2815 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002816 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002817 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03002818 int err;
2819
2820 BT_DBG("hci%u", index);
2821
Antti Julku7fbec222011-06-15 12:01:15 +03002822 if (len != sizeof(*cp))
2823 return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002824 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002825
2826 hdev = hci_dev_get(index);
2827 if (!hdev)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002828 return cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE,
2829 MGMT_STATUS_INVALID_PARAMS,
2830 &cp->addr, sizeof(cp->addr));
Antti Julku7fbec222011-06-15 12:01:15 +03002831
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002832 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002833
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002834 err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002835 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002836 status = MGMT_STATUS_INVALID_PARAMS;
Antti Julku7fbec222011-06-15 12:01:15 +03002837 else
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002838 status = 0;
2839
2840 err = cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE, status,
2841 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03002842
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002843 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002844 hci_dev_put(hdev);
2845
2846 return err;
2847}
2848
Antti Julkuf6422ec2011-06-22 13:11:56 +03002849static int set_fast_connectable(struct sock *sk, u16 index,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002850 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03002851{
2852 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002853 struct mgmt_mode *cp = data;
Antti Julkuf6422ec2011-06-22 13:11:56 +03002854 struct hci_cp_write_page_scan_activity acp;
2855 u8 type;
2856 int err;
2857
2858 BT_DBG("hci%u", index);
2859
2860 if (len != sizeof(*cp))
2861 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002862 MGMT_STATUS_INVALID_PARAMS);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002863
2864 hdev = hci_dev_get(index);
2865 if (!hdev)
2866 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002867 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg5400c042012-02-21 16:40:33 +02002868 if (!hdev_is_powered(hdev))
2869 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
2870 MGMT_STATUS_NOT_POWERED);
2871
2872 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
2873 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
2874 MGMT_STATUS_REJECTED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002875
2876 hci_dev_lock(hdev);
2877
Johan Hedbergf7c68692011-12-15 00:47:36 +02002878 if (cp->val) {
Antti Julkuf6422ec2011-06-22 13:11:56 +03002879 type = PAGE_SCAN_TYPE_INTERLACED;
2880 acp.interval = 0x0024; /* 22.5 msec page scan interval */
2881 } else {
2882 type = PAGE_SCAN_TYPE_STANDARD; /* default */
2883 acp.interval = 0x0800; /* default 1.28 sec page scan */
2884 }
2885
2886 acp.window = 0x0012; /* default 11.25 msec page scan window */
2887
2888 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
2889 sizeof(acp), &acp);
2890 if (err < 0) {
2891 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002892 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002893 goto done;
2894 }
2895
2896 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
2897 if (err < 0) {
2898 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002899 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002900 goto done;
2901 }
2902
Johan Hedbergaee9b2182012-02-18 15:07:59 +02002903 err = cmd_complete(sk, index, MGMT_OP_SET_FAST_CONNECTABLE, 0,
2904 NULL, 0);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002905done:
2906 hci_dev_unlock(hdev);
2907 hci_dev_put(hdev);
2908
2909 return err;
2910}
2911
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002912static int load_long_term_keys(struct sock *sk, u16 index,
2913 void *cp_data, u16 len)
2914{
2915 struct hci_dev *hdev;
2916 struct mgmt_cp_load_long_term_keys *cp = cp_data;
2917 u16 key_count, expected_len;
2918 int i;
2919
2920 if (len < sizeof(*cp))
2921 return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS,
2922 EINVAL);
2923
2924 key_count = get_unaligned_le16(&cp->key_count);
2925
2926 expected_len = sizeof(*cp) + key_count *
2927 sizeof(struct mgmt_ltk_info);
2928 if (expected_len != len) {
2929 BT_ERR("load_keys: expected %u bytes, got %u bytes",
2930 len, expected_len);
2931 return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS,
2932 EINVAL);
2933 }
2934
2935 hdev = hci_dev_get(index);
2936 if (!hdev)
2937 return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS,
2938 ENODEV);
2939
2940 BT_DBG("hci%u key_count %u", index, key_count);
2941
2942 hci_dev_lock(hdev);
2943
2944 hci_smp_ltks_clear(hdev);
2945
2946 for (i = 0; i < key_count; i++) {
2947 struct mgmt_ltk_info *key = &cp->keys[i];
2948 u8 type;
2949
2950 if (key->master)
2951 type = HCI_SMP_LTK;
2952 else
2953 type = HCI_SMP_LTK_SLAVE;
2954
2955 hci_add_ltk(hdev, &key->addr.bdaddr, key->addr.type,
2956 type, 0, key->authenticated, key->val,
2957 key->enc_size, key->ediv, key->rand);
2958 }
2959
2960 hci_dev_unlock(hdev);
2961 hci_dev_put(hdev);
2962
2963 return 0;
2964}
2965
Johan Hedberg03811012010-12-08 00:21:06 +02002966int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
2967{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002968 void *buf;
2969 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02002970 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002971 u16 opcode, index, len;
Johan Hedberg03811012010-12-08 00:21:06 +02002972 int err;
2973
2974 BT_DBG("got %zu bytes", msglen);
2975
2976 if (msglen < sizeof(*hdr))
2977 return -EINVAL;
2978
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03002979 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02002980 if (!buf)
2981 return -ENOMEM;
2982
2983 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
2984 err = -EFAULT;
2985 goto done;
2986 }
2987
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002988 hdr = buf;
Johan Hedberg03811012010-12-08 00:21:06 +02002989 opcode = get_unaligned_le16(&hdr->opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002990 index = get_unaligned_le16(&hdr->index);
Johan Hedberg03811012010-12-08 00:21:06 +02002991 len = get_unaligned_le16(&hdr->len);
2992
2993 if (len != msglen - sizeof(*hdr)) {
2994 err = -EINVAL;
2995 goto done;
2996 }
2997
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002998 cp = buf + sizeof(*hdr);
2999
Johan Hedberg03811012010-12-08 00:21:06 +02003000 switch (opcode) {
Johan Hedberg02d98122010-12-13 21:07:04 +02003001 case MGMT_OP_READ_VERSION:
3002 err = read_version(sk);
3003 break;
Johan Hedberge70bb2e2012-02-13 16:59:33 +02003004 case MGMT_OP_READ_COMMANDS:
3005 err = read_commands(sk);
3006 break;
Johan Hedbergfaba42e2010-12-13 21:07:05 +02003007 case MGMT_OP_READ_INDEX_LIST:
3008 err = read_index_list(sk);
3009 break;
Johan Hedbergf7b64e62010-12-13 21:07:06 +02003010 case MGMT_OP_READ_INFO:
Szymon Janc4e51eae2011-02-25 19:05:48 +01003011 err = read_controller_info(sk, index);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02003012 break;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02003013 case MGMT_OP_SET_POWERED:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003014 err = set_powered(sk, index, cp, len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02003015 break;
Johan Hedberg73f22f62010-12-29 16:00:25 +02003016 case MGMT_OP_SET_DISCOVERABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003017 err = set_discoverable(sk, index, cp, len);
Johan Hedberg73f22f62010-12-29 16:00:25 +02003018 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003019 case MGMT_OP_SET_CONNECTABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003020 err = set_connectable(sk, index, cp, len);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003021 break;
Johan Hedbergf7c68692011-12-15 00:47:36 +02003022 case MGMT_OP_SET_FAST_CONNECTABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003023 err = set_fast_connectable(sk, index, cp, len);
Johan Hedbergf7c68692011-12-15 00:47:36 +02003024 break;
Johan Hedbergc542a062011-01-26 13:11:03 +02003025 case MGMT_OP_SET_PAIRABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003026 err = set_pairable(sk, index, cp, len);
Johan Hedbergc542a062011-01-26 13:11:03 +02003027 break;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003028 case MGMT_OP_SET_LINK_SECURITY:
3029 err = set_link_security(sk, index, cp, len);
3030 break;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003031 case MGMT_OP_SET_SSP:
3032 err = set_ssp(sk, index, cp, len);
3033 break;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02003034 case MGMT_OP_SET_HS:
3035 err = set_hs(sk, index, cp, len);
3036 break;
Johan Hedberg06199cf2012-02-22 16:37:11 +02003037 case MGMT_OP_SET_LE:
3038 err = set_le(sk, index, cp, len);
3039 break;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02003040 case MGMT_OP_ADD_UUID:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003041 err = add_uuid(sk, index, cp, len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02003042 break;
3043 case MGMT_OP_REMOVE_UUID:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003044 err = remove_uuid(sk, index, cp, len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02003045 break;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02003046 case MGMT_OP_SET_DEV_CLASS:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003047 err = set_dev_class(sk, index, cp, len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02003048 break;
Johan Hedberg86742e12011-11-07 23:13:38 +02003049 case MGMT_OP_LOAD_LINK_KEYS:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003050 err = load_link_keys(sk, index, cp, len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003051 break;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003052 case MGMT_OP_DISCONNECT:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003053 err = disconnect(sk, index, cp, len);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003054 break;
Johan Hedberg2784eb42011-01-21 13:56:35 +02003055 case MGMT_OP_GET_CONNECTIONS:
Szymon Janc8ce62842011-03-01 16:55:32 +01003056 err = get_connections(sk, index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02003057 break;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003058 case MGMT_OP_PIN_CODE_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003059 err = pin_code_reply(sk, index, cp, len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003060 break;
3061 case MGMT_OP_PIN_CODE_NEG_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003062 err = pin_code_neg_reply(sk, index, cp, len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003063 break;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02003064 case MGMT_OP_SET_IO_CAPABILITY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003065 err = set_io_capability(sk, index, cp, len);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02003066 break;
Johan Hedberge9a416b2011-02-19 12:05:56 -03003067 case MGMT_OP_PAIR_DEVICE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003068 err = pair_device(sk, index, cp, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03003069 break;
Johan Hedberg28424702012-02-02 04:02:29 +02003070 case MGMT_OP_CANCEL_PAIR_DEVICE:
3071 err = cancel_pair_device(sk, index, buf + sizeof(*hdr), len);
3072 break;
Johan Hedberg124f6e32012-02-09 13:50:12 +02003073 case MGMT_OP_UNPAIR_DEVICE:
3074 err = unpair_device(sk, index, cp, len);
3075 break;
Johan Hedberga5c29682011-02-19 12:05:57 -03003076 case MGMT_OP_USER_CONFIRM_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003077 err = user_confirm_reply(sk, index, cp, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03003078 break;
3079 case MGMT_OP_USER_CONFIRM_NEG_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003080 err = user_confirm_neg_reply(sk, index, cp, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03003081 break;
Brian Gix604086b2011-11-23 08:28:33 -08003082 case MGMT_OP_USER_PASSKEY_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003083 err = user_passkey_reply(sk, index, cp, len);
Brian Gix604086b2011-11-23 08:28:33 -08003084 break;
3085 case MGMT_OP_USER_PASSKEY_NEG_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003086 err = user_passkey_neg_reply(sk, index, cp, len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003087 break;
Johan Hedbergb312b1612011-03-16 14:29:37 +02003088 case MGMT_OP_SET_LOCAL_NAME:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003089 err = set_local_name(sk, index, cp, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003090 break;
Szymon Jancc35938b2011-03-22 13:12:21 +01003091 case MGMT_OP_READ_LOCAL_OOB_DATA:
3092 err = read_local_oob_data(sk, index);
3093 break;
Szymon Janc2763eda2011-03-22 13:12:22 +01003094 case MGMT_OP_ADD_REMOTE_OOB_DATA:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003095 err = add_remote_oob_data(sk, index, cp, len);
Szymon Janc2763eda2011-03-22 13:12:22 +01003096 break;
3097 case MGMT_OP_REMOVE_REMOTE_OOB_DATA:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003098 err = remove_remote_oob_data(sk, index, cp, len);
Szymon Janc2763eda2011-03-22 13:12:22 +01003099 break;
Johan Hedberg14a53662011-04-27 10:29:56 -04003100 case MGMT_OP_START_DISCOVERY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003101 err = start_discovery(sk, index, cp, len);
Johan Hedberg14a53662011-04-27 10:29:56 -04003102 break;
3103 case MGMT_OP_STOP_DISCOVERY:
Johan Hedbergd9306502012-02-20 23:25:18 +02003104 err = stop_discovery(sk, index, cp, len);
Johan Hedberg14a53662011-04-27 10:29:56 -04003105 break;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003106 case MGMT_OP_CONFIRM_NAME:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003107 err = confirm_name(sk, index, cp, len);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003108 break;
Antti Julku7fbec222011-06-15 12:01:15 +03003109 case MGMT_OP_BLOCK_DEVICE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003110 err = block_device(sk, index, cp, len);
Antti Julku7fbec222011-06-15 12:01:15 +03003111 break;
3112 case MGMT_OP_UNBLOCK_DEVICE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003113 err = unblock_device(sk, index, cp, len);
Antti Julku7fbec222011-06-15 12:01:15 +03003114 break;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003115 case MGMT_OP_LOAD_LONG_TERM_KEYS:
3116 err = load_long_term_keys(sk, index, cp, len);
3117 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003118 default:
Johan Hedberg72a734e2010-12-30 00:38:22 +02003119 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02003120 err = cmd_status(sk, index, opcode,
3121 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003122 break;
3123 }
Johan Hedberg72a734e2010-12-30 00:38:22 +02003124
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003125 if (err < 0)
Johan Hedberg72a734e2010-12-30 00:38:22 +02003126 goto done;
3127
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003128 err = msglen;
3129
3130done:
3131 kfree(buf);
3132 return err;
3133}
3134
Johan Hedbergb24752f2011-11-03 14:40:33 +02003135static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
3136{
3137 u8 *status = data;
3138
3139 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
3140 mgmt_pending_remove(cmd);
3141}
3142
Johan Hedberg744cf192011-11-08 20:40:14 +02003143int mgmt_index_added(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +02003144{
Johan Hedberg744cf192011-11-08 20:40:14 +02003145 return mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02003146}
3147
Johan Hedberg744cf192011-11-08 20:40:14 +02003148int mgmt_index_removed(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +02003149{
Johan Hedbergb24752f2011-11-03 14:40:33 +02003150 u8 status = ENODEV;
3151
Johan Hedberg744cf192011-11-08 20:40:14 +02003152 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02003153
Johan Hedberg744cf192011-11-08 20:40:14 +02003154 return mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02003155}
3156
3157struct cmd_lookup {
Johan Hedberg03811012010-12-08 00:21:06 +02003158 struct sock *sk;
Johan Hedberg69ab39e2011-12-15 00:47:35 +02003159 struct hci_dev *hdev;
Johan Hedberg90e70452012-02-23 23:09:40 +02003160 u8 mgmt_status;
Johan Hedberg03811012010-12-08 00:21:06 +02003161};
3162
Johan Hedberg69ab39e2011-12-15 00:47:35 +02003163static void settings_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberg03811012010-12-08 00:21:06 +02003164{
Johan Hedberg03811012010-12-08 00:21:06 +02003165 struct cmd_lookup *match = data;
3166
Johan Hedberg69ab39e2011-12-15 00:47:35 +02003167 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02003168
3169 list_del(&cmd->list);
3170
3171 if (match->sk == NULL) {
3172 match->sk = cmd->sk;
3173 sock_hold(match->sk);
3174 }
3175
3176 mgmt_pending_free(cmd);
3177}
3178
Johan Hedberg744cf192011-11-08 20:40:14 +02003179int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg03811012010-12-08 00:21:06 +02003180{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02003181 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003182 int err;
Johan Hedberg03811012010-12-08 00:21:06 +02003183
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003184 if (!test_bit(HCI_MGMT, &hdev->dev_flags))
3185 return 0;
3186
Johan Hedberg69ab39e2011-12-15 00:47:35 +02003187 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
Johan Hedberg03811012010-12-08 00:21:06 +02003188
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003189 if (powered) {
3190 u8 scan = 0;
3191
3192 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3193 scan |= SCAN_PAGE;
3194 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3195 scan |= SCAN_INQUIRY;
3196
3197 if (scan)
3198 hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
Johan Hedberg504c8dc2012-02-23 13:30:41 +02003199
3200 update_class(hdev);
3201 update_eir(hdev);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003202 } else {
Johan Hedbergb24752f2011-11-03 14:40:33 +02003203 u8 status = ENETDOWN;
Johan Hedberg744cf192011-11-08 20:40:14 +02003204 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02003205 }
3206
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003207 err = new_settings(hdev, match.sk);
Johan Hedberg03811012010-12-08 00:21:06 +02003208
3209 if (match.sk)
3210 sock_put(match.sk);
3211
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003212 return err;
Johan Hedberg03811012010-12-08 00:21:06 +02003213}
3214
Johan Hedberg744cf192011-11-08 20:40:14 +02003215int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg03811012010-12-08 00:21:06 +02003216{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02003217 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003218 bool changed = false;
3219 int err = 0;
Johan Hedberg03811012010-12-08 00:21:06 +02003220
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003221 if (discoverable) {
3222 if (!test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3223 changed = true;
3224 } else {
3225 if (test_and_clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3226 changed = true;
3227 }
Johan Hedberg03811012010-12-08 00:21:06 +02003228
Johan Hedberged9b5f22012-02-21 20:47:06 +02003229 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp,
3230 &match);
3231
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003232 if (changed)
3233 err = new_settings(hdev, match.sk);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003234
Johan Hedberg03811012010-12-08 00:21:06 +02003235 if (match.sk)
3236 sock_put(match.sk);
3237
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003238 return err;
Johan Hedberg03811012010-12-08 00:21:06 +02003239}
3240
Johan Hedberg744cf192011-11-08 20:40:14 +02003241int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg03811012010-12-08 00:21:06 +02003242{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02003243 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003244 bool changed = false;
3245 int err = 0;
Johan Hedberg03811012010-12-08 00:21:06 +02003246
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003247 if (connectable) {
3248 if (!test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3249 changed = true;
3250 } else {
3251 if (test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3252 changed = true;
3253 }
Johan Hedberg03811012010-12-08 00:21:06 +02003254
Johan Hedberged9b5f22012-02-21 20:47:06 +02003255 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev, settings_rsp,
3256 &match);
3257
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003258 if (changed)
3259 err = new_settings(hdev, match.sk);
Johan Hedberg03811012010-12-08 00:21:06 +02003260
3261 if (match.sk)
3262 sock_put(match.sk);
3263
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003264 return err;
Johan Hedberg03811012010-12-08 00:21:06 +02003265}
3266
Johan Hedberg744cf192011-11-08 20:40:14 +02003267int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003268{
Johan Hedbergca69b792011-11-11 18:10:00 +02003269 u8 mgmt_err = mgmt_status(status);
3270
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003271 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02003272 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Johan Hedbergca69b792011-11-11 18:10:00 +02003273 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003274
3275 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02003276 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Johan Hedbergca69b792011-11-11 18:10:00 +02003277 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003278
3279 return 0;
3280}
3281
Johan Hedberg744cf192011-11-08 20:40:14 +02003282int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
3283 u8 persistent)
Johan Hedberg03811012010-12-08 00:21:06 +02003284{
Johan Hedberg86742e12011-11-07 23:13:38 +02003285 struct mgmt_ev_new_link_key ev;
Johan Hedberg03811012010-12-08 00:21:06 +02003286
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003287 memset(&ev, 0, sizeof(ev));
Johan Hedberg03811012010-12-08 00:21:06 +02003288
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003289 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02003290 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
3291 ev.key.addr.type = MGMT_ADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003292 ev.key.type = key->type;
3293 memcpy(ev.key.val, key->val, 16);
3294 ev.key.pin_len = key->pin_len;
Johan Hedberg03811012010-12-08 00:21:06 +02003295
Johan Hedberg744cf192011-11-08 20:40:14 +02003296 return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02003297}
Johan Hedbergf7520542011-01-20 12:34:39 +02003298
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003299int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
3300{
3301 struct mgmt_ev_new_long_term_key ev;
3302
3303 memset(&ev, 0, sizeof(ev));
3304
3305 ev.store_hint = persistent;
3306 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
3307 ev.key.addr.type = key->bdaddr_type;
3308 ev.key.authenticated = key->authenticated;
3309 ev.key.enc_size = key->enc_size;
3310 ev.key.ediv = key->ediv;
3311
3312 if (key->type == HCI_SMP_LTK)
3313 ev.key.master = 1;
3314
3315 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
3316 memcpy(ev.key.val, key->val, sizeof(key->val));
3317
3318 return mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev,
3319 &ev, sizeof(ev), NULL);
3320}
3321
Johan Hedbergafc747a2012-01-15 18:11:07 +02003322int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Johan Hedberg08c79b62012-02-23 22:31:51 +02003323 u8 addr_type, u32 flags, u8 *name,
3324 u8 name_len, u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02003325{
Johan Hedbergb644ba32012-01-17 21:48:47 +02003326 char buf[512];
3327 struct mgmt_ev_device_connected *ev = (void *) buf;
3328 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02003329
Johan Hedbergb644ba32012-01-17 21:48:47 +02003330 bacpy(&ev->addr.bdaddr, bdaddr);
3331 ev->addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02003332
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02003333 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02003334
Johan Hedbergb644ba32012-01-17 21:48:47 +02003335 if (name_len > 0)
3336 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
3337 name, name_len);
3338
3339 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
3340 eir_len = eir_append_data(&ev->eir[eir_len], eir_len,
3341 EIR_CLASS_OF_DEV, dev_class, 3);
3342
3343 put_unaligned_le16(eir_len, &ev->eir_len);
3344
3345 return mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
3346 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02003347}
3348
Johan Hedberg8962ee72011-01-20 12:40:27 +02003349static void disconnect_rsp(struct pending_cmd *cmd, void *data)
3350{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01003351 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003352 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02003353 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003354
Johan Hedberg88c3df12012-02-09 14:27:38 +02003355 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3356 rp.addr.type = cp->addr.type;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003357
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003358 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, 0, &rp,
3359 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003360
3361 *sk = cmd->sk;
3362 sock_hold(*sk);
3363
Johan Hedberga664b5b2011-02-19 12:06:02 -03003364 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003365}
3366
Johan Hedberg124f6e32012-02-09 13:50:12 +02003367static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02003368{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003369 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02003370 struct mgmt_cp_unpair_device *cp = cmd->param;
3371 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02003372
3373 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02003374 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3375 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02003376
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003377 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
3378
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003379 cmd_complete(cmd->sk, cmd->index, cmd->opcode, 0, &rp, sizeof(rp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02003380
3381 mgmt_pending_remove(cmd);
3382}
3383
Johan Hedbergafc747a2012-01-15 18:11:07 +02003384int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
3385 u8 link_type, u8 addr_type)
Johan Hedbergf7520542011-01-20 12:34:39 +02003386{
Johan Hedberg4c659c32011-11-07 23:13:39 +02003387 struct mgmt_addr_info ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003388 struct sock *sk = NULL;
3389 int err;
3390
Johan Hedberg744cf192011-11-08 20:40:14 +02003391 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02003392
Johan Hedbergf7520542011-01-20 12:34:39 +02003393 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02003394 ev.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02003395
Johan Hedbergafc747a2012-01-15 18:11:07 +02003396 err = mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev),
3397 sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003398
3399 if (sk)
3400 sock_put(sk);
3401
Johan Hedberg124f6e32012-02-09 13:50:12 +02003402 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003403 hdev);
Johan Hedberga8a1d192011-11-10 15:54:38 +02003404
Johan Hedberg8962ee72011-01-20 12:40:27 +02003405 return err;
3406}
3407
Johan Hedberg88c3df12012-02-09 14:27:38 +02003408int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
3409 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02003410{
Johan Hedberg88c3df12012-02-09 14:27:38 +02003411 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003412 struct pending_cmd *cmd;
3413 int err;
3414
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003415 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003416 if (!cmd)
3417 return -ENOENT;
3418
Johan Hedberg88c3df12012-02-09 14:27:38 +02003419 bacpy(&rp.addr.bdaddr, bdaddr);
3420 rp.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02003421
Johan Hedberg88c3df12012-02-09 14:27:38 +02003422 err = cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003423 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003424
Johan Hedberga664b5b2011-02-19 12:06:02 -03003425 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003426
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003427 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
3428 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003429 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02003430}
Johan Hedberg17d5c042011-01-22 06:09:08 +02003431
Johan Hedberg48264f02011-11-09 13:58:58 +02003432int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
3433 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02003434{
3435 struct mgmt_ev_connect_failed ev;
3436
Johan Hedberg4c659c32011-11-07 23:13:39 +02003437 bacpy(&ev.addr.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02003438 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003439 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003440
Johan Hedberg744cf192011-11-08 20:40:14 +02003441 return mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003442}
Johan Hedberg980e1a52011-01-22 06:10:07 +02003443
Johan Hedberg744cf192011-11-08 20:40:14 +02003444int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003445{
3446 struct mgmt_ev_pin_code_request ev;
3447
Johan Hedbergd8457692012-02-17 14:24:57 +02003448 bacpy(&ev.addr.bdaddr, bdaddr);
3449 ev.addr.type = MGMT_ADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02003450 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003451
Johan Hedberg744cf192011-11-08 20:40:14 +02003452 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01003453 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003454}
3455
Johan Hedberg744cf192011-11-08 20:40:14 +02003456int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3457 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003458{
3459 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003460 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003461 int err;
3462
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003463 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003464 if (!cmd)
3465 return -ENOENT;
3466
Johan Hedbergd8457692012-02-17 14:24:57 +02003467 bacpy(&rp.addr.bdaddr, bdaddr);
3468 rp.addr.type = MGMT_ADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003469
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003470 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
3471 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003472
Johan Hedberga664b5b2011-02-19 12:06:02 -03003473 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003474
3475 return err;
3476}
3477
Johan Hedberg744cf192011-11-08 20:40:14 +02003478int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3479 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003480{
3481 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003482 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003483 int err;
3484
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003485 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003486 if (!cmd)
3487 return -ENOENT;
3488
Johan Hedbergd8457692012-02-17 14:24:57 +02003489 bacpy(&rp.addr.bdaddr, bdaddr);
3490 rp.addr.type = MGMT_ADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003491
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003492 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
3493 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003494
Johan Hedberga664b5b2011-02-19 12:06:02 -03003495 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003496
3497 return err;
3498}
Johan Hedberga5c29682011-02-19 12:05:57 -03003499
Johan Hedberg744cf192011-11-08 20:40:14 +02003500int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003501 u8 link_type, u8 addr_type, __le32 value,
3502 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03003503{
3504 struct mgmt_ev_user_confirm_request ev;
3505
Johan Hedberg744cf192011-11-08 20:40:14 +02003506 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03003507
Johan Hedberg272d90d2012-02-09 15:26:12 +02003508 bacpy(&ev.addr.bdaddr, bdaddr);
3509 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07003510 ev.confirm_hint = confirm_hint;
Johan Hedberga5c29682011-02-19 12:05:57 -03003511 put_unaligned_le32(value, &ev.value);
3512
Johan Hedberg744cf192011-11-08 20:40:14 +02003513 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01003514 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03003515}
3516
Johan Hedberg272d90d2012-02-09 15:26:12 +02003517int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
3518 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08003519{
3520 struct mgmt_ev_user_passkey_request ev;
3521
3522 BT_DBG("%s", hdev->name);
3523
Johan Hedberg272d90d2012-02-09 15:26:12 +02003524 bacpy(&ev.addr.bdaddr, bdaddr);
3525 ev.addr.type = link_to_mgmt(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08003526
3527 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
3528 NULL);
3529}
3530
Brian Gix0df4c182011-11-16 13:53:13 -08003531static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003532 u8 link_type, u8 addr_type, u8 status,
3533 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03003534{
3535 struct pending_cmd *cmd;
3536 struct mgmt_rp_user_confirm_reply rp;
3537 int err;
3538
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003539 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03003540 if (!cmd)
3541 return -ENOENT;
3542
Johan Hedberg272d90d2012-02-09 15:26:12 +02003543 bacpy(&rp.addr.bdaddr, bdaddr);
3544 rp.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003545 err = cmd_complete(cmd->sk, hdev->id, opcode, mgmt_status(status),
3546 &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03003547
Johan Hedberga664b5b2011-02-19 12:06:02 -03003548 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03003549
3550 return err;
3551}
3552
Johan Hedberg744cf192011-11-08 20:40:14 +02003553int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003554 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003555{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003556 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3557 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003558}
3559
Johan Hedberg272d90d2012-02-09 15:26:12 +02003560int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3561 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003562{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003563 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3564 status, MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003565}
Johan Hedberg2a611692011-02-19 12:06:00 -03003566
Brian Gix604086b2011-11-23 08:28:33 -08003567int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003568 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003569{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003570 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3571 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003572}
3573
Johan Hedberg272d90d2012-02-09 15:26:12 +02003574int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3575 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003576{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003577 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3578 status, MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003579}
3580
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003581int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
3582 u8 addr_type, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03003583{
3584 struct mgmt_ev_auth_failed ev;
3585
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003586 bacpy(&ev.addr.bdaddr, bdaddr);
3587 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003588 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03003589
Johan Hedberg744cf192011-11-08 20:40:14 +02003590 return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03003591}
Johan Hedbergb312b1612011-03-16 14:29:37 +02003592
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003593int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
3594{
3595 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg47990ea2012-02-22 11:58:37 +02003596 bool changed = false;
3597 int err = 0;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003598
3599 if (status) {
3600 u8 mgmt_err = mgmt_status(status);
3601 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
3602 cmd_status_rsp, &mgmt_err);
3603 return 0;
3604 }
3605
Johan Hedberg47990ea2012-02-22 11:58:37 +02003606 if (test_bit(HCI_AUTH, &hdev->flags)) {
3607 if (!test_and_set_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
3608 changed = true;
3609 } else {
3610 if (test_and_clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
3611 changed = true;
3612 }
3613
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003614 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
3615 &match);
3616
Johan Hedberg47990ea2012-02-22 11:58:37 +02003617 if (changed)
3618 err = new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003619
3620 if (match.sk)
3621 sock_put(match.sk);
3622
3623 return err;
3624}
3625
Johan Hedbergcacaf522012-02-21 00:52:42 +02003626static int clear_eir(struct hci_dev *hdev)
3627{
3628 struct hci_cp_write_eir cp;
3629
3630 if (!(hdev->features[6] & LMP_EXT_INQ))
3631 return 0;
3632
Johan Hedbergc80da272012-02-22 15:38:48 +02003633 memset(hdev->eir, 0, sizeof(hdev->eir));
3634
Johan Hedbergcacaf522012-02-21 00:52:42 +02003635 memset(&cp, 0, sizeof(cp));
3636
3637 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
3638}
3639
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003640int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003641{
3642 struct cmd_lookup match = { NULL, hdev };
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003643 bool changed = false;
3644 int err = 0;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003645
3646 if (status) {
3647 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003648
3649 if (enable && test_and_clear_bit(HCI_SSP_ENABLED,
3650 &hdev->dev_flags))
3651 err = new_settings(hdev, NULL);
3652
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003653 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev,
3654 cmd_status_rsp, &mgmt_err);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003655
3656 return err;
3657 }
3658
3659 if (enable) {
3660 if (!test_and_set_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3661 changed = true;
3662 } else {
3663 if (test_and_clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3664 changed = true;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003665 }
3666
3667 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
3668
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003669 if (changed)
3670 err = new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003671
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02003672 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003673 sock_put(match.sk);
3674
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02003675 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3676 update_eir(hdev);
3677 else
3678 clear_eir(hdev);
Johan Hedbergcacaf522012-02-21 00:52:42 +02003679
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003680 return err;
3681}
3682
Johan Hedberg90e70452012-02-23 23:09:40 +02003683static void class_rsp(struct pending_cmd *cmd, void *data)
3684{
3685 struct cmd_lookup *match = data;
3686
3687 cmd_complete(cmd->sk, cmd->index, cmd->opcode, match->mgmt_status,
3688 match->hdev->dev_class, 3);
3689
3690 list_del(&cmd->list);
3691
3692 if (match->sk == NULL) {
3693 match->sk = cmd->sk;
3694 sock_hold(match->sk);
3695 }
3696
3697 mgmt_pending_free(cmd);
3698}
3699
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003700int mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
3701 u8 status)
3702{
Johan Hedberg90e70452012-02-23 23:09:40 +02003703 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
3704 int err = 0;
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003705
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02003706 clear_bit(HCI_PENDING_CLASS, &hdev->dev_flags);
3707
Johan Hedberg90e70452012-02-23 23:09:40 +02003708 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, class_rsp, &match);
3709 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, class_rsp, &match);
3710 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, class_rsp, &match);
3711
3712 if (!status)
3713 err = mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
3714 dev_class, 3, NULL);
3715
3716 if (match.sk)
3717 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003718
3719 return err;
3720}
3721
Johan Hedberg744cf192011-11-08 20:40:14 +02003722int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02003723{
3724 struct pending_cmd *cmd;
3725 struct mgmt_cp_set_local_name ev;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003726 bool changed = false;
3727 int err = 0;
3728
3729 if (memcmp(name, hdev->dev_name, sizeof(hdev->dev_name)) != 0) {
3730 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
3731 changed = true;
3732 }
Johan Hedbergb312b1612011-03-16 14:29:37 +02003733
3734 memset(&ev, 0, sizeof(ev));
3735 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003736 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003737
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003738 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003739 if (!cmd)
3740 goto send_event;
3741
Johan Hedberg7bdaae42012-02-22 21:39:58 +02003742 /* Always assume that either the short or the complete name has
3743 * changed if there was a pending mgmt command */
3744 changed = true;
3745
Johan Hedbergb312b1612011-03-16 14:29:37 +02003746 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02003747 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
Johan Hedbergca69b792011-11-11 18:10:00 +02003748 mgmt_status(status));
Johan Hedbergb312b1612011-03-16 14:29:37 +02003749 goto failed;
3750 }
3751
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003752 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0, &ev,
Johan Hedbergb312b1612011-03-16 14:29:37 +02003753 sizeof(ev));
3754 if (err < 0)
3755 goto failed;
3756
3757send_event:
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003758 if (changed)
3759 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev,
3760 sizeof(ev), cmd ? cmd->sk : NULL);
3761
Johan Hedbergf51d5b22012-02-22 18:17:32 +02003762 update_eir(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003763
3764failed:
3765 if (cmd)
3766 mgmt_pending_remove(cmd);
3767 return err;
3768}
Szymon Jancc35938b2011-03-22 13:12:21 +01003769
Johan Hedberg744cf192011-11-08 20:40:14 +02003770int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
3771 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01003772{
3773 struct pending_cmd *cmd;
3774 int err;
3775
Johan Hedberg744cf192011-11-08 20:40:14 +02003776 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01003777
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003778 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003779 if (!cmd)
3780 return -ENOENT;
3781
3782 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02003783 err = cmd_status(cmd->sk, hdev->id,
Johan Hedbergca69b792011-11-11 18:10:00 +02003784 MGMT_OP_READ_LOCAL_OOB_DATA,
3785 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01003786 } else {
3787 struct mgmt_rp_read_local_oob_data rp;
3788
3789 memcpy(rp.hash, hash, sizeof(rp.hash));
3790 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
3791
Johan Hedberg744cf192011-11-08 20:40:14 +02003792 err = cmd_complete(cmd->sk, hdev->id,
3793 MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003794 0, &rp, sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01003795 }
3796
3797 mgmt_pending_remove(cmd);
3798
3799 return err;
3800}
Johan Hedberge17acd42011-03-30 23:57:16 +03003801
Johan Hedberg06199cf2012-02-22 16:37:11 +02003802int mgmt_le_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
3803{
3804 struct cmd_lookup match = { NULL, hdev };
3805 bool changed = false;
3806 int err = 0;
3807
3808 if (status) {
3809 u8 mgmt_err = mgmt_status(status);
3810
3811 if (enable && test_and_clear_bit(HCI_LE_ENABLED,
3812 &hdev->dev_flags))
3813 err = new_settings(hdev, NULL);
3814
3815 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev,
3816 cmd_status_rsp, &mgmt_err);
3817
3818 return err;
3819 }
3820
3821 if (enable) {
3822 if (!test_and_set_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3823 changed = true;
3824 } else {
3825 if (test_and_clear_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3826 changed = true;
3827 }
3828
3829 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
3830
3831 if (changed)
3832 err = new_settings(hdev, match.sk);
3833
3834 if (match.sk)
3835 sock_put(match.sk);
3836
3837 return err;
3838}
3839
Johan Hedberg48264f02011-11-09 13:58:58 +02003840int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Johan Hedberg561aafb2012-01-04 13:31:59 +02003841 u8 addr_type, u8 *dev_class, s8 rssi,
Johan Hedberg388fc8f2012-02-23 00:38:59 +02003842 u8 cfm_name, u8 ssp, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03003843{
Johan Hedberge319d2e2012-01-15 19:51:59 +02003844 char buf[512];
3845 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02003846 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03003847
Johan Hedberg1dc06092012-01-15 21:01:23 +02003848 /* Leave 5 bytes for a potential CoD field */
3849 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Andre Guedes7d262f82012-01-10 18:20:49 -03003850 return -EINVAL;
3851
Johan Hedberg1dc06092012-01-15 21:01:23 +02003852 memset(buf, 0, sizeof(buf));
3853
Johan Hedberge319d2e2012-01-15 19:51:59 +02003854 bacpy(&ev->addr.bdaddr, bdaddr);
3855 ev->addr.type = link_to_mgmt(link_type, addr_type);
3856 ev->rssi = rssi;
Johan Hedberg9a395a82012-02-23 00:00:32 +02003857 if (cfm_name)
3858 ev->flags[0] |= MGMT_DEV_FOUND_CONFIRM_NAME;
Johan Hedberg388fc8f2012-02-23 00:38:59 +02003859 if (!ssp)
3860 ev->flags[0] |= MGMT_DEV_FOUND_LEGACY_PAIRING;
Johan Hedberge17acd42011-03-30 23:57:16 +03003861
Johan Hedberg1dc06092012-01-15 21:01:23 +02003862 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02003863 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03003864
Johan Hedberg1dc06092012-01-15 21:01:23 +02003865 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
3866 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
3867 dev_class, 3);
3868
3869 put_unaligned_le16(eir_len, &ev->eir_len);
3870
3871 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03003872
Johan Hedberge319d2e2012-01-15 19:51:59 +02003873 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03003874}
Johan Hedberga88a9652011-03-30 13:18:12 +03003875
Johan Hedbergb644ba32012-01-17 21:48:47 +02003876int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
3877 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03003878{
Johan Hedbergb644ba32012-01-17 21:48:47 +02003879 struct mgmt_ev_device_found *ev;
3880 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
3881 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03003882
Johan Hedbergb644ba32012-01-17 21:48:47 +02003883 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03003884
Johan Hedbergb644ba32012-01-17 21:48:47 +02003885 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03003886
Johan Hedbergb644ba32012-01-17 21:48:47 +02003887 bacpy(&ev->addr.bdaddr, bdaddr);
3888 ev->addr.type = link_to_mgmt(link_type, addr_type);
3889 ev->rssi = rssi;
3890
3891 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
3892 name_len);
3893
3894 put_unaligned_le16(eir_len, &ev->eir_len);
3895
Johan Hedberg053c7e02012-02-04 00:06:00 +02003896 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev,
3897 sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03003898}
Johan Hedberg314b2382011-04-27 10:29:57 -04003899
Andre Guedes7a135102011-11-09 17:14:25 -03003900int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
Johan Hedberg164a6e72011-11-01 17:06:44 +02003901{
3902 struct pending_cmd *cmd;
Johan Hedbergf808e162012-02-19 12:52:07 +02003903 u8 type;
Johan Hedberg164a6e72011-11-01 17:06:44 +02003904 int err;
3905
Andre Guedes203159d2012-02-13 15:41:01 -03003906 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3907
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003908 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003909 if (!cmd)
3910 return -ENOENT;
3911
Johan Hedbergf808e162012-02-19 12:52:07 +02003912 type = hdev->discovery.type;
3913
3914 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
3915 &type, sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02003916 mgmt_pending_remove(cmd);
3917
3918 return err;
3919}
3920
Andre Guedese6d465c2011-11-09 17:14:26 -03003921int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
3922{
3923 struct pending_cmd *cmd;
3924 int err;
3925
3926 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
3927 if (!cmd)
3928 return -ENOENT;
3929
Johan Hedbergd9306502012-02-20 23:25:18 +02003930 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
3931 &hdev->discovery.type,
3932 sizeof(hdev->discovery.type));
Johan Hedberg03811012010-12-08 00:21:06 +02003933 mgmt_pending_remove(cmd);
3934
3935 return err;
3936}
Johan Hedberg314b2382011-04-27 10:29:57 -04003937
Johan Hedberg744cf192011-11-08 20:40:14 +02003938int mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04003939{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02003940 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02003941 struct pending_cmd *cmd;
3942
Andre Guedes343fb142011-11-22 17:14:19 -03003943 BT_DBG("%s discovering %u", hdev->name, discovering);
3944
Johan Hedberg164a6e72011-11-01 17:06:44 +02003945 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003946 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003947 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003948 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003949
3950 if (cmd != NULL) {
Johan Hedbergf808e162012-02-19 12:52:07 +02003951 u8 type = hdev->discovery.type;
3952
Johan Hedbergd9306502012-02-20 23:25:18 +02003953 cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0,
Johan Hedbergf808e162012-02-19 12:52:07 +02003954 &type, sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02003955 mgmt_pending_remove(cmd);
3956 }
3957
Johan Hedbergf963e8e2012-02-20 23:30:44 +02003958 memset(&ev, 0, sizeof(ev));
3959 ev.type = hdev->discovery.type;
3960 ev.discovering = discovering;
3961
3962 return mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04003963}
Antti Julku5e762442011-08-25 16:48:02 +03003964
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003965int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003966{
3967 struct pending_cmd *cmd;
3968 struct mgmt_ev_device_blocked ev;
3969
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003970 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003971
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003972 bacpy(&ev.addr.bdaddr, bdaddr);
3973 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003974
Johan Hedberg744cf192011-11-08 20:40:14 +02003975 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
3976 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003977}
3978
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003979int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003980{
3981 struct pending_cmd *cmd;
3982 struct mgmt_ev_device_unblocked ev;
3983
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003984 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003985
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003986 bacpy(&ev.addr.bdaddr, bdaddr);
3987 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003988
Johan Hedberg744cf192011-11-08 20:40:14 +02003989 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
3990 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003991}
Marcel Holtmannd7b7e792012-02-20 21:47:49 +01003992
3993module_param(enable_hs, bool, 0644);
3994MODULE_PARM_DESC(enable_hs, "Enable High Speed support");
3995
3996module_param(enable_le, bool, 0644);
3997MODULE_PARM_DESC(enable_le, "Enable Low Energy support");