blob: c4d3bc9c86b5a12c0eceb067f8da97599eae9624 [file] [log] [blame]
Johan Hedberg03811012010-12-08 00:21:06 +02001/*
2 BlueZ - Bluetooth protocol stack for Linux
Johan Hedbergea585ab2012-02-17 14:50:39 +02003
Johan Hedberg03811012010-12-08 00:21:06 +02004 Copyright (C) 2010 Nokia Corporation
Johan Hedbergea585ab2012-02-17 14:50:39 +02005 Copyright (C) 2011-2012 Intel Corporation
Johan Hedberg03811012010-12-08 00:21:06 +02006
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License version 2 as
9 published by the Free Software Foundation;
10
11 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
12 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
13 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
14 IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
15 CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
16 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19
20 ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
21 COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
22 SOFTWARE IS DISCLAIMED.
23*/
24
25/* Bluetooth HCI Management interface */
26
Johan Hedbergca69b792011-11-11 18:10:00 +020027#include <linux/kernel.h>
Szymon Janc72359752011-02-17 14:16:32 +010028#include <linux/uaccess.h>
Paul Gortmaker3a9a2312011-05-27 09:12:25 -040029#include <linux/module.h>
Johan Hedberg03811012010-12-08 00:21:06 +020030#include <asm/unaligned.h>
31
32#include <net/bluetooth/bluetooth.h>
33#include <net/bluetooth/hci_core.h>
34#include <net/bluetooth/mgmt.h>
Brian Gix5fe57d92011-12-21 16:12:13 -080035#include <net/bluetooth/smp.h>
Johan Hedberg03811012010-12-08 00:21:06 +020036
Marcel Holtmannd7b7e792012-02-20 21:47:49 +010037bool enable_hs;
38bool enable_le;
39
Johan Hedberg2da9c552012-02-17 14:39:28 +020040#define MGMT_VERSION 1
41#define MGMT_REVISION 0
Johan Hedberg02d98122010-12-13 21:07:04 +020042
Johan Hedberge70bb2e2012-02-13 16:59:33 +020043static const u16 mgmt_commands[] = {
44 MGMT_OP_READ_INDEX_LIST,
45 MGMT_OP_READ_INFO,
46 MGMT_OP_SET_POWERED,
47 MGMT_OP_SET_DISCOVERABLE,
48 MGMT_OP_SET_CONNECTABLE,
49 MGMT_OP_SET_FAST_CONNECTABLE,
50 MGMT_OP_SET_PAIRABLE,
51 MGMT_OP_SET_LINK_SECURITY,
52 MGMT_OP_SET_SSP,
53 MGMT_OP_SET_HS,
54 MGMT_OP_SET_LE,
55 MGMT_OP_SET_DEV_CLASS,
56 MGMT_OP_SET_LOCAL_NAME,
57 MGMT_OP_ADD_UUID,
58 MGMT_OP_REMOVE_UUID,
59 MGMT_OP_LOAD_LINK_KEYS,
60 MGMT_OP_LOAD_LONG_TERM_KEYS,
61 MGMT_OP_DISCONNECT,
62 MGMT_OP_GET_CONNECTIONS,
63 MGMT_OP_PIN_CODE_REPLY,
64 MGMT_OP_PIN_CODE_NEG_REPLY,
65 MGMT_OP_SET_IO_CAPABILITY,
66 MGMT_OP_PAIR_DEVICE,
67 MGMT_OP_CANCEL_PAIR_DEVICE,
68 MGMT_OP_UNPAIR_DEVICE,
69 MGMT_OP_USER_CONFIRM_REPLY,
70 MGMT_OP_USER_CONFIRM_NEG_REPLY,
71 MGMT_OP_USER_PASSKEY_REPLY,
72 MGMT_OP_USER_PASSKEY_NEG_REPLY,
73 MGMT_OP_READ_LOCAL_OOB_DATA,
74 MGMT_OP_ADD_REMOTE_OOB_DATA,
75 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
76 MGMT_OP_START_DISCOVERY,
77 MGMT_OP_STOP_DISCOVERY,
78 MGMT_OP_CONFIRM_NAME,
79 MGMT_OP_BLOCK_DEVICE,
80 MGMT_OP_UNBLOCK_DEVICE,
81};
82
83static const u16 mgmt_events[] = {
84 MGMT_EV_CONTROLLER_ERROR,
85 MGMT_EV_INDEX_ADDED,
86 MGMT_EV_INDEX_REMOVED,
87 MGMT_EV_NEW_SETTINGS,
88 MGMT_EV_CLASS_OF_DEV_CHANGED,
89 MGMT_EV_LOCAL_NAME_CHANGED,
90 MGMT_EV_NEW_LINK_KEY,
91 MGMT_EV_NEW_LONG_TERM_KEY,
92 MGMT_EV_DEVICE_CONNECTED,
93 MGMT_EV_DEVICE_DISCONNECTED,
94 MGMT_EV_CONNECT_FAILED,
95 MGMT_EV_PIN_CODE_REQUEST,
96 MGMT_EV_USER_CONFIRM_REQUEST,
97 MGMT_EV_USER_PASSKEY_REQUEST,
98 MGMT_EV_AUTH_FAILED,
99 MGMT_EV_DEVICE_FOUND,
100 MGMT_EV_DISCOVERING,
101 MGMT_EV_DEVICE_BLOCKED,
102 MGMT_EV_DEVICE_UNBLOCKED,
103 MGMT_EV_DEVICE_UNPAIRED,
104};
105
Andre Guedes3fd24152012-02-03 17:48:01 -0300106/*
107 * These LE scan and inquiry parameters were chosen according to LE General
108 * Discovery Procedure specification.
109 */
110#define LE_SCAN_TYPE 0x01
111#define LE_SCAN_WIN 0x12
112#define LE_SCAN_INT 0x12
113#define LE_SCAN_TIMEOUT_LE_ONLY 10240 /* TGAP(gen_disc_scan_min) */
Andre Guedes5e0452c2012-02-17 20:39:38 -0300114#define LE_SCAN_TIMEOUT_BREDR_LE 5120 /* TGAP(100)/2 */
Andre Guedes3fd24152012-02-03 17:48:01 -0300115
Andre Guedese8777522012-02-03 17:48:02 -0300116#define INQUIRY_LEN_BREDR 0x08 /* TGAP(100) */
Andre Guedes5e0452c2012-02-17 20:39:38 -0300117#define INQUIRY_LEN_BREDR_LE 0x04 /* TGAP(100)/2 */
Andre Guedes2519a1f2011-11-07 11:45:24 -0300118
Johan Hedberg7d785252011-12-15 00:47:39 +0200119#define SERVICE_CACHE_TIMEOUT (5 * 1000)
120
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200121#define hdev_is_powered(hdev) (test_bit(HCI_UP, &hdev->flags) && \
122 !test_bit(HCI_AUTO_OFF, &hdev->dev_flags))
123
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200124struct pending_cmd {
125 struct list_head list;
Johan Hedbergfc2f4b12011-11-09 13:58:56 +0200126 u16 opcode;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200127 int index;
Szymon Jancc68fb7f2011-03-22 13:12:19 +0100128 void *param;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200129 struct sock *sk;
Johan Hedberge9a416b2011-02-19 12:05:56 -0300130 void *user_data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200131};
132
Johan Hedbergca69b792011-11-11 18:10:00 +0200133/* HCI to MGMT error code conversion table */
134static u8 mgmt_status_table[] = {
135 MGMT_STATUS_SUCCESS,
136 MGMT_STATUS_UNKNOWN_COMMAND, /* Unknown Command */
137 MGMT_STATUS_NOT_CONNECTED, /* No Connection */
138 MGMT_STATUS_FAILED, /* Hardware Failure */
139 MGMT_STATUS_CONNECT_FAILED, /* Page Timeout */
140 MGMT_STATUS_AUTH_FAILED, /* Authentication Failed */
141 MGMT_STATUS_NOT_PAIRED, /* PIN or Key Missing */
142 MGMT_STATUS_NO_RESOURCES, /* Memory Full */
143 MGMT_STATUS_TIMEOUT, /* Connection Timeout */
144 MGMT_STATUS_NO_RESOURCES, /* Max Number of Connections */
145 MGMT_STATUS_NO_RESOURCES, /* Max Number of SCO Connections */
146 MGMT_STATUS_ALREADY_CONNECTED, /* ACL Connection Exists */
147 MGMT_STATUS_BUSY, /* Command Disallowed */
148 MGMT_STATUS_NO_RESOURCES, /* Rejected Limited Resources */
149 MGMT_STATUS_REJECTED, /* Rejected Security */
150 MGMT_STATUS_REJECTED, /* Rejected Personal */
151 MGMT_STATUS_TIMEOUT, /* Host Timeout */
152 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Feature */
153 MGMT_STATUS_INVALID_PARAMS, /* Invalid Parameters */
154 MGMT_STATUS_DISCONNECTED, /* OE User Ended Connection */
155 MGMT_STATUS_NO_RESOURCES, /* OE Low Resources */
156 MGMT_STATUS_DISCONNECTED, /* OE Power Off */
157 MGMT_STATUS_DISCONNECTED, /* Connection Terminated */
158 MGMT_STATUS_BUSY, /* Repeated Attempts */
159 MGMT_STATUS_REJECTED, /* Pairing Not Allowed */
160 MGMT_STATUS_FAILED, /* Unknown LMP PDU */
161 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Remote Feature */
162 MGMT_STATUS_REJECTED, /* SCO Offset Rejected */
163 MGMT_STATUS_REJECTED, /* SCO Interval Rejected */
164 MGMT_STATUS_REJECTED, /* Air Mode Rejected */
165 MGMT_STATUS_INVALID_PARAMS, /* Invalid LMP Parameters */
166 MGMT_STATUS_FAILED, /* Unspecified Error */
167 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported LMP Parameter Value */
168 MGMT_STATUS_FAILED, /* Role Change Not Allowed */
169 MGMT_STATUS_TIMEOUT, /* LMP Response Timeout */
170 MGMT_STATUS_FAILED, /* LMP Error Transaction Collision */
171 MGMT_STATUS_FAILED, /* LMP PDU Not Allowed */
172 MGMT_STATUS_REJECTED, /* Encryption Mode Not Accepted */
173 MGMT_STATUS_FAILED, /* Unit Link Key Used */
174 MGMT_STATUS_NOT_SUPPORTED, /* QoS Not Supported */
175 MGMT_STATUS_TIMEOUT, /* Instant Passed */
176 MGMT_STATUS_NOT_SUPPORTED, /* Pairing Not Supported */
177 MGMT_STATUS_FAILED, /* Transaction Collision */
178 MGMT_STATUS_INVALID_PARAMS, /* Unacceptable Parameter */
179 MGMT_STATUS_REJECTED, /* QoS Rejected */
180 MGMT_STATUS_NOT_SUPPORTED, /* Classification Not Supported */
181 MGMT_STATUS_REJECTED, /* Insufficient Security */
182 MGMT_STATUS_INVALID_PARAMS, /* Parameter Out Of Range */
183 MGMT_STATUS_BUSY, /* Role Switch Pending */
184 MGMT_STATUS_FAILED, /* Slot Violation */
185 MGMT_STATUS_FAILED, /* Role Switch Failed */
186 MGMT_STATUS_INVALID_PARAMS, /* EIR Too Large */
187 MGMT_STATUS_NOT_SUPPORTED, /* Simple Pairing Not Supported */
188 MGMT_STATUS_BUSY, /* Host Busy Pairing */
189 MGMT_STATUS_REJECTED, /* Rejected, No Suitable Channel */
190 MGMT_STATUS_BUSY, /* Controller Busy */
191 MGMT_STATUS_INVALID_PARAMS, /* Unsuitable Connection Interval */
192 MGMT_STATUS_TIMEOUT, /* Directed Advertising Timeout */
193 MGMT_STATUS_AUTH_FAILED, /* Terminated Due to MIC Failure */
194 MGMT_STATUS_CONNECT_FAILED, /* Connection Establishment Failed */
195 MGMT_STATUS_CONNECT_FAILED, /* MAC Connection Failed */
196};
197
198static u8 mgmt_status(u8 hci_status)
199{
200 if (hci_status < ARRAY_SIZE(mgmt_status_table))
201 return mgmt_status_table[hci_status];
202
203 return MGMT_STATUS_FAILED;
204}
205
Szymon Janc4e51eae2011-02-25 19:05:48 +0100206static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200207{
208 struct sk_buff *skb;
209 struct mgmt_hdr *hdr;
210 struct mgmt_ev_cmd_status *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300211 int err;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200212
Szymon Janc34eb5252011-02-28 14:10:08 +0100213 BT_DBG("sock %p, index %u, cmd %u, status %u", sk, index, cmd, status);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200214
215 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_ATOMIC);
216 if (!skb)
217 return -ENOMEM;
218
219 hdr = (void *) skb_put(skb, sizeof(*hdr));
220
221 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_STATUS);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100222 hdr->index = cpu_to_le16(index);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200223 hdr->len = cpu_to_le16(sizeof(*ev));
224
225 ev = (void *) skb_put(skb, sizeof(*ev));
226 ev->status = status;
227 put_unaligned_le16(cmd, &ev->opcode);
228
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300229 err = sock_queue_rcv_skb(sk, skb);
230 if (err < 0)
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200231 kfree_skb(skb);
232
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300233 return err;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200234}
235
Johan Hedbergaee9b212012-02-18 15:07:59 +0200236static int cmd_complete(struct sock *sk, u16 index, u16 cmd, u8 status,
237 void *rp, size_t rp_len)
Johan Hedberg02d98122010-12-13 21:07:04 +0200238{
239 struct sk_buff *skb;
240 struct mgmt_hdr *hdr;
241 struct mgmt_ev_cmd_complete *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300242 int err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200243
244 BT_DBG("sock %p", sk);
245
Johan Hedberga38528f2011-01-22 06:46:43 +0200246 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + rp_len, GFP_ATOMIC);
Johan Hedberg02d98122010-12-13 21:07:04 +0200247 if (!skb)
248 return -ENOMEM;
249
250 hdr = (void *) skb_put(skb, sizeof(*hdr));
Johan Hedberga38528f2011-01-22 06:46:43 +0200251
Johan Hedberg02d98122010-12-13 21:07:04 +0200252 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100253 hdr->index = cpu_to_le16(index);
Johan Hedberga38528f2011-01-22 06:46:43 +0200254 hdr->len = cpu_to_le16(sizeof(*ev) + rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200255
Johan Hedberga38528f2011-01-22 06:46:43 +0200256 ev = (void *) skb_put(skb, sizeof(*ev) + rp_len);
257 put_unaligned_le16(cmd, &ev->opcode);
Johan Hedbergaee9b212012-02-18 15:07:59 +0200258 ev->status = status;
Szymon Janc8020c162011-02-28 14:09:50 +0100259
260 if (rp)
261 memcpy(ev->data, rp, rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200262
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300263 err = sock_queue_rcv_skb(sk, skb);
264 if (err < 0)
Johan Hedberg02d98122010-12-13 21:07:04 +0200265 kfree_skb(skb);
266
Marcel Holtmanne5f0e152012-02-22 11:59:01 +0100267 return err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200268}
269
Johan Hedberga38528f2011-01-22 06:46:43 +0200270static int read_version(struct sock *sk)
271{
272 struct mgmt_rp_read_version rp;
273
274 BT_DBG("sock %p", sk);
275
276 rp.version = MGMT_VERSION;
277 put_unaligned_le16(MGMT_REVISION, &rp.revision);
278
Johan Hedbergaee9b212012-02-18 15:07:59 +0200279 return cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, 0, &rp,
Szymon Janc4e51eae2011-02-25 19:05:48 +0100280 sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200281}
282
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200283static int read_commands(struct sock *sk)
284{
285 struct mgmt_rp_read_commands *rp;
286 u16 num_commands = ARRAY_SIZE(mgmt_commands);
287 u16 num_events = ARRAY_SIZE(mgmt_events);
288 u16 *opcode;
289 size_t rp_size;
290 int i, err;
291
292 BT_DBG("sock %p", sk);
293
294 rp_size = sizeof(*rp) + ((num_commands + num_events) * sizeof(u16));
295
296 rp = kmalloc(rp_size, GFP_KERNEL);
297 if (!rp)
298 return -ENOMEM;
299
300 put_unaligned_le16(num_commands, &rp->num_commands);
301 put_unaligned_le16(num_events, &rp->num_events);
302
303 for (i = 0, opcode = rp->opcodes; i < num_commands; i++, opcode++)
304 put_unaligned_le16(mgmt_commands[i], opcode);
305
306 for (i = 0; i < num_events; i++, opcode++)
307 put_unaligned_le16(mgmt_events[i], opcode);
308
Johan Hedbergaee9b212012-02-18 15:07:59 +0200309 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_COMMANDS, 0, rp,
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200310 rp_size);
311 kfree(rp);
312
313 return err;
314}
315
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200316static int read_index_list(struct sock *sk)
317{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200318 struct mgmt_rp_read_index_list *rp;
319 struct list_head *p;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200320 struct hci_dev *d;
Johan Hedberga38528f2011-01-22 06:46:43 +0200321 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200322 u16 count;
Johan Hedberga38528f2011-01-22 06:46:43 +0200323 int i, err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200324
325 BT_DBG("sock %p", sk);
326
327 read_lock(&hci_dev_list_lock);
328
329 count = 0;
330 list_for_each(p, &hci_dev_list) {
331 count++;
332 }
333
Johan Hedberga38528f2011-01-22 06:46:43 +0200334 rp_len = sizeof(*rp) + (2 * count);
335 rp = kmalloc(rp_len, GFP_ATOMIC);
336 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100337 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200338 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100339 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200340
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200341 put_unaligned_le16(count, &rp->num_controllers);
342
343 i = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200344 list_for_each_entry(d, &hci_dev_list, list) {
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200345 if (test_bit(HCI_SETUP, &d->dev_flags))
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200346 continue;
347
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200348 put_unaligned_le16(d->id, &rp->index[i++]);
349 BT_DBG("Added hci%u", d->id);
350 }
351
352 read_unlock(&hci_dev_list_lock);
353
Johan Hedbergaee9b212012-02-18 15:07:59 +0200354 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST, 0, rp,
Szymon Janc4e51eae2011-02-25 19:05:48 +0100355 rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200356
Johan Hedberga38528f2011-01-22 06:46:43 +0200357 kfree(rp);
358
359 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200360}
361
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200362static u32 get_supported_settings(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +0200363{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200364 u32 settings = 0;
Johan Hedberg03811012010-12-08 00:21:06 +0200365
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200366 settings |= MGMT_SETTING_POWERED;
367 settings |= MGMT_SETTING_CONNECTABLE;
368 settings |= MGMT_SETTING_FAST_CONNECTABLE;
369 settings |= MGMT_SETTING_DISCOVERABLE;
370 settings |= MGMT_SETTING_PAIRABLE;
Johan Hedberg03811012010-12-08 00:21:06 +0200371
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200372 if (hdev->features[6] & LMP_SIMPLE_PAIR)
373 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200374
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200375 if (!(hdev->features[4] & LMP_NO_BREDR)) {
376 settings |= MGMT_SETTING_BREDR;
377 settings |= MGMT_SETTING_LINK_SECURITY;
378 }
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200379
Marcel Holtmannd7b7e792012-02-20 21:47:49 +0100380 if (enable_hs)
381 settings |= MGMT_SETTING_HS;
382
383 if (enable_le) {
384 if (hdev->features[4] & LMP_LE)
385 settings |= MGMT_SETTING_LE;
386 }
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200387
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200388 return settings;
389}
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200390
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200391static u32 get_current_settings(struct hci_dev *hdev)
392{
393 u32 settings = 0;
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200394
Johan Hedbergf1f0eb02012-02-21 17:15:41 +0200395 if (hdev_is_powered(hdev))
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100396 settings |= MGMT_SETTING_POWERED;
397
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200398 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200399 settings |= MGMT_SETTING_CONNECTABLE;
400
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200401 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200402 settings |= MGMT_SETTING_DISCOVERABLE;
403
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200404 if (test_bit(HCI_PAIRABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200405 settings |= MGMT_SETTING_PAIRABLE;
406
407 if (!(hdev->features[4] & LMP_NO_BREDR))
408 settings |= MGMT_SETTING_BREDR;
409
Johan Hedberg06199cf2012-02-22 16:37:11 +0200410 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200411 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200412
Johan Hedberg47990ea2012-02-22 11:58:37 +0200413 if (test_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200414 settings |= MGMT_SETTING_LINK_SECURITY;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200415
Johan Hedberg84bde9d2012-01-25 14:21:06 +0200416 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200417 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200418
Johan Hedberg6d80dfd2012-02-20 23:50:38 +0200419 if (test_bit(HCI_HS_ENABLED, &hdev->dev_flags))
420 settings |= MGMT_SETTING_HS;
421
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200422 return settings;
Johan Hedbergc542a062011-01-26 13:11:03 +0200423}
424
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300425#define PNP_INFO_SVCLASS_ID 0x1200
426
427static u8 bluetooth_base_uuid[] = {
428 0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80,
429 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
430};
431
432static u16 get_uuid16(u8 *uuid128)
433{
434 u32 val;
435 int i;
436
437 for (i = 0; i < 12; i++) {
438 if (bluetooth_base_uuid[i] != uuid128[i])
439 return 0;
440 }
441
442 memcpy(&val, &uuid128[12], 4);
443
444 val = le32_to_cpu(val);
445 if (val > 0xffff)
446 return 0;
447
448 return (u16) val;
449}
450
451static void create_eir(struct hci_dev *hdev, u8 *data)
452{
453 u8 *ptr = data;
454 u16 eir_len = 0;
455 u16 uuid16_list[HCI_MAX_EIR_LENGTH / sizeof(u16)];
456 int i, truncated = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200457 struct bt_uuid *uuid;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300458 size_t name_len;
459
460 name_len = strlen(hdev->dev_name);
461
462 if (name_len > 0) {
463 /* EIR Data type */
464 if (name_len > 48) {
465 name_len = 48;
466 ptr[1] = EIR_NAME_SHORT;
467 } else
468 ptr[1] = EIR_NAME_COMPLETE;
469
470 /* EIR Data length */
471 ptr[0] = name_len + 1;
472
473 memcpy(ptr + 2, hdev->dev_name, name_len);
474
475 eir_len += (name_len + 2);
476 ptr += (name_len + 2);
477 }
478
479 memset(uuid16_list, 0, sizeof(uuid16_list));
480
481 /* Group all UUID16 types */
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200482 list_for_each_entry(uuid, &hdev->uuids, list) {
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300483 u16 uuid16;
484
485 uuid16 = get_uuid16(uuid->uuid);
486 if (uuid16 == 0)
487 return;
488
489 if (uuid16 < 0x1100)
490 continue;
491
492 if (uuid16 == PNP_INFO_SVCLASS_ID)
493 continue;
494
495 /* Stop if not enough space to put next UUID */
496 if (eir_len + 2 + sizeof(u16) > HCI_MAX_EIR_LENGTH) {
497 truncated = 1;
498 break;
499 }
500
501 /* Check for duplicates */
502 for (i = 0; uuid16_list[i] != 0; i++)
503 if (uuid16_list[i] == uuid16)
504 break;
505
506 if (uuid16_list[i] == 0) {
507 uuid16_list[i] = uuid16;
508 eir_len += sizeof(u16);
509 }
510 }
511
512 if (uuid16_list[0] != 0) {
513 u8 *length = ptr;
514
515 /* EIR Data type */
516 ptr[1] = truncated ? EIR_UUID16_SOME : EIR_UUID16_ALL;
517
518 ptr += 2;
519 eir_len += 2;
520
521 for (i = 0; uuid16_list[i] != 0; i++) {
522 *ptr++ = (uuid16_list[i] & 0x00ff);
523 *ptr++ = (uuid16_list[i] & 0xff00) >> 8;
524 }
525
526 /* EIR Data length */
527 *length = (i * sizeof(u16)) + 1;
528 }
529}
530
531static int update_eir(struct hci_dev *hdev)
532{
533 struct hci_cp_write_eir cp;
534
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200535 if (!hdev_is_powered(hdev))
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200536 return 0;
537
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300538 if (!(hdev->features[6] & LMP_EXT_INQ))
539 return 0;
540
Johan Hedberg84bde9d2012-01-25 14:21:06 +0200541 if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300542 return 0;
543
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200544 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300545 return 0;
546
547 memset(&cp, 0, sizeof(cp));
548
549 create_eir(hdev, cp.data);
550
551 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
552 return 0;
553
554 memcpy(hdev->eir, cp.data, sizeof(cp.data));
555
556 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
557}
558
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200559static u8 get_service_classes(struct hci_dev *hdev)
560{
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300561 struct bt_uuid *uuid;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200562 u8 val = 0;
563
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300564 list_for_each_entry(uuid, &hdev->uuids, list)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200565 val |= uuid->svc_hint;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200566
567 return val;
568}
569
570static int update_class(struct hci_dev *hdev)
571{
572 u8 cod[3];
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 Hedberg0cbf4ed2012-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 Hedberg0cbf4ed2012-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 Hedbergaee9b212012-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 Hedbergaee9b212012-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;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001263 u8 val, enabled;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001264
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;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001283 enabled = !!(hdev->host_features[0] & LMP_HOST_LE);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001284
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001285 if (!hdev_is_powered(hdev) || val == enabled) {
Johan Hedberg06199cf2012-02-22 16:37:11 +02001286 bool changed = false;
1287
1288 if (val != test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
1289 change_bit(HCI_LE_ENABLED, &hdev->dev_flags);
1290 changed = true;
1291 }
1292
1293 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1294 if (err < 0)
1295 goto failed;
1296
1297 if (changed)
1298 err = new_settings(hdev, sk);
1299
1300 goto failed;
1301 }
1302
1303 if (mgmt_pending_find(MGMT_OP_SET_LE, hdev)) {
1304 err = cmd_status(sk, index, MGMT_OP_SET_LE, MGMT_STATUS_BUSY);
1305 goto failed;
1306 }
1307
1308 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
1309 if (!cmd) {
1310 err = -ENOMEM;
1311 goto failed;
1312 }
1313
1314 memset(&hci_cp, 0, sizeof(hci_cp));
1315
1316 if (val) {
1317 hci_cp.le = val;
1318 hci_cp.simul = !!(hdev->features[6] & LMP_SIMUL_LE_BR);
1319 }
1320
1321 err = hci_send_cmd(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED,
1322 sizeof(hci_cp), &hci_cp);
1323 if (err < 0) {
1324 mgmt_pending_remove(cmd);
1325 goto failed;
1326 }
1327
1328failed:
1329 hci_dev_put(hdev);
1330 return err;
1331}
1332
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001333static int add_uuid(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001334{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001335 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001336 struct pending_cmd *cmd;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001337 struct hci_dev *hdev;
1338 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001339 int err;
1340
Szymon Janc4e51eae2011-02-25 19:05:48 +01001341 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001342
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001343 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001344 return cmd_status(sk, index, MGMT_OP_ADD_UUID,
1345 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001346
Szymon Janc4e51eae2011-02-25 19:05:48 +01001347 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001348 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001349 return cmd_status(sk, index, MGMT_OP_ADD_UUID,
1350 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001351
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001352 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001353
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001354 if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
1355 err = cmd_status(sk, index, MGMT_OP_ADD_UUID,
1356 MGMT_STATUS_BUSY);
1357 goto failed;
1358 }
1359
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001360 uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC);
1361 if (!uuid) {
1362 err = -ENOMEM;
1363 goto failed;
1364 }
1365
1366 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001367 uuid->svc_hint = cp->svc_hint;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001368
1369 list_add(&uuid->list, &hdev->uuids);
1370
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001371 err = update_class(hdev);
1372 if (err < 0)
1373 goto failed;
1374
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001375 err = update_eir(hdev);
1376 if (err < 0)
1377 goto failed;
1378
Johan Hedberg90e70452012-02-23 23:09:40 +02001379 if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
1380 err = cmd_complete(sk, index, MGMT_OP_ADD_UUID, 0,
1381 hdev->dev_class, 3);
1382 goto failed;
1383 }
1384
1385 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len);
1386 if (!cmd) {
1387 err = -ENOMEM;
1388 goto failed;
1389 }
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001390
1391failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001392 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001393 hci_dev_put(hdev);
1394
1395 return err;
1396}
1397
Johan Hedberg24b78d02012-02-23 23:24:30 +02001398static bool enable_service_cache(struct hci_dev *hdev)
1399{
1400 if (!hdev_is_powered(hdev))
1401 return false;
1402
1403 if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
1404 schedule_delayed_work(&hdev->service_cache,
1405 msecs_to_jiffies(SERVICE_CACHE_TIMEOUT));
1406 return true;
1407 }
1408
1409 return false;
1410}
1411
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001412static int remove_uuid(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001413{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001414 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001415 struct pending_cmd *cmd;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001416 struct list_head *p, *n;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001417 struct hci_dev *hdev;
1418 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 +02001419 int err, found;
1420
Szymon Janc4e51eae2011-02-25 19:05:48 +01001421 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001422
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001423 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001424 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
1425 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001426
Szymon Janc4e51eae2011-02-25 19:05:48 +01001427 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001428 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001429 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
1430 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001431
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001432 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001433
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001434 if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
1435 err = cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
1436 MGMT_STATUS_BUSY);
1437 goto unlock;
1438 }
1439
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001440 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
1441 err = hci_uuids_clear(hdev);
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001442
Johan Hedberg24b78d02012-02-23 23:24:30 +02001443 if (enable_service_cache(hdev)) {
1444 err = cmd_complete(sk, index, MGMT_OP_REMOVE_UUID, 0,
1445 hdev->dev_class, 3);
1446 goto unlock;
1447 }
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001448
Johan Hedberg9246a862012-02-23 21:33:16 +02001449 goto update_class;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001450 }
1451
1452 found = 0;
1453
1454 list_for_each_safe(p, n, &hdev->uuids) {
1455 struct bt_uuid *match = list_entry(p, struct bt_uuid, list);
1456
1457 if (memcmp(match->uuid, cp->uuid, 16) != 0)
1458 continue;
1459
1460 list_del(&match->list);
1461 found++;
1462 }
1463
1464 if (found == 0) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001465 err = cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
1466 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001467 goto unlock;
1468 }
1469
Johan Hedberg9246a862012-02-23 21:33:16 +02001470update_class:
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001471 err = update_class(hdev);
1472 if (err < 0)
1473 goto unlock;
1474
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001475 err = update_eir(hdev);
1476 if (err < 0)
1477 goto unlock;
1478
Johan Hedberg90e70452012-02-23 23:09:40 +02001479 if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
1480 err = cmd_complete(sk, index, MGMT_OP_REMOVE_UUID, 0,
Johan Hedberg9997a532012-02-23 15:57:46 +02001481 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001482 goto unlock;
1483 }
1484
1485 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
1486 if (!cmd) {
1487 err = -ENOMEM;
1488 goto unlock;
1489 }
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001490
1491unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001492 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001493 hci_dev_put(hdev);
1494
1495 return err;
1496}
1497
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001498static int set_dev_class(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001499{
1500 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001501 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001502 struct pending_cmd *cmd;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001503 int err;
1504
Szymon Janc4e51eae2011-02-25 19:05:48 +01001505 BT_DBG("request for hci%u", index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001506
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001507 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001508 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS,
1509 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001510
Szymon Janc4e51eae2011-02-25 19:05:48 +01001511 hdev = hci_dev_get(index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001512 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001513 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS,
1514 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001515
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001516 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001517
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001518 if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
1519 err = cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS,
1520 MGMT_STATUS_BUSY);
1521 goto unlock;
1522 }
1523
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001524 hdev->major_class = cp->major;
1525 hdev->minor_class = cp->minor;
1526
Johan Hedberg932f5ff2012-02-22 22:11:32 +02001527 if (!hdev_is_powered(hdev)) {
1528 err = cmd_complete(sk, index, MGMT_OP_SET_DEV_CLASS, 0,
1529 hdev->dev_class, 3);
1530 goto unlock;
1531 }
1532
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001533 if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02001534 hci_dev_unlock(hdev);
1535 cancel_delayed_work_sync(&hdev->service_cache);
1536 hci_dev_lock(hdev);
Johan Hedberg14c0b602011-12-15 00:47:37 +02001537 update_eir(hdev);
Johan Hedberg7d785252011-12-15 00:47:39 +02001538 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02001539
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001540 err = update_class(hdev);
Johan Hedberg90e70452012-02-23 23:09:40 +02001541 if (err < 0)
1542 goto unlock;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001543
Johan Hedberg90e70452012-02-23 23:09:40 +02001544 if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergaee9b212012-02-18 15:07:59 +02001545 err = cmd_complete(sk, index, MGMT_OP_SET_DEV_CLASS, 0,
Johan Hedberg8ec37032012-02-22 22:02:50 +02001546 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001547 goto unlock;
1548 }
1549
1550 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
1551 if (!cmd) {
1552 err = -ENOMEM;
1553 goto unlock;
1554 }
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001555
Johan Hedbergb5235a62012-02-21 14:32:24 +02001556unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001557 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001558 hci_dev_put(hdev);
1559
1560 return err;
1561}
1562
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001563static int load_link_keys(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001564{
1565 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001566 struct mgmt_cp_load_link_keys *cp = data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001567 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001568 int i;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001569
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001570 if (len < sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001571 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1572 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001573
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001574 key_count = get_unaligned_le16(&cp->key_count);
1575
Johan Hedberg86742e12011-11-07 23:13:38 +02001576 expected_len = sizeof(*cp) + key_count *
1577 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001578 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001579 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001580 len, expected_len);
Johan Hedbergca69b792011-11-11 18:10:00 +02001581 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1582 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001583 }
1584
Szymon Janc4e51eae2011-02-25 19:05:48 +01001585 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001586 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001587 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1588 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001589
Szymon Janc4e51eae2011-02-25 19:05:48 +01001590 BT_DBG("hci%u debug_keys %u key_count %u", index, cp->debug_keys,
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001591 key_count);
1592
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001593 hci_dev_lock(hdev);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001594
1595 hci_link_keys_clear(hdev);
1596
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001597 set_bit(HCI_LINK_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001598
1599 if (cp->debug_keys)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001600 set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001601 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001602 clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001603
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001604 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001605 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001606
Johan Hedbergd753fdc2012-02-17 14:06:34 +02001607 hci_add_link_key(hdev, NULL, 0, &key->addr.bdaddr, key->val,
1608 key->type, key->pin_len);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001609 }
1610
Johan Hedbergaee9b212012-02-18 15:07:59 +02001611 cmd_complete(sk, index, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02001612
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001613 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001614 hci_dev_put(hdev);
1615
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001616 return 0;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001617}
1618
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001619static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
1620 u8 addr_type, struct sock *skip_sk)
1621{
1622 struct mgmt_ev_device_unpaired ev;
1623
1624 bacpy(&ev.addr.bdaddr, bdaddr);
1625 ev.addr.type = addr_type;
1626
1627 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
1628 skip_sk);
1629}
1630
Johan Hedberg124f6e32012-02-09 13:50:12 +02001631static int unpair_device(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001632{
1633 struct hci_dev *hdev;
Johan Hedberg124f6e32012-02-09 13:50:12 +02001634 struct mgmt_cp_unpair_device *cp = data;
1635 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001636 struct hci_cp_disconnect dc;
1637 struct pending_cmd *cmd;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001638 struct hci_conn *conn;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001639 int err;
1640
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001641 if (len != sizeof(*cp))
Johan Hedberg124f6e32012-02-09 13:50:12 +02001642 return cmd_status(sk, index, MGMT_OP_UNPAIR_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02001643 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001644
Szymon Janc4e51eae2011-02-25 19:05:48 +01001645 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001646 if (!hdev)
Johan Hedberg124f6e32012-02-09 13:50:12 +02001647 return cmd_status(sk, index, MGMT_OP_UNPAIR_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02001648 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001649
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001650 hci_dev_lock(hdev);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001651
Johan Hedberga8a1d192011-11-10 15:54:38 +02001652 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02001653 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1654 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001655
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001656 if (!hdev_is_powered(hdev)) {
1657 err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE,
1658 MGMT_STATUS_NOT_POWERED,
1659 &rp, sizeof(rp));
1660 goto unlock;
1661 }
1662
Johan Hedberg124f6e32012-02-09 13:50:12 +02001663 if (cp->addr.type == MGMT_ADDR_BREDR)
1664 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
1665 else
1666 err = hci_remove_ltk(hdev, &cp->addr.bdaddr);
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03001667
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001668 if (err < 0) {
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001669 err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE,
1670 MGMT_STATUS_NOT_PAIRED,
1671 &rp, sizeof(rp));
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001672 goto unlock;
1673 }
1674
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001675 if (cp->disconnect) {
1676 if (cp->addr.type == MGMT_ADDR_BREDR)
1677 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
1678 &cp->addr.bdaddr);
1679 else
1680 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
1681 &cp->addr.bdaddr);
1682 } else {
1683 conn = NULL;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001684 }
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001685
Johan Hedberga8a1d192011-11-10 15:54:38 +02001686 if (!conn) {
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001687 err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE, 0,
Johan Hedbergaee9b212012-02-18 15:07:59 +02001688 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001689 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001690 goto unlock;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001691 }
1692
Johan Hedberg124f6e32012-02-09 13:50:12 +02001693 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
1694 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02001695 if (!cmd) {
1696 err = -ENOMEM;
1697 goto unlock;
1698 }
1699
1700 put_unaligned_le16(conn->handle, &dc.handle);
1701 dc.reason = 0x13; /* Remote User Terminated Connection */
1702 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1703 if (err < 0)
1704 mgmt_pending_remove(cmd);
1705
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001706unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001707 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001708 hci_dev_put(hdev);
1709
1710 return err;
1711}
1712
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001713static int disconnect(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02001714{
1715 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001716 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001717 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03001718 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001719 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001720 int err;
1721
1722 BT_DBG("");
1723
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001724 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001725 return cmd_status(sk, index, MGMT_OP_DISCONNECT,
1726 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001727
Szymon Janc4e51eae2011-02-25 19:05:48 +01001728 hdev = hci_dev_get(index);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001729 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001730 return cmd_status(sk, index, MGMT_OP_DISCONNECT,
1731 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001732
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001733 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001734
1735 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001736 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1737 MGMT_STATUS_NOT_POWERED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001738 goto failed;
1739 }
1740
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001741 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001742 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1743 MGMT_STATUS_BUSY);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001744 goto failed;
1745 }
1746
Johan Hedberg88c3df12012-02-09 14:27:38 +02001747 if (cp->addr.type == MGMT_ADDR_BREDR)
1748 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
1749 else
1750 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03001751
Johan Hedberg8962ee72011-01-20 12:40:27 +02001752 if (!conn) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001753 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1754 MGMT_STATUS_NOT_CONNECTED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001755 goto failed;
1756 }
1757
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001758 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001759 if (!cmd) {
1760 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001761 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001762 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001763
1764 put_unaligned_le16(conn->handle, &dc.handle);
1765 dc.reason = 0x13; /* Remote User Terminated Connection */
1766
1767 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1768 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001769 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001770
1771failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001772 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001773 hci_dev_put(hdev);
1774
1775 return err;
1776}
1777
Johan Hedberg48264f02011-11-09 13:58:58 +02001778static u8 link_to_mgmt(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02001779{
1780 switch (link_type) {
1781 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02001782 switch (addr_type) {
1783 case ADDR_LE_DEV_PUBLIC:
1784 return MGMT_ADDR_LE_PUBLIC;
1785 case ADDR_LE_DEV_RANDOM:
1786 return MGMT_ADDR_LE_RANDOM;
1787 default:
1788 return MGMT_ADDR_INVALID;
1789 }
Johan Hedberg4c659c32011-11-07 23:13:39 +02001790 case ACL_LINK:
1791 return MGMT_ADDR_BREDR;
1792 default:
1793 return MGMT_ADDR_INVALID;
1794 }
1795}
1796
Szymon Janc8ce62842011-03-01 16:55:32 +01001797static int get_connections(struct sock *sk, u16 index)
Johan Hedberg2784eb42011-01-21 13:56:35 +02001798{
Johan Hedberg2784eb42011-01-21 13:56:35 +02001799 struct mgmt_rp_get_connections *rp;
1800 struct hci_dev *hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001801 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02001802 size_t rp_len;
Johan Hedberg60fc5fb2012-02-23 09:52:28 +02001803 int err;
1804 u16 i;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001805
1806 BT_DBG("");
1807
Szymon Janc4e51eae2011-02-25 19:05:48 +01001808 hdev = hci_dev_get(index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001809 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001810 return cmd_status(sk, index, MGMT_OP_GET_CONNECTIONS,
1811 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001812
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001813 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001814
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001815 if (!hdev_is_powered(hdev)) {
1816 err = cmd_status(sk, index, MGMT_OP_GET_CONNECTIONS,
1817 MGMT_STATUS_NOT_POWERED);
1818 goto unlock;
1819 }
1820
Johan Hedberg60fc5fb2012-02-23 09:52:28 +02001821 i = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02001822 list_for_each_entry(c, &hdev->conn_hash.list, list) {
1823 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
Johan Hedberg60fc5fb2012-02-23 09:52:28 +02001824 i++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001825 }
1826
Johan Hedberg60fc5fb2012-02-23 09:52:28 +02001827 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberga38528f2011-01-22 06:46:43 +02001828 rp = kmalloc(rp_len, GFP_ATOMIC);
1829 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02001830 err = -ENOMEM;
1831 goto unlock;
1832 }
1833
Johan Hedberg2784eb42011-01-21 13:56:35 +02001834 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001835 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02001836 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
1837 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001838 bacpy(&rp->addr[i].bdaddr, &c->dst);
Johan Hedberg48264f02011-11-09 13:58:58 +02001839 rp->addr[i].type = link_to_mgmt(c->type, c->dst_type);
Johan Hedberg4c659c32011-11-07 23:13:39 +02001840 if (rp->addr[i].type == MGMT_ADDR_INVALID)
1841 continue;
1842 i++;
1843 }
1844
Johan Hedberg60fc5fb2012-02-23 09:52:28 +02001845 put_unaligned_le16(i, &rp->conn_count);
1846
Johan Hedberg4c659c32011-11-07 23:13:39 +02001847 /* Recalculate length in case of filtered SCO connections, etc */
1848 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02001849
Johan Hedbergaee9b212012-02-18 15:07:59 +02001850 err = cmd_complete(sk, index, MGMT_OP_GET_CONNECTIONS, 0, rp, rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001851
Johan Hedberga38528f2011-01-22 06:46:43 +02001852 kfree(rp);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001853
1854unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001855 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001856 hci_dev_put(hdev);
1857 return err;
1858}
1859
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001860static int send_pin_code_neg_reply(struct sock *sk, u16 index,
1861 struct hci_dev *hdev, struct mgmt_cp_pin_code_neg_reply *cp)
1862{
1863 struct pending_cmd *cmd;
1864 int err;
1865
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001866 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001867 sizeof(*cp));
1868 if (!cmd)
1869 return -ENOMEM;
1870
Johan Hedbergd8457692012-02-17 14:24:57 +02001871 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
1872 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001873 if (err < 0)
1874 mgmt_pending_remove(cmd);
1875
1876 return err;
1877}
1878
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001879static int pin_code_reply(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001880{
1881 struct hci_dev *hdev;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001882 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001883 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001884 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03001885 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001886 int err;
1887
1888 BT_DBG("");
1889
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001890 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001891 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1892 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001893
Szymon Janc4e51eae2011-02-25 19:05:48 +01001894 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001895 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001896 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1897 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001898
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001899 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001900
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001901 if (!hdev_is_powered(hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001902 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1903 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001904 goto failed;
1905 }
1906
Johan Hedbergd8457692012-02-17 14:24:57 +02001907 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001908 if (!conn) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001909 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1910 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001911 goto failed;
1912 }
1913
1914 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02001915 struct mgmt_cp_pin_code_neg_reply ncp;
1916
1917 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001918
1919 BT_ERR("PIN code is not 16 bytes long");
1920
1921 err = send_pin_code_neg_reply(sk, index, hdev, &ncp);
1922 if (err >= 0)
1923 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001924 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001925
1926 goto failed;
1927 }
1928
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001929 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data,
1930 len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001931 if (!cmd) {
1932 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001933 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001934 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02001935
Johan Hedbergd8457692012-02-17 14:24:57 +02001936 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001937 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02001938 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02001939
1940 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
1941 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001942 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001943
1944failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001945 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001946 hci_dev_put(hdev);
1947
1948 return err;
1949}
1950
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001951static int pin_code_neg_reply(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001952{
1953 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001954 struct mgmt_cp_pin_code_neg_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001955 int err;
1956
1957 BT_DBG("");
1958
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001959 if (len != sizeof(*cp))
1960 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001961 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001962
Szymon Janc4e51eae2011-02-25 19:05:48 +01001963 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001964 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001965 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001966 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001967
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001968 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001969
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001970 if (!hdev_is_powered(hdev)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001971 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001972 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001973 goto failed;
1974 }
1975
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001976 err = send_pin_code_neg_reply(sk, index, hdev, cp);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001977
1978failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001979 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001980 hci_dev_put(hdev);
1981
1982 return err;
1983}
1984
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001985static int set_io_capability(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001986{
1987 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001988 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001989
1990 BT_DBG("");
1991
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001992 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001993 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY,
1994 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001995
Szymon Janc4e51eae2011-02-25 19:05:48 +01001996 hdev = hci_dev_get(index);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001997 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001998 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY,
1999 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002000
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002001 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002002
2003 hdev->io_capability = cp->io_capability;
2004
2005 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Szymon Jancb8534e02011-03-01 16:55:34 +01002006 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002007
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002008 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002009 hci_dev_put(hdev);
2010
Johan Hedbergaee9b212012-02-18 15:07:59 +02002011 return cmd_complete(sk, index, MGMT_OP_SET_IO_CAPABILITY, 0, NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002012}
2013
Johan Hedberge9a416b2011-02-19 12:05:56 -03002014static inline struct pending_cmd *find_pairing(struct hci_conn *conn)
2015{
2016 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002017 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002018
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002019 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03002020 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
2021 continue;
2022
Johan Hedberge9a416b2011-02-19 12:05:56 -03002023 if (cmd->user_data != conn)
2024 continue;
2025
2026 return cmd;
2027 }
2028
2029 return NULL;
2030}
2031
2032static void pairing_complete(struct pending_cmd *cmd, u8 status)
2033{
2034 struct mgmt_rp_pair_device rp;
2035 struct hci_conn *conn = cmd->user_data;
2036
Johan Hedbergba4e5642011-11-11 00:07:34 +02002037 bacpy(&rp.addr.bdaddr, &conn->dst);
2038 rp.addr.type = link_to_mgmt(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002039
Johan Hedbergaee9b212012-02-18 15:07:59 +02002040 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, status,
2041 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002042
2043 /* So we don't get further callbacks for this connection */
2044 conn->connect_cfm_cb = NULL;
2045 conn->security_cfm_cb = NULL;
2046 conn->disconn_cfm_cb = NULL;
2047
2048 hci_conn_put(conn);
2049
Johan Hedberga664b5b2011-02-19 12:06:02 -03002050 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002051}
2052
2053static void pairing_complete_cb(struct hci_conn *conn, u8 status)
2054{
2055 struct pending_cmd *cmd;
2056
2057 BT_DBG("status %u", status);
2058
Johan Hedberg56e5cb82011-11-08 20:40:16 +02002059 cmd = find_pairing(conn);
2060 if (!cmd)
2061 BT_DBG("Unable to find a pending command");
2062 else
Johan Hedberge2113262012-02-18 15:20:03 +02002063 pairing_complete(cmd, mgmt_status(status));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002064}
2065
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002066static int pair_device(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002067{
2068 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002069 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02002070 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002071 struct pending_cmd *cmd;
2072 u8 sec_level, auth_type;
2073 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002074 int err;
2075
2076 BT_DBG("");
2077
Szymon Jancbdce7ba2011-02-25 19:05:49 +01002078 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02002079 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE,
2080 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01002081
Szymon Janc4e51eae2011-02-25 19:05:48 +01002082 hdev = hci_dev_get(index);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002083 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002084 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE,
2085 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002086
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002087 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002088
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002089 if (!hdev_is_powered(hdev)) {
2090 err = cmd_status(sk, index, MGMT_OP_PAIR_DEVICE,
2091 MGMT_STATUS_NOT_POWERED);
2092 goto unlock;
2093 }
2094
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002095 sec_level = BT_SECURITY_MEDIUM;
2096 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002097 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002098 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03002099 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002100
Johan Hedbergba4e5642011-11-11 00:07:34 +02002101 if (cp->addr.type == MGMT_ADDR_BREDR)
2102 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr, sec_level,
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002103 auth_type);
2104 else
Johan Hedbergba4e5642011-11-11 00:07:34 +02002105 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr, sec_level,
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002106 auth_type);
2107
Johan Hedberg1425acb2011-11-11 00:07:35 +02002108 memset(&rp, 0, sizeof(rp));
2109 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2110 rp.addr.type = cp->addr.type;
2111
Ville Tervo30e76272011-02-22 16:10:53 -03002112 if (IS_ERR(conn)) {
Johan Hedberge2113262012-02-18 15:20:03 +02002113 err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE,
2114 MGMT_STATUS_CONNECT_FAILED,
2115 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002116 goto unlock;
2117 }
2118
2119 if (conn->connect_cfm_cb) {
2120 hci_conn_put(conn);
Johan Hedberge2113262012-02-18 15:20:03 +02002121 err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE,
2122 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002123 goto unlock;
2124 }
2125
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002126 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002127 if (!cmd) {
2128 err = -ENOMEM;
2129 hci_conn_put(conn);
2130 goto unlock;
2131 }
2132
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002133 /* For LE, just connecting isn't a proof that the pairing finished */
Johan Hedbergba4e5642011-11-11 00:07:34 +02002134 if (cp->addr.type == MGMT_ADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002135 conn->connect_cfm_cb = pairing_complete_cb;
2136
Johan Hedberge9a416b2011-02-19 12:05:56 -03002137 conn->security_cfm_cb = pairing_complete_cb;
2138 conn->disconn_cfm_cb = pairing_complete_cb;
2139 conn->io_capability = cp->io_cap;
2140 cmd->user_data = conn;
2141
2142 if (conn->state == BT_CONNECTED &&
2143 hci_conn_security(conn, sec_level, auth_type))
2144 pairing_complete(cmd, 0);
2145
2146 err = 0;
2147
2148unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002149 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002150 hci_dev_put(hdev);
2151
2152 return err;
2153}
2154
Johan Hedberg28424702012-02-02 04:02:29 +02002155static int cancel_pair_device(struct sock *sk, u16 index,
2156 unsigned char *data, u16 len)
2157{
2158 struct mgmt_addr_info *addr = (void *) data;
2159 struct hci_dev *hdev;
2160 struct pending_cmd *cmd;
2161 struct hci_conn *conn;
2162 int err;
2163
2164 BT_DBG("");
2165
2166 if (len != sizeof(*addr))
2167 return cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
2168 MGMT_STATUS_INVALID_PARAMS);
2169
2170 hdev = hci_dev_get(index);
2171 if (!hdev)
2172 return cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
2173 MGMT_STATUS_INVALID_PARAMS);
2174
2175 hci_dev_lock(hdev);
2176
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002177 if (!hdev_is_powered(hdev)) {
2178 err = cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
2179 MGMT_STATUS_NOT_POWERED);
2180 goto unlock;
2181 }
2182
Johan Hedberg28424702012-02-02 04:02:29 +02002183 cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
2184 if (!cmd) {
2185 err = cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
2186 MGMT_STATUS_INVALID_PARAMS);
2187 goto unlock;
2188 }
2189
2190 conn = cmd->user_data;
2191
2192 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
2193 err = cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
2194 MGMT_STATUS_INVALID_PARAMS);
2195 goto unlock;
2196 }
2197
2198 pairing_complete(cmd, MGMT_STATUS_CANCELLED);
2199
Johan Hedbergaee9b212012-02-18 15:07:59 +02002200 err = cmd_complete(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE, 0, addr,
Johan Hedberg28424702012-02-02 04:02:29 +02002201 sizeof(*addr));
2202unlock:
2203 hci_dev_unlock(hdev);
2204 hci_dev_put(hdev);
2205
2206 return err;
2207}
2208
Brian Gix0df4c182011-11-16 13:53:13 -08002209static int user_pairing_resp(struct sock *sk, u16 index, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02002210 u8 type, u16 mgmt_op, u16 hci_op,
2211 __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03002212{
Johan Hedberga5c29682011-02-19 12:05:57 -03002213 struct pending_cmd *cmd;
2214 struct hci_dev *hdev;
Brian Gix0df4c182011-11-16 13:53:13 -08002215 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03002216 int err;
2217
Szymon Janc4e51eae2011-02-25 19:05:48 +01002218 hdev = hci_dev_get(index);
Johan Hedberga5c29682011-02-19 12:05:57 -03002219 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002220 return cmd_status(sk, index, mgmt_op,
2221 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga5c29682011-02-19 12:05:57 -03002222
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002223 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02002224
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002225 if (!hdev_is_powered(hdev)) {
Brian Gix0df4c182011-11-16 13:53:13 -08002226 err = cmd_status(sk, index, mgmt_op, MGMT_STATUS_NOT_POWERED);
2227 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002228 }
2229
Johan Hedberg272d90d2012-02-09 15:26:12 +02002230 if (type == MGMT_ADDR_BREDR)
2231 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, bdaddr);
2232 else
Brian Gix47c15e22011-11-16 13:53:14 -08002233 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, bdaddr);
Brian Gix47c15e22011-11-16 13:53:14 -08002234
Johan Hedberg272d90d2012-02-09 15:26:12 +02002235 if (!conn) {
2236 err = cmd_status(sk, index, mgmt_op,
2237 MGMT_STATUS_NOT_CONNECTED);
2238 goto done;
2239 }
2240
2241 if (type == MGMT_ADDR_LE_PUBLIC || type == MGMT_ADDR_LE_RANDOM) {
Brian Gix47c15e22011-11-16 13:53:14 -08002242 /* Continue with pairing via SMP */
Brian Gix5fe57d92011-12-21 16:12:13 -08002243 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix47c15e22011-11-16 13:53:14 -08002244
Brian Gix5fe57d92011-12-21 16:12:13 -08002245 if (!err)
2246 err = cmd_status(sk, index, mgmt_op,
2247 MGMT_STATUS_SUCCESS);
2248 else
2249 err = cmd_status(sk, index, mgmt_op,
2250 MGMT_STATUS_FAILED);
2251
Brian Gix47c15e22011-11-16 13:53:14 -08002252 goto done;
2253 }
2254
Brian Gix0df4c182011-11-16 13:53:13 -08002255 cmd = mgmt_pending_add(sk, mgmt_op, hdev, bdaddr, sizeof(*bdaddr));
Johan Hedberga5c29682011-02-19 12:05:57 -03002256 if (!cmd) {
2257 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08002258 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002259 }
2260
Brian Gix0df4c182011-11-16 13:53:13 -08002261 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08002262 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
2263 struct hci_cp_user_passkey_reply cp;
2264
2265 bacpy(&cp.bdaddr, bdaddr);
2266 cp.passkey = passkey;
2267 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
2268 } else
2269 err = hci_send_cmd(hdev, hci_op, sizeof(*bdaddr), bdaddr);
2270
Johan Hedberga664b5b2011-02-19 12:06:02 -03002271 if (err < 0)
2272 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002273
Brian Gix0df4c182011-11-16 13:53:13 -08002274done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002275 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002276 hci_dev_put(hdev);
2277
2278 return err;
2279}
2280
Brian Gix0df4c182011-11-16 13:53:13 -08002281static int user_confirm_reply(struct sock *sk, u16 index, void *data, u16 len)
2282{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002283 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002284
2285 BT_DBG("");
2286
2287 if (len != sizeof(*cp))
2288 return cmd_status(sk, index, MGMT_OP_USER_CONFIRM_REPLY,
2289 MGMT_STATUS_INVALID_PARAMS);
2290
Johan Hedberg272d90d2012-02-09 15:26:12 +02002291 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
2292 MGMT_OP_USER_CONFIRM_REPLY,
2293 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002294}
2295
2296static int user_confirm_neg_reply(struct sock *sk, u16 index, void *data,
2297 u16 len)
2298{
Johan Hedbergc9c26592011-12-15 00:47:41 +02002299 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002300
2301 BT_DBG("");
2302
2303 if (len != sizeof(*cp))
2304 return cmd_status(sk, index, MGMT_OP_USER_CONFIRM_NEG_REPLY,
2305 MGMT_STATUS_INVALID_PARAMS);
2306
Johan Hedberg272d90d2012-02-09 15:26:12 +02002307 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
2308 MGMT_OP_USER_CONFIRM_NEG_REPLY,
2309 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002310}
2311
Brian Gix604086b2011-11-23 08:28:33 -08002312static int user_passkey_reply(struct sock *sk, u16 index, void *data, u16 len)
2313{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002314 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002315
2316 BT_DBG("");
2317
2318 if (len != sizeof(*cp))
2319 return cmd_status(sk, index, MGMT_OP_USER_PASSKEY_REPLY,
2320 EINVAL);
2321
Johan Hedberg272d90d2012-02-09 15:26:12 +02002322 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
2323 MGMT_OP_USER_PASSKEY_REPLY,
2324 HCI_OP_USER_PASSKEY_REPLY,
2325 cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08002326}
2327
2328static int user_passkey_neg_reply(struct sock *sk, u16 index, void *data,
2329 u16 len)
2330{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002331 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002332
2333 BT_DBG("");
2334
2335 if (len != sizeof(*cp))
2336 return cmd_status(sk, index, MGMT_OP_USER_PASSKEY_NEG_REPLY,
2337 EINVAL);
2338
Johan Hedberg272d90d2012-02-09 15:26:12 +02002339 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
2340 MGMT_OP_USER_PASSKEY_NEG_REPLY,
2341 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08002342}
2343
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002344static int set_local_name(struct sock *sk, u16 index, void *data,
Johan Hedbergb312b1612011-03-16 14:29:37 +02002345 u16 len)
2346{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002347 struct mgmt_cp_set_local_name *mgmt_cp = data;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002348 struct hci_cp_write_local_name hci_cp;
2349 struct hci_dev *hdev;
2350 struct pending_cmd *cmd;
2351 int err;
2352
2353 BT_DBG("");
2354
2355 if (len != sizeof(*mgmt_cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02002356 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME,
2357 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002358
2359 hdev = hci_dev_get(index);
2360 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002361 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME,
2362 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002363
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002364 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002365
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002366 memcpy(hdev->short_name, mgmt_cp->short_name,
2367 sizeof(hdev->short_name));
2368
Johan Hedbergb5235a62012-02-21 14:32:24 +02002369 if (!hdev_is_powered(hdev)) {
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002370 memcpy(hdev->dev_name, mgmt_cp->name, sizeof(hdev->dev_name));
2371
2372 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
2373 data, len);
2374 if (err < 0)
2375 goto failed;
2376
2377 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data, len,
2378 sk);
2379
Johan Hedbergb5235a62012-02-21 14:32:24 +02002380 goto failed;
2381 }
2382
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002383 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002384 if (!cmd) {
2385 err = -ENOMEM;
2386 goto failed;
2387 }
2388
2389 memcpy(hci_cp.name, mgmt_cp->name, sizeof(hci_cp.name));
2390 err = hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(hci_cp),
2391 &hci_cp);
2392 if (err < 0)
2393 mgmt_pending_remove(cmd);
2394
2395failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002396 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002397 hci_dev_put(hdev);
2398
2399 return err;
2400}
2401
Szymon Jancc35938b2011-03-22 13:12:21 +01002402static int read_local_oob_data(struct sock *sk, u16 index)
2403{
2404 struct hci_dev *hdev;
2405 struct pending_cmd *cmd;
2406 int err;
2407
2408 BT_DBG("hci%u", index);
2409
2410 hdev = hci_dev_get(index);
2411 if (!hdev)
2412 return cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002413 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancc35938b2011-03-22 13:12:21 +01002414
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002415 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002416
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002417 if (!hdev_is_powered(hdev)) {
Szymon Jancc35938b2011-03-22 13:12:21 +01002418 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002419 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002420 goto unlock;
2421 }
2422
2423 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
2424 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002425 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002426 goto unlock;
2427 }
2428
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002429 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02002430 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2431 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01002432 goto unlock;
2433 }
2434
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002435 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01002436 if (!cmd) {
2437 err = -ENOMEM;
2438 goto unlock;
2439 }
2440
2441 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
2442 if (err < 0)
2443 mgmt_pending_remove(cmd);
2444
2445unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002446 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002447 hci_dev_put(hdev);
2448
2449 return err;
2450}
2451
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002452static int add_remote_oob_data(struct sock *sk, u16 index, void *data,
2453 u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002454{
2455 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002456 struct mgmt_cp_add_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002457 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002458 int err;
2459
2460 BT_DBG("hci%u ", index);
2461
2462 if (len != sizeof(*cp))
2463 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002464 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01002465
2466 hdev = hci_dev_get(index);
2467 if (!hdev)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002468 return cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
2469 MGMT_STATUS_INVALID_PARAMS,
2470 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002471
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002472 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002473
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002474 if (!hdev_is_powered(hdev)) {
2475 err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
2476 MGMT_STATUS_NOT_POWERED,
2477 &cp->addr, sizeof(cp->addr));
2478 goto unlock;
2479 }
2480
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002481 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, cp->hash,
Szymon Janc2763eda2011-03-22 13:12:22 +01002482 cp->randomizer);
2483 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002484 status = MGMT_STATUS_FAILED;
Szymon Janc2763eda2011-03-22 13:12:22 +01002485 else
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002486 status = 0;
2487
2488 err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, status,
2489 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002490
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002491unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002492 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002493 hci_dev_put(hdev);
2494
2495 return err;
2496}
2497
2498static int remove_remote_oob_data(struct sock *sk, u16 index,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002499 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002500{
2501 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002502 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002503 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002504 int err;
2505
2506 BT_DBG("hci%u ", index);
2507
2508 if (len != sizeof(*cp))
2509 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002510 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01002511
2512 hdev = hci_dev_get(index);
2513 if (!hdev)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002514 return cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2515 MGMT_STATUS_INVALID_PARAMS,
2516 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002517
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002518 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002519
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002520 if (!hdev_is_powered(hdev)) {
2521 err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2522 MGMT_STATUS_NOT_POWERED,
2523 &cp->addr, sizeof(cp->addr));
2524 goto unlock;
2525 }
2526
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002527 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr);
Szymon Janc2763eda2011-03-22 13:12:22 +01002528 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002529 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01002530 else
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002531 status = 0;
2532
2533 err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA, status,
2534 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002535
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002536unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002537 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002538 hci_dev_put(hdev);
2539
2540 return err;
2541}
2542
Andre Guedes5e0452c2012-02-17 20:39:38 -03002543static int discovery(struct hci_dev *hdev)
2544{
2545 int err;
2546
2547 if (lmp_host_le_capable(hdev)) {
2548 if (lmp_bredr_capable(hdev)) {
2549 err = hci_le_scan(hdev, LE_SCAN_TYPE,
2550 LE_SCAN_INT, LE_SCAN_WIN,
2551 LE_SCAN_TIMEOUT_BREDR_LE);
2552 } else {
2553 hdev->discovery.type = DISCOV_TYPE_LE;
2554 err = hci_le_scan(hdev, LE_SCAN_TYPE,
2555 LE_SCAN_INT, LE_SCAN_WIN,
2556 LE_SCAN_TIMEOUT_LE_ONLY);
2557 }
2558 } else {
2559 hdev->discovery.type = DISCOV_TYPE_BREDR;
2560 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
2561 }
2562
2563 return err;
2564}
2565
2566int mgmt_interleaved_discovery(struct hci_dev *hdev)
2567{
2568 int err;
2569
2570 BT_DBG("%s", hdev->name);
2571
2572 hci_dev_lock(hdev);
2573
2574 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR_LE);
2575 if (err < 0)
2576 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2577
2578 hci_dev_unlock(hdev);
2579
2580 return err;
2581}
2582
Johan Hedberg450dfda2011-11-12 11:58:22 +02002583static int start_discovery(struct sock *sk, u16 index,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002584 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002585{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002586 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002587 struct pending_cmd *cmd;
2588 struct hci_dev *hdev;
2589 int err;
2590
2591 BT_DBG("hci%u", index);
2592
Johan Hedberg450dfda2011-11-12 11:58:22 +02002593 if (len != sizeof(*cp))
2594 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2595 MGMT_STATUS_INVALID_PARAMS);
2596
Johan Hedberg14a53662011-04-27 10:29:56 -04002597 hdev = hci_dev_get(index);
2598 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002599 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2600 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg14a53662011-04-27 10:29:56 -04002601
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002602 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002603
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002604 if (!hdev_is_powered(hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02002605 err = cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2606 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02002607 goto failed;
2608 }
2609
Johan Hedbergff9ef572012-01-04 14:23:45 +02002610 if (hdev->discovery.state != DISCOVERY_STOPPED) {
2611 err = cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2612 MGMT_STATUS_BUSY);
2613 goto failed;
2614 }
2615
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002616 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002617 if (!cmd) {
2618 err = -ENOMEM;
2619 goto failed;
2620 }
2621
Andre Guedes4aab14e2012-02-17 20:39:36 -03002622 hdev->discovery.type = cp->type;
2623
2624 switch (hdev->discovery.type) {
Andre Guedesf39799f2012-02-17 20:39:35 -03002625 case DISCOV_TYPE_BREDR:
Andre Guedes3fd24152012-02-03 17:48:01 -03002626 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
Andre Guedesf39799f2012-02-17 20:39:35 -03002627 break;
2628
2629 case DISCOV_TYPE_LE:
Andre Guedes3fd24152012-02-03 17:48:01 -03002630 err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT,
2631 LE_SCAN_WIN, LE_SCAN_TIMEOUT_LE_ONLY);
Andre Guedesf39799f2012-02-17 20:39:35 -03002632 break;
2633
Andre Guedes5e0452c2012-02-17 20:39:38 -03002634 case DISCOV_TYPE_INTERLEAVED:
2635 err = discovery(hdev);
2636 break;
2637
Andre Guedesf39799f2012-02-17 20:39:35 -03002638 default:
Andre Guedes3fd24152012-02-03 17:48:01 -03002639 err = -EINVAL;
Andre Guedesf39799f2012-02-17 20:39:35 -03002640 }
Andre Guedes3fd24152012-02-03 17:48:01 -03002641
Johan Hedberg14a53662011-04-27 10:29:56 -04002642 if (err < 0)
2643 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002644 else
2645 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002646
2647failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002648 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002649 hci_dev_put(hdev);
2650
2651 return err;
2652}
2653
Johan Hedbergd9306502012-02-20 23:25:18 +02002654static int stop_discovery(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002655{
Johan Hedbergd9306502012-02-20 23:25:18 +02002656 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002657 struct hci_dev *hdev;
2658 struct pending_cmd *cmd;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002659 struct hci_cp_remote_name_req_cancel cp;
2660 struct inquiry_entry *e;
Johan Hedberg14a53662011-04-27 10:29:56 -04002661 int err;
2662
2663 BT_DBG("hci%u", index);
2664
Johan Hedbergd9306502012-02-20 23:25:18 +02002665 if (len != sizeof(*mgmt_cp))
2666 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY,
2667 MGMT_STATUS_INVALID_PARAMS);
2668
Johan Hedberg14a53662011-04-27 10:29:56 -04002669 hdev = hci_dev_get(index);
2670 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002671 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY,
2672 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg14a53662011-04-27 10:29:56 -04002673
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002674 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002675
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002676 if (!hci_discovery_active(hdev)) {
Johan Hedbergd9306502012-02-20 23:25:18 +02002677 err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY,
2678 MGMT_STATUS_REJECTED,
2679 &mgmt_cp->type, sizeof(mgmt_cp->type));
2680 goto unlock;
2681 }
2682
2683 if (hdev->discovery.type != mgmt_cp->type) {
2684 err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY,
2685 MGMT_STATUS_INVALID_PARAMS,
2686 &mgmt_cp->type, sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002687 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02002688 }
2689
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002690 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002691 if (!cmd) {
2692 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002693 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04002694 }
2695
Andre Guedes343f9352012-02-17 20:39:37 -03002696 if (hdev->discovery.state == DISCOVERY_FINDING) {
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002697 err = hci_cancel_inquiry(hdev);
2698 if (err < 0)
2699 mgmt_pending_remove(cmd);
2700 else
2701 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
2702 goto unlock;
2703 }
2704
2705 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY, NAME_PENDING);
2706 if (!e) {
2707 mgmt_pending_remove(cmd);
Johan Hedbergaee9b212012-02-18 15:07:59 +02002708 err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY, 0,
Johan Hedbergd9306502012-02-20 23:25:18 +02002709 &mgmt_cp->type, sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002710 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2711 goto unlock;
2712 }
2713
2714 bacpy(&cp.bdaddr, &e->data.bdaddr);
2715 err = hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ_CANCEL,
2716 sizeof(cp), &cp);
Johan Hedberg14a53662011-04-27 10:29:56 -04002717 if (err < 0)
2718 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002719 else
2720 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002721
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002722unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002723 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002724 hci_dev_put(hdev);
2725
2726 return err;
2727}
2728
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002729static int confirm_name(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02002730{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002731 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002732 struct inquiry_entry *e;
2733 struct hci_dev *hdev;
2734 int err;
2735
2736 BT_DBG("hci%u", index);
2737
2738 if (len != sizeof(*cp))
2739 return cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2740 MGMT_STATUS_INVALID_PARAMS);
2741
2742 hdev = hci_dev_get(index);
2743 if (!hdev)
2744 return cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2745 MGMT_STATUS_INVALID_PARAMS);
2746
2747 hci_dev_lock(hdev);
2748
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002749 if (!hci_discovery_active(hdev)) {
2750 err = cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2751 MGMT_STATUS_FAILED);
2752 goto failed;
2753 }
2754
Johan Hedberga198e7b2012-02-17 14:27:06 +02002755 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002756 if (!e) {
Marcel Holtmanne5f0e152012-02-22 11:59:01 +01002757 err = cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
Johan Hedberg561aafb2012-01-04 13:31:59 +02002758 MGMT_STATUS_INVALID_PARAMS);
2759 goto failed;
2760 }
2761
2762 if (cp->name_known) {
2763 e->name_state = NAME_KNOWN;
2764 list_del(&e->list);
2765 } else {
2766 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e202012-01-09 00:53:02 +02002767 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002768 }
2769
2770 err = 0;
2771
2772failed:
2773 hci_dev_unlock(hdev);
2774
2775 return err;
2776}
2777
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002778static int block_device(struct sock *sk, u16 index, void *data, u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002779{
2780 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002781 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002782 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03002783 int err;
2784
2785 BT_DBG("hci%u", index);
2786
Antti Julku7fbec222011-06-15 12:01:15 +03002787 if (len != sizeof(*cp))
2788 return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002789 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002790
2791 hdev = hci_dev_get(index);
2792 if (!hdev)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002793 return cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE,
2794 MGMT_STATUS_INVALID_PARAMS,
2795 &cp->addr, sizeof(cp->addr));
Antti Julku7fbec222011-06-15 12:01:15 +03002796
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002797 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002798
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002799 err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002800 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002801 status = MGMT_STATUS_FAILED;
Antti Julku7fbec222011-06-15 12:01:15 +03002802 else
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002803 status = 0;
2804
2805 err = cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE, status,
2806 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03002807
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002808 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002809 hci_dev_put(hdev);
2810
2811 return err;
2812}
2813
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002814static int unblock_device(struct sock *sk, u16 index, void *data, u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002815{
2816 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002817 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002818 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03002819 int err;
2820
2821 BT_DBG("hci%u", index);
2822
Antti Julku7fbec222011-06-15 12:01:15 +03002823 if (len != sizeof(*cp))
2824 return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002825 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002826
2827 hdev = hci_dev_get(index);
2828 if (!hdev)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002829 return cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE,
2830 MGMT_STATUS_INVALID_PARAMS,
2831 &cp->addr, sizeof(cp->addr));
Antti Julku7fbec222011-06-15 12:01:15 +03002832
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002833 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002834
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002835 err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002836 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002837 status = MGMT_STATUS_INVALID_PARAMS;
Antti Julku7fbec222011-06-15 12:01:15 +03002838 else
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002839 status = 0;
2840
2841 err = cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE, status,
2842 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03002843
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002844 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002845 hci_dev_put(hdev);
2846
2847 return err;
2848}
2849
Antti Julkuf6422ec2011-06-22 13:11:56 +03002850static int set_fast_connectable(struct sock *sk, u16 index,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002851 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03002852{
2853 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002854 struct mgmt_mode *cp = data;
Antti Julkuf6422ec2011-06-22 13:11:56 +03002855 struct hci_cp_write_page_scan_activity acp;
2856 u8 type;
2857 int err;
2858
2859 BT_DBG("hci%u", index);
2860
2861 if (len != sizeof(*cp))
2862 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002863 MGMT_STATUS_INVALID_PARAMS);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002864
2865 hdev = hci_dev_get(index);
2866 if (!hdev)
2867 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002868 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg5400c042012-02-21 16:40:33 +02002869 if (!hdev_is_powered(hdev))
2870 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
2871 MGMT_STATUS_NOT_POWERED);
2872
2873 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
2874 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
2875 MGMT_STATUS_REJECTED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002876
2877 hci_dev_lock(hdev);
2878
Johan Hedbergf7c68692011-12-15 00:47:36 +02002879 if (cp->val) {
Antti Julkuf6422ec2011-06-22 13:11:56 +03002880 type = PAGE_SCAN_TYPE_INTERLACED;
2881 acp.interval = 0x0024; /* 22.5 msec page scan interval */
2882 } else {
2883 type = PAGE_SCAN_TYPE_STANDARD; /* default */
2884 acp.interval = 0x0800; /* default 1.28 sec page scan */
2885 }
2886
2887 acp.window = 0x0012; /* default 11.25 msec page scan window */
2888
2889 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
2890 sizeof(acp), &acp);
2891 if (err < 0) {
2892 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002893 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002894 goto done;
2895 }
2896
2897 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
2898 if (err < 0) {
2899 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002900 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002901 goto done;
2902 }
2903
Johan Hedbergaee9b212012-02-18 15:07:59 +02002904 err = cmd_complete(sk, index, MGMT_OP_SET_FAST_CONNECTABLE, 0,
2905 NULL, 0);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002906done:
2907 hci_dev_unlock(hdev);
2908 hci_dev_put(hdev);
2909
2910 return err;
2911}
2912
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002913static int load_long_term_keys(struct sock *sk, u16 index,
2914 void *cp_data, u16 len)
2915{
2916 struct hci_dev *hdev;
2917 struct mgmt_cp_load_long_term_keys *cp = cp_data;
2918 u16 key_count, expected_len;
2919 int i;
2920
2921 if (len < sizeof(*cp))
2922 return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS,
2923 EINVAL);
2924
2925 key_count = get_unaligned_le16(&cp->key_count);
2926
2927 expected_len = sizeof(*cp) + key_count *
2928 sizeof(struct mgmt_ltk_info);
2929 if (expected_len != len) {
2930 BT_ERR("load_keys: expected %u bytes, got %u bytes",
2931 len, expected_len);
2932 return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS,
2933 EINVAL);
2934 }
2935
2936 hdev = hci_dev_get(index);
2937 if (!hdev)
2938 return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS,
2939 ENODEV);
2940
2941 BT_DBG("hci%u key_count %u", index, key_count);
2942
2943 hci_dev_lock(hdev);
2944
2945 hci_smp_ltks_clear(hdev);
2946
2947 for (i = 0; i < key_count; i++) {
2948 struct mgmt_ltk_info *key = &cp->keys[i];
2949 u8 type;
2950
2951 if (key->master)
2952 type = HCI_SMP_LTK;
2953 else
2954 type = HCI_SMP_LTK_SLAVE;
2955
2956 hci_add_ltk(hdev, &key->addr.bdaddr, key->addr.type,
2957 type, 0, key->authenticated, key->val,
2958 key->enc_size, key->ediv, key->rand);
2959 }
2960
2961 hci_dev_unlock(hdev);
2962 hci_dev_put(hdev);
2963
2964 return 0;
2965}
2966
Johan Hedberg03811012010-12-08 00:21:06 +02002967int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
2968{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002969 void *buf;
2970 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02002971 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002972 u16 opcode, index, len;
Johan Hedberg03811012010-12-08 00:21:06 +02002973 int err;
2974
2975 BT_DBG("got %zu bytes", msglen);
2976
2977 if (msglen < sizeof(*hdr))
2978 return -EINVAL;
2979
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03002980 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02002981 if (!buf)
2982 return -ENOMEM;
2983
2984 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
2985 err = -EFAULT;
2986 goto done;
2987 }
2988
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002989 hdr = buf;
Johan Hedberg03811012010-12-08 00:21:06 +02002990 opcode = get_unaligned_le16(&hdr->opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002991 index = get_unaligned_le16(&hdr->index);
Johan Hedberg03811012010-12-08 00:21:06 +02002992 len = get_unaligned_le16(&hdr->len);
2993
2994 if (len != msglen - sizeof(*hdr)) {
2995 err = -EINVAL;
2996 goto done;
2997 }
2998
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002999 cp = buf + sizeof(*hdr);
3000
Johan Hedberg03811012010-12-08 00:21:06 +02003001 switch (opcode) {
Johan Hedberg02d98122010-12-13 21:07:04 +02003002 case MGMT_OP_READ_VERSION:
3003 err = read_version(sk);
3004 break;
Johan Hedberge70bb2e2012-02-13 16:59:33 +02003005 case MGMT_OP_READ_COMMANDS:
3006 err = read_commands(sk);
3007 break;
Johan Hedbergfaba42e2010-12-13 21:07:05 +02003008 case MGMT_OP_READ_INDEX_LIST:
3009 err = read_index_list(sk);
3010 break;
Johan Hedbergf7b64e62010-12-13 21:07:06 +02003011 case MGMT_OP_READ_INFO:
Szymon Janc4e51eae2011-02-25 19:05:48 +01003012 err = read_controller_info(sk, index);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02003013 break;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02003014 case MGMT_OP_SET_POWERED:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003015 err = set_powered(sk, index, cp, len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02003016 break;
Johan Hedberg73f22f62010-12-29 16:00:25 +02003017 case MGMT_OP_SET_DISCOVERABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003018 err = set_discoverable(sk, index, cp, len);
Johan Hedberg73f22f62010-12-29 16:00:25 +02003019 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003020 case MGMT_OP_SET_CONNECTABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003021 err = set_connectable(sk, index, cp, len);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003022 break;
Johan Hedbergf7c68692011-12-15 00:47:36 +02003023 case MGMT_OP_SET_FAST_CONNECTABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003024 err = set_fast_connectable(sk, index, cp, len);
Johan Hedbergf7c68692011-12-15 00:47:36 +02003025 break;
Johan Hedbergc542a062011-01-26 13:11:03 +02003026 case MGMT_OP_SET_PAIRABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003027 err = set_pairable(sk, index, cp, len);
Johan Hedbergc542a062011-01-26 13:11:03 +02003028 break;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003029 case MGMT_OP_SET_LINK_SECURITY:
3030 err = set_link_security(sk, index, cp, len);
3031 break;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003032 case MGMT_OP_SET_SSP:
3033 err = set_ssp(sk, index, cp, len);
3034 break;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02003035 case MGMT_OP_SET_HS:
3036 err = set_hs(sk, index, cp, len);
3037 break;
Johan Hedberg06199cf2012-02-22 16:37:11 +02003038 case MGMT_OP_SET_LE:
3039 err = set_le(sk, index, cp, len);
3040 break;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02003041 case MGMT_OP_ADD_UUID:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003042 err = add_uuid(sk, index, cp, len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02003043 break;
3044 case MGMT_OP_REMOVE_UUID:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003045 err = remove_uuid(sk, index, cp, len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02003046 break;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02003047 case MGMT_OP_SET_DEV_CLASS:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003048 err = set_dev_class(sk, index, cp, len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02003049 break;
Johan Hedberg86742e12011-11-07 23:13:38 +02003050 case MGMT_OP_LOAD_LINK_KEYS:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003051 err = load_link_keys(sk, index, cp, len);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02003052 break;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003053 case MGMT_OP_DISCONNECT:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003054 err = disconnect(sk, index, cp, len);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003055 break;
Johan Hedberg2784eb42011-01-21 13:56:35 +02003056 case MGMT_OP_GET_CONNECTIONS:
Szymon Janc8ce62842011-03-01 16:55:32 +01003057 err = get_connections(sk, index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02003058 break;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003059 case MGMT_OP_PIN_CODE_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003060 err = pin_code_reply(sk, index, cp, len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003061 break;
3062 case MGMT_OP_PIN_CODE_NEG_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003063 err = pin_code_neg_reply(sk, index, cp, len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003064 break;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02003065 case MGMT_OP_SET_IO_CAPABILITY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003066 err = set_io_capability(sk, index, cp, len);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02003067 break;
Johan Hedberge9a416b2011-02-19 12:05:56 -03003068 case MGMT_OP_PAIR_DEVICE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003069 err = pair_device(sk, index, cp, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03003070 break;
Johan Hedberg28424702012-02-02 04:02:29 +02003071 case MGMT_OP_CANCEL_PAIR_DEVICE:
3072 err = cancel_pair_device(sk, index, buf + sizeof(*hdr), len);
3073 break;
Johan Hedberg124f6e32012-02-09 13:50:12 +02003074 case MGMT_OP_UNPAIR_DEVICE:
3075 err = unpair_device(sk, index, cp, len);
3076 break;
Johan Hedberga5c29682011-02-19 12:05:57 -03003077 case MGMT_OP_USER_CONFIRM_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003078 err = user_confirm_reply(sk, index, cp, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03003079 break;
3080 case MGMT_OP_USER_CONFIRM_NEG_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003081 err = user_confirm_neg_reply(sk, index, cp, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03003082 break;
Brian Gix604086b2011-11-23 08:28:33 -08003083 case MGMT_OP_USER_PASSKEY_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003084 err = user_passkey_reply(sk, index, cp, len);
Brian Gix604086b2011-11-23 08:28:33 -08003085 break;
3086 case MGMT_OP_USER_PASSKEY_NEG_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003087 err = user_passkey_neg_reply(sk, index, cp, len);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02003088 break;
Johan Hedbergb312b1612011-03-16 14:29:37 +02003089 case MGMT_OP_SET_LOCAL_NAME:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003090 err = set_local_name(sk, index, cp, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003091 break;
Szymon Jancc35938b2011-03-22 13:12:21 +01003092 case MGMT_OP_READ_LOCAL_OOB_DATA:
3093 err = read_local_oob_data(sk, index);
3094 break;
Szymon Janc2763eda2011-03-22 13:12:22 +01003095 case MGMT_OP_ADD_REMOTE_OOB_DATA:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003096 err = add_remote_oob_data(sk, index, cp, len);
Szymon Janc2763eda2011-03-22 13:12:22 +01003097 break;
3098 case MGMT_OP_REMOVE_REMOTE_OOB_DATA:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003099 err = remove_remote_oob_data(sk, index, cp, len);
Szymon Janc2763eda2011-03-22 13:12:22 +01003100 break;
Johan Hedberg14a53662011-04-27 10:29:56 -04003101 case MGMT_OP_START_DISCOVERY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003102 err = start_discovery(sk, index, cp, len);
Johan Hedberg14a53662011-04-27 10:29:56 -04003103 break;
3104 case MGMT_OP_STOP_DISCOVERY:
Johan Hedbergd9306502012-02-20 23:25:18 +02003105 err = stop_discovery(sk, index, cp, len);
Johan Hedberg14a53662011-04-27 10:29:56 -04003106 break;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003107 case MGMT_OP_CONFIRM_NAME:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003108 err = confirm_name(sk, index, cp, len);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003109 break;
Antti Julku7fbec222011-06-15 12:01:15 +03003110 case MGMT_OP_BLOCK_DEVICE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003111 err = block_device(sk, index, cp, len);
Antti Julku7fbec222011-06-15 12:01:15 +03003112 break;
3113 case MGMT_OP_UNBLOCK_DEVICE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003114 err = unblock_device(sk, index, cp, len);
Antti Julku7fbec222011-06-15 12:01:15 +03003115 break;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003116 case MGMT_OP_LOAD_LONG_TERM_KEYS:
3117 err = load_long_term_keys(sk, index, cp, len);
3118 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003119 default:
Johan Hedberg72a734e2010-12-30 00:38:22 +02003120 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02003121 err = cmd_status(sk, index, opcode,
3122 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003123 break;
3124 }
Johan Hedberg72a734e2010-12-30 00:38:22 +02003125
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003126 if (err < 0)
Johan Hedberg72a734e2010-12-30 00:38:22 +02003127 goto done;
3128
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003129 err = msglen;
3130
3131done:
3132 kfree(buf);
3133 return err;
3134}
3135
Johan Hedbergb24752f2011-11-03 14:40:33 +02003136static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
3137{
3138 u8 *status = data;
3139
3140 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
3141 mgmt_pending_remove(cmd);
3142}
3143
Johan Hedberg744cf192011-11-08 20:40:14 +02003144int mgmt_index_added(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +02003145{
Johan Hedberg744cf192011-11-08 20:40:14 +02003146 return mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02003147}
3148
Johan Hedberg744cf192011-11-08 20:40:14 +02003149int mgmt_index_removed(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +02003150{
Johan Hedbergb24752f2011-11-03 14:40:33 +02003151 u8 status = ENODEV;
3152
Johan Hedberg744cf192011-11-08 20:40:14 +02003153 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02003154
Johan Hedberg744cf192011-11-08 20:40:14 +02003155 return mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02003156}
3157
3158struct cmd_lookup {
Johan Hedberg03811012010-12-08 00:21:06 +02003159 struct sock *sk;
Johan Hedberg69ab39e2011-12-15 00:47:35 +02003160 struct hci_dev *hdev;
Johan Hedberg90e70452012-02-23 23:09:40 +02003161 u8 mgmt_status;
Johan Hedberg03811012010-12-08 00:21:06 +02003162};
3163
Johan Hedberg69ab39e2011-12-15 00:47:35 +02003164static void settings_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberg03811012010-12-08 00:21:06 +02003165{
Johan Hedberg03811012010-12-08 00:21:06 +02003166 struct cmd_lookup *match = data;
3167
Johan Hedberg69ab39e2011-12-15 00:47:35 +02003168 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02003169
3170 list_del(&cmd->list);
3171
3172 if (match->sk == NULL) {
3173 match->sk = cmd->sk;
3174 sock_hold(match->sk);
3175 }
3176
3177 mgmt_pending_free(cmd);
3178}
3179
Johan Hedberg744cf192011-11-08 20:40:14 +02003180int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg03811012010-12-08 00:21:06 +02003181{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02003182 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003183 int err;
Johan Hedberg03811012010-12-08 00:21:06 +02003184
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003185 if (!test_bit(HCI_MGMT, &hdev->dev_flags))
3186 return 0;
3187
Johan Hedberg69ab39e2011-12-15 00:47:35 +02003188 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
Johan Hedberg03811012010-12-08 00:21:06 +02003189
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003190 if (powered) {
3191 u8 scan = 0;
3192
3193 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3194 scan |= SCAN_PAGE;
3195 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3196 scan |= SCAN_INQUIRY;
3197
3198 if (scan)
3199 hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
Johan Hedberg504c8dc2012-02-23 13:30:41 +02003200
3201 update_class(hdev);
3202 update_eir(hdev);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003203 } else {
Johan Hedbergb24752f2011-11-03 14:40:33 +02003204 u8 status = ENETDOWN;
Johan Hedberg744cf192011-11-08 20:40:14 +02003205 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02003206 }
3207
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003208 err = new_settings(hdev, match.sk);
Johan Hedberg03811012010-12-08 00:21:06 +02003209
3210 if (match.sk)
3211 sock_put(match.sk);
3212
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003213 return err;
Johan Hedberg03811012010-12-08 00:21:06 +02003214}
3215
Johan Hedberg744cf192011-11-08 20:40:14 +02003216int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg03811012010-12-08 00:21:06 +02003217{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02003218 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003219 bool changed = false;
3220 int err = 0;
Johan Hedberg03811012010-12-08 00:21:06 +02003221
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003222 if (discoverable) {
3223 if (!test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3224 changed = true;
3225 } else {
3226 if (test_and_clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3227 changed = true;
3228 }
Johan Hedberg03811012010-12-08 00:21:06 +02003229
Johan Hedberged9b5f22012-02-21 20:47:06 +02003230 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp,
3231 &match);
3232
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003233 if (changed)
3234 err = new_settings(hdev, match.sk);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003235
Johan Hedberg03811012010-12-08 00:21:06 +02003236 if (match.sk)
3237 sock_put(match.sk);
3238
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003239 return err;
Johan Hedberg03811012010-12-08 00:21:06 +02003240}
3241
Johan Hedberg744cf192011-11-08 20:40:14 +02003242int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg03811012010-12-08 00:21:06 +02003243{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02003244 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003245 bool changed = false;
3246 int err = 0;
Johan Hedberg03811012010-12-08 00:21:06 +02003247
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003248 if (connectable) {
3249 if (!test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3250 changed = true;
3251 } else {
3252 if (test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3253 changed = true;
3254 }
Johan Hedberg03811012010-12-08 00:21:06 +02003255
Johan Hedberged9b5f22012-02-21 20:47:06 +02003256 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev, settings_rsp,
3257 &match);
3258
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003259 if (changed)
3260 err = new_settings(hdev, match.sk);
Johan Hedberg03811012010-12-08 00:21:06 +02003261
3262 if (match.sk)
3263 sock_put(match.sk);
3264
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003265 return err;
Johan Hedberg03811012010-12-08 00:21:06 +02003266}
3267
Johan Hedberg744cf192011-11-08 20:40:14 +02003268int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003269{
Johan Hedbergca69b792011-11-11 18:10:00 +02003270 u8 mgmt_err = mgmt_status(status);
3271
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003272 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02003273 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Johan Hedbergca69b792011-11-11 18:10:00 +02003274 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003275
3276 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02003277 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Johan Hedbergca69b792011-11-11 18:10:00 +02003278 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003279
3280 return 0;
3281}
3282
Johan Hedberg744cf192011-11-08 20:40:14 +02003283int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
3284 u8 persistent)
Johan Hedberg03811012010-12-08 00:21:06 +02003285{
Johan Hedberg86742e12011-11-07 23:13:38 +02003286 struct mgmt_ev_new_link_key ev;
Johan Hedberg03811012010-12-08 00:21:06 +02003287
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003288 memset(&ev, 0, sizeof(ev));
Johan Hedberg03811012010-12-08 00:21:06 +02003289
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003290 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02003291 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
3292 ev.key.addr.type = MGMT_ADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003293 ev.key.type = key->type;
3294 memcpy(ev.key.val, key->val, 16);
3295 ev.key.pin_len = key->pin_len;
Johan Hedberg03811012010-12-08 00:21:06 +02003296
Johan Hedberg744cf192011-11-08 20:40:14 +02003297 return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02003298}
Johan Hedbergf7520542011-01-20 12:34:39 +02003299
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003300int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
3301{
3302 struct mgmt_ev_new_long_term_key ev;
3303
3304 memset(&ev, 0, sizeof(ev));
3305
3306 ev.store_hint = persistent;
3307 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
3308 ev.key.addr.type = key->bdaddr_type;
3309 ev.key.authenticated = key->authenticated;
3310 ev.key.enc_size = key->enc_size;
3311 ev.key.ediv = key->ediv;
3312
3313 if (key->type == HCI_SMP_LTK)
3314 ev.key.master = 1;
3315
3316 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
3317 memcpy(ev.key.val, key->val, sizeof(key->val));
3318
3319 return mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev,
3320 &ev, sizeof(ev), NULL);
3321}
3322
Johan Hedbergafc747a2012-01-15 18:11:07 +02003323int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Johan Hedberg08c79b62012-02-23 22:31:51 +02003324 u8 addr_type, u32 flags, u8 *name,
3325 u8 name_len, u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02003326{
Johan Hedbergb644ba32012-01-17 21:48:47 +02003327 char buf[512];
3328 struct mgmt_ev_device_connected *ev = (void *) buf;
3329 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02003330
Johan Hedbergb644ba32012-01-17 21:48:47 +02003331 bacpy(&ev->addr.bdaddr, bdaddr);
3332 ev->addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02003333
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02003334 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02003335
Johan Hedbergb644ba32012-01-17 21:48:47 +02003336 if (name_len > 0)
3337 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
3338 name, name_len);
3339
3340 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
3341 eir_len = eir_append_data(&ev->eir[eir_len], eir_len,
3342 EIR_CLASS_OF_DEV, dev_class, 3);
3343
3344 put_unaligned_le16(eir_len, &ev->eir_len);
3345
3346 return mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
3347 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02003348}
3349
Johan Hedberg8962ee72011-01-20 12:40:27 +02003350static void disconnect_rsp(struct pending_cmd *cmd, void *data)
3351{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01003352 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003353 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02003354 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003355
Johan Hedberg88c3df12012-02-09 14:27:38 +02003356 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3357 rp.addr.type = cp->addr.type;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003358
Johan Hedbergaee9b212012-02-18 15:07:59 +02003359 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, 0, &rp,
3360 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003361
3362 *sk = cmd->sk;
3363 sock_hold(*sk);
3364
Johan Hedberga664b5b2011-02-19 12:06:02 -03003365 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003366}
3367
Johan Hedberg124f6e32012-02-09 13:50:12 +02003368static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02003369{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003370 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02003371 struct mgmt_cp_unpair_device *cp = cmd->param;
3372 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02003373
3374 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02003375 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3376 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02003377
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003378 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
3379
Johan Hedbergaee9b212012-02-18 15:07:59 +02003380 cmd_complete(cmd->sk, cmd->index, cmd->opcode, 0, &rp, sizeof(rp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02003381
3382 mgmt_pending_remove(cmd);
3383}
3384
Johan Hedbergafc747a2012-01-15 18:11:07 +02003385int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
3386 u8 link_type, u8 addr_type)
Johan Hedbergf7520542011-01-20 12:34:39 +02003387{
Johan Hedberg4c659c32011-11-07 23:13:39 +02003388 struct mgmt_addr_info ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003389 struct sock *sk = NULL;
3390 int err;
3391
Johan Hedberg744cf192011-11-08 20:40:14 +02003392 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02003393
Johan Hedbergf7520542011-01-20 12:34:39 +02003394 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02003395 ev.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02003396
Johan Hedbergafc747a2012-01-15 18:11:07 +02003397 err = mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev),
3398 sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003399
3400 if (sk)
3401 sock_put(sk);
3402
Johan Hedberg124f6e32012-02-09 13:50:12 +02003403 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003404 hdev);
Johan Hedberga8a1d192011-11-10 15:54:38 +02003405
Johan Hedberg8962ee72011-01-20 12:40:27 +02003406 return err;
3407}
3408
Johan Hedberg88c3df12012-02-09 14:27:38 +02003409int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
3410 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02003411{
Johan Hedberg88c3df12012-02-09 14:27:38 +02003412 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003413 struct pending_cmd *cmd;
3414 int err;
3415
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003416 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003417 if (!cmd)
3418 return -ENOENT;
3419
Johan Hedberg88c3df12012-02-09 14:27:38 +02003420 bacpy(&rp.addr.bdaddr, bdaddr);
3421 rp.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02003422
Johan Hedberg88c3df12012-02-09 14:27:38 +02003423 err = cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
Johan Hedbergaee9b212012-02-18 15:07:59 +02003424 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003425
Johan Hedberga664b5b2011-02-19 12:06:02 -03003426 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003427
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003428 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
3429 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003430 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02003431}
Johan Hedberg17d5c042011-01-22 06:09:08 +02003432
Johan Hedberg48264f02011-11-09 13:58:58 +02003433int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
3434 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02003435{
3436 struct mgmt_ev_connect_failed ev;
3437
Johan Hedberg4c659c32011-11-07 23:13:39 +02003438 bacpy(&ev.addr.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02003439 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003440 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003441
Johan Hedberg744cf192011-11-08 20:40:14 +02003442 return mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003443}
Johan Hedberg980e1a52011-01-22 06:10:07 +02003444
Johan Hedberg744cf192011-11-08 20:40:14 +02003445int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003446{
3447 struct mgmt_ev_pin_code_request ev;
3448
Johan Hedbergd8457692012-02-17 14:24:57 +02003449 bacpy(&ev.addr.bdaddr, bdaddr);
3450 ev.addr.type = MGMT_ADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02003451 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003452
Johan Hedberg744cf192011-11-08 20:40:14 +02003453 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01003454 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003455}
3456
Johan Hedberg744cf192011-11-08 20:40:14 +02003457int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3458 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003459{
3460 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003461 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003462 int err;
3463
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003464 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003465 if (!cmd)
3466 return -ENOENT;
3467
Johan Hedbergd8457692012-02-17 14:24:57 +02003468 bacpy(&rp.addr.bdaddr, bdaddr);
3469 rp.addr.type = MGMT_ADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003470
Johan Hedbergaee9b212012-02-18 15:07:59 +02003471 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
3472 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003473
Johan Hedberga664b5b2011-02-19 12:06:02 -03003474 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003475
3476 return err;
3477}
3478
Johan Hedberg744cf192011-11-08 20:40:14 +02003479int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3480 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003481{
3482 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003483 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003484 int err;
3485
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003486 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003487 if (!cmd)
3488 return -ENOENT;
3489
Johan Hedbergd8457692012-02-17 14:24:57 +02003490 bacpy(&rp.addr.bdaddr, bdaddr);
3491 rp.addr.type = MGMT_ADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003492
Johan Hedbergaee9b212012-02-18 15:07:59 +02003493 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
3494 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003495
Johan Hedberga664b5b2011-02-19 12:06:02 -03003496 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003497
3498 return err;
3499}
Johan Hedberga5c29682011-02-19 12:05:57 -03003500
Johan Hedberg744cf192011-11-08 20:40:14 +02003501int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003502 u8 link_type, u8 addr_type, __le32 value,
3503 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03003504{
3505 struct mgmt_ev_user_confirm_request ev;
3506
Johan Hedberg744cf192011-11-08 20:40:14 +02003507 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03003508
Johan Hedberg272d90d2012-02-09 15:26:12 +02003509 bacpy(&ev.addr.bdaddr, bdaddr);
3510 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07003511 ev.confirm_hint = confirm_hint;
Johan Hedberga5c29682011-02-19 12:05:57 -03003512 put_unaligned_le32(value, &ev.value);
3513
Johan Hedberg744cf192011-11-08 20:40:14 +02003514 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01003515 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03003516}
3517
Johan Hedberg272d90d2012-02-09 15:26:12 +02003518int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
3519 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08003520{
3521 struct mgmt_ev_user_passkey_request ev;
3522
3523 BT_DBG("%s", hdev->name);
3524
Johan Hedberg272d90d2012-02-09 15:26:12 +02003525 bacpy(&ev.addr.bdaddr, bdaddr);
3526 ev.addr.type = link_to_mgmt(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08003527
3528 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
3529 NULL);
3530}
3531
Brian Gix0df4c182011-11-16 13:53:13 -08003532static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003533 u8 link_type, u8 addr_type, u8 status,
3534 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03003535{
3536 struct pending_cmd *cmd;
3537 struct mgmt_rp_user_confirm_reply rp;
3538 int err;
3539
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003540 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03003541 if (!cmd)
3542 return -ENOENT;
3543
Johan Hedberg272d90d2012-02-09 15:26:12 +02003544 bacpy(&rp.addr.bdaddr, bdaddr);
3545 rp.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergaee9b212012-02-18 15:07:59 +02003546 err = cmd_complete(cmd->sk, hdev->id, opcode, mgmt_status(status),
3547 &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03003548
Johan Hedberga664b5b2011-02-19 12:06:02 -03003549 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03003550
3551 return err;
3552}
3553
Johan Hedberg744cf192011-11-08 20:40:14 +02003554int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003555 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003556{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003557 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3558 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003559}
3560
Johan Hedberg272d90d2012-02-09 15:26:12 +02003561int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3562 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003563{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003564 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3565 status, MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003566}
Johan Hedberg2a611692011-02-19 12:06:00 -03003567
Brian Gix604086b2011-11-23 08:28:33 -08003568int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003569 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003570{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003571 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3572 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003573}
3574
Johan Hedberg272d90d2012-02-09 15:26:12 +02003575int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3576 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003577{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003578 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3579 status, MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003580}
3581
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003582int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
3583 u8 addr_type, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03003584{
3585 struct mgmt_ev_auth_failed ev;
3586
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003587 bacpy(&ev.addr.bdaddr, bdaddr);
3588 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003589 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03003590
Johan Hedberg744cf192011-11-08 20:40:14 +02003591 return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03003592}
Johan Hedbergb312b1612011-03-16 14:29:37 +02003593
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003594int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
3595{
3596 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg47990ea2012-02-22 11:58:37 +02003597 bool changed = false;
3598 int err = 0;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003599
3600 if (status) {
3601 u8 mgmt_err = mgmt_status(status);
3602 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
3603 cmd_status_rsp, &mgmt_err);
3604 return 0;
3605 }
3606
Johan Hedberg47990ea2012-02-22 11:58:37 +02003607 if (test_bit(HCI_AUTH, &hdev->flags)) {
3608 if (!test_and_set_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
3609 changed = true;
3610 } else {
3611 if (test_and_clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
3612 changed = true;
3613 }
3614
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003615 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
3616 &match);
3617
Johan Hedberg47990ea2012-02-22 11:58:37 +02003618 if (changed)
3619 err = new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003620
3621 if (match.sk)
3622 sock_put(match.sk);
3623
3624 return err;
3625}
3626
Johan Hedbergcacaf522012-02-21 00:52:42 +02003627static int clear_eir(struct hci_dev *hdev)
3628{
3629 struct hci_cp_write_eir cp;
3630
3631 if (!(hdev->features[6] & LMP_EXT_INQ))
3632 return 0;
3633
Johan Hedbergc80da272012-02-22 15:38:48 +02003634 memset(hdev->eir, 0, sizeof(hdev->eir));
3635
Johan Hedbergcacaf522012-02-21 00:52:42 +02003636 memset(&cp, 0, sizeof(cp));
3637
3638 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
3639}
3640
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003641int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003642{
3643 struct cmd_lookup match = { NULL, hdev };
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003644 bool changed = false;
3645 int err = 0;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003646
3647 if (status) {
3648 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003649
3650 if (enable && test_and_clear_bit(HCI_SSP_ENABLED,
3651 &hdev->dev_flags))
3652 err = new_settings(hdev, NULL);
3653
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003654 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev,
3655 cmd_status_rsp, &mgmt_err);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003656
3657 return err;
3658 }
3659
3660 if (enable) {
3661 if (!test_and_set_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3662 changed = true;
3663 } else {
3664 if (test_and_clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3665 changed = true;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003666 }
3667
3668 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
3669
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003670 if (changed)
3671 err = new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003672
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02003673 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003674 sock_put(match.sk);
3675
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02003676 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3677 update_eir(hdev);
3678 else
3679 clear_eir(hdev);
Johan Hedbergcacaf522012-02-21 00:52:42 +02003680
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003681 return err;
3682}
3683
Johan Hedberg90e70452012-02-23 23:09:40 +02003684static void class_rsp(struct pending_cmd *cmd, void *data)
3685{
3686 struct cmd_lookup *match = data;
3687
3688 cmd_complete(cmd->sk, cmd->index, cmd->opcode, match->mgmt_status,
3689 match->hdev->dev_class, 3);
3690
3691 list_del(&cmd->list);
3692
3693 if (match->sk == NULL) {
3694 match->sk = cmd->sk;
3695 sock_hold(match->sk);
3696 }
3697
3698 mgmt_pending_free(cmd);
3699}
3700
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003701int mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
3702 u8 status)
3703{
Johan Hedberg90e70452012-02-23 23:09:40 +02003704 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
3705 int err = 0;
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003706
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02003707 clear_bit(HCI_PENDING_CLASS, &hdev->dev_flags);
3708
Johan Hedberg90e70452012-02-23 23:09:40 +02003709 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, class_rsp, &match);
3710 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, class_rsp, &match);
3711 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, class_rsp, &match);
3712
3713 if (!status)
3714 err = mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
3715 dev_class, 3, NULL);
3716
3717 if (match.sk)
3718 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003719
3720 return err;
3721}
3722
Johan Hedberg744cf192011-11-08 20:40:14 +02003723int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02003724{
3725 struct pending_cmd *cmd;
3726 struct mgmt_cp_set_local_name ev;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003727 bool changed = false;
3728 int err = 0;
3729
3730 if (memcmp(name, hdev->dev_name, sizeof(hdev->dev_name)) != 0) {
3731 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
3732 changed = true;
3733 }
Johan Hedbergb312b1612011-03-16 14:29:37 +02003734
3735 memset(&ev, 0, sizeof(ev));
3736 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003737 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003738
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003739 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003740 if (!cmd)
3741 goto send_event;
3742
Johan Hedberg7bdaae42012-02-22 21:39:58 +02003743 /* Always assume that either the short or the complete name has
3744 * changed if there was a pending mgmt command */
3745 changed = true;
3746
Johan Hedbergb312b1612011-03-16 14:29:37 +02003747 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02003748 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
Johan Hedbergca69b792011-11-11 18:10:00 +02003749 mgmt_status(status));
Johan Hedbergb312b1612011-03-16 14:29:37 +02003750 goto failed;
3751 }
3752
Johan Hedbergaee9b212012-02-18 15:07:59 +02003753 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0, &ev,
Johan Hedbergb312b1612011-03-16 14:29:37 +02003754 sizeof(ev));
3755 if (err < 0)
3756 goto failed;
3757
3758send_event:
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003759 if (changed)
3760 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev,
3761 sizeof(ev), cmd ? cmd->sk : NULL);
3762
Johan Hedbergf51d5b22012-02-22 18:17:32 +02003763 update_eir(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003764
3765failed:
3766 if (cmd)
3767 mgmt_pending_remove(cmd);
3768 return err;
3769}
Szymon Jancc35938b2011-03-22 13:12:21 +01003770
Johan Hedberg744cf192011-11-08 20:40:14 +02003771int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
3772 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01003773{
3774 struct pending_cmd *cmd;
3775 int err;
3776
Johan Hedberg744cf192011-11-08 20:40:14 +02003777 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01003778
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003779 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003780 if (!cmd)
3781 return -ENOENT;
3782
3783 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02003784 err = cmd_status(cmd->sk, hdev->id,
Johan Hedbergca69b792011-11-11 18:10:00 +02003785 MGMT_OP_READ_LOCAL_OOB_DATA,
3786 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01003787 } else {
3788 struct mgmt_rp_read_local_oob_data rp;
3789
3790 memcpy(rp.hash, hash, sizeof(rp.hash));
3791 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
3792
Johan Hedberg744cf192011-11-08 20:40:14 +02003793 err = cmd_complete(cmd->sk, hdev->id,
3794 MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergaee9b212012-02-18 15:07:59 +02003795 0, &rp, sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01003796 }
3797
3798 mgmt_pending_remove(cmd);
3799
3800 return err;
3801}
Johan Hedberge17acd42011-03-30 23:57:16 +03003802
Johan Hedberg06199cf2012-02-22 16:37:11 +02003803int mgmt_le_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
3804{
3805 struct cmd_lookup match = { NULL, hdev };
3806 bool changed = false;
3807 int err = 0;
3808
3809 if (status) {
3810 u8 mgmt_err = mgmt_status(status);
3811
3812 if (enable && test_and_clear_bit(HCI_LE_ENABLED,
3813 &hdev->dev_flags))
3814 err = new_settings(hdev, NULL);
3815
3816 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev,
3817 cmd_status_rsp, &mgmt_err);
3818
3819 return err;
3820 }
3821
3822 if (enable) {
3823 if (!test_and_set_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3824 changed = true;
3825 } else {
3826 if (test_and_clear_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3827 changed = true;
3828 }
3829
3830 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
3831
3832 if (changed)
3833 err = new_settings(hdev, match.sk);
3834
3835 if (match.sk)
3836 sock_put(match.sk);
3837
3838 return err;
3839}
3840
Johan Hedberg48264f02011-11-09 13:58:58 +02003841int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Johan Hedberg561aafb2012-01-04 13:31:59 +02003842 u8 addr_type, u8 *dev_class, s8 rssi,
Johan Hedberg388fc8f2012-02-23 00:38:59 +02003843 u8 cfm_name, u8 ssp, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03003844{
Johan Hedberge319d2e2012-01-15 19:51:59 +02003845 char buf[512];
3846 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02003847 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03003848
Johan Hedberg1dc06092012-01-15 21:01:23 +02003849 /* Leave 5 bytes for a potential CoD field */
3850 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Andre Guedes7d262f82012-01-10 18:20:49 -03003851 return -EINVAL;
3852
Johan Hedberg1dc06092012-01-15 21:01:23 +02003853 memset(buf, 0, sizeof(buf));
3854
Johan Hedberge319d2e2012-01-15 19:51:59 +02003855 bacpy(&ev->addr.bdaddr, bdaddr);
3856 ev->addr.type = link_to_mgmt(link_type, addr_type);
3857 ev->rssi = rssi;
Johan Hedberg9a395a82012-02-23 00:00:32 +02003858 if (cfm_name)
3859 ev->flags[0] |= MGMT_DEV_FOUND_CONFIRM_NAME;
Johan Hedberg388fc8f2012-02-23 00:38:59 +02003860 if (!ssp)
3861 ev->flags[0] |= MGMT_DEV_FOUND_LEGACY_PAIRING;
Johan Hedberge17acd42011-03-30 23:57:16 +03003862
Johan Hedberg1dc06092012-01-15 21:01:23 +02003863 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02003864 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03003865
Johan Hedberg1dc06092012-01-15 21:01:23 +02003866 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
3867 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
3868 dev_class, 3);
3869
3870 put_unaligned_le16(eir_len, &ev->eir_len);
3871
3872 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03003873
Johan Hedberge319d2e2012-01-15 19:51:59 +02003874 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03003875}
Johan Hedberga88a9652011-03-30 13:18:12 +03003876
Johan Hedbergb644ba32012-01-17 21:48:47 +02003877int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
3878 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03003879{
Johan Hedbergb644ba32012-01-17 21:48:47 +02003880 struct mgmt_ev_device_found *ev;
3881 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
3882 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03003883
Johan Hedbergb644ba32012-01-17 21:48:47 +02003884 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03003885
Johan Hedbergb644ba32012-01-17 21:48:47 +02003886 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03003887
Johan Hedbergb644ba32012-01-17 21:48:47 +02003888 bacpy(&ev->addr.bdaddr, bdaddr);
3889 ev->addr.type = link_to_mgmt(link_type, addr_type);
3890 ev->rssi = rssi;
3891
3892 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
3893 name_len);
3894
3895 put_unaligned_le16(eir_len, &ev->eir_len);
3896
Johan Hedberg053c7e02012-02-04 00:06:00 +02003897 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev,
3898 sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03003899}
Johan Hedberg314b2382011-04-27 10:29:57 -04003900
Andre Guedes7a135102011-11-09 17:14:25 -03003901int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
Johan Hedberg164a6e72011-11-01 17:06:44 +02003902{
3903 struct pending_cmd *cmd;
Johan Hedbergf808e162012-02-19 12:52:07 +02003904 u8 type;
Johan Hedberg164a6e72011-11-01 17:06:44 +02003905 int err;
3906
Andre Guedes203159d2012-02-13 15:41:01 -03003907 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3908
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003909 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003910 if (!cmd)
3911 return -ENOENT;
3912
Johan Hedbergf808e162012-02-19 12:52:07 +02003913 type = hdev->discovery.type;
3914
3915 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
3916 &type, sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02003917 mgmt_pending_remove(cmd);
3918
3919 return err;
3920}
3921
Andre Guedese6d465c2011-11-09 17:14:26 -03003922int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
3923{
3924 struct pending_cmd *cmd;
3925 int err;
3926
3927 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
3928 if (!cmd)
3929 return -ENOENT;
3930
Johan Hedbergd9306502012-02-20 23:25:18 +02003931 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
3932 &hdev->discovery.type,
3933 sizeof(hdev->discovery.type));
Johan Hedberg03811012010-12-08 00:21:06 +02003934 mgmt_pending_remove(cmd);
3935
3936 return err;
3937}
Johan Hedberg314b2382011-04-27 10:29:57 -04003938
Johan Hedberg744cf192011-11-08 20:40:14 +02003939int mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04003940{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02003941 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02003942 struct pending_cmd *cmd;
3943
Andre Guedes343fb142011-11-22 17:14:19 -03003944 BT_DBG("%s discovering %u", hdev->name, discovering);
3945
Johan Hedberg164a6e72011-11-01 17:06:44 +02003946 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003947 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003948 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003949 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003950
3951 if (cmd != NULL) {
Johan Hedbergf808e162012-02-19 12:52:07 +02003952 u8 type = hdev->discovery.type;
3953
Johan Hedbergd9306502012-02-20 23:25:18 +02003954 cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0,
Johan Hedbergf808e162012-02-19 12:52:07 +02003955 &type, sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02003956 mgmt_pending_remove(cmd);
3957 }
3958
Johan Hedbergf963e8e2012-02-20 23:30:44 +02003959 memset(&ev, 0, sizeof(ev));
3960 ev.type = hdev->discovery.type;
3961 ev.discovering = discovering;
3962
3963 return mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04003964}
Antti Julku5e762442011-08-25 16:48:02 +03003965
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003966int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003967{
3968 struct pending_cmd *cmd;
3969 struct mgmt_ev_device_blocked ev;
3970
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003971 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003972
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003973 bacpy(&ev.addr.bdaddr, bdaddr);
3974 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003975
Johan Hedberg744cf192011-11-08 20:40:14 +02003976 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
3977 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003978}
3979
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003980int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003981{
3982 struct pending_cmd *cmd;
3983 struct mgmt_ev_device_unblocked ev;
3984
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003985 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003986
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003987 bacpy(&ev.addr.bdaddr, bdaddr);
3988 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003989
Johan Hedberg744cf192011-11-08 20:40:14 +02003990 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
3991 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003992}
Marcel Holtmannd7b7e792012-02-20 21:47:49 +01003993
3994module_param(enable_hs, bool, 0644);
3995MODULE_PARM_DESC(enable_hs, "Enable High Speed support");
3996
3997module_param(enable_le, bool, 0644);
3998MODULE_PARM_DESC(enable_le, "Enable Low Energy support");