blob: 0e169dacfd4f7dae0ad058620863cfa18f9179a0 [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
Marcel Holtmann17b02e62012-03-01 14:32:37 -0800119#define CACHE_TIMEOUT msecs_to_jiffies(2 * 1000)
Johan Hedberg7d785252011-12-15 00:47:39 +0200120
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200121#define hdev_is_powered(hdev) (test_bit(HCI_UP, &hdev->flags) && \
122 !test_bit(HCI_AUTO_OFF, &hdev->dev_flags))
123
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200124struct pending_cmd {
125 struct list_head list;
Johan Hedbergfc2f4b12011-11-09 13:58:56 +0200126 u16 opcode;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200127 int index;
Szymon Jancc68fb7f2011-03-22 13:12:19 +0100128 void *param;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200129 struct sock *sk;
Johan Hedberge9a416b2011-02-19 12:05:56 -0300130 void *user_data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200131};
132
Johan Hedbergca69b792011-11-11 18:10:00 +0200133/* HCI to MGMT error code conversion table */
134static u8 mgmt_status_table[] = {
135 MGMT_STATUS_SUCCESS,
136 MGMT_STATUS_UNKNOWN_COMMAND, /* Unknown Command */
137 MGMT_STATUS_NOT_CONNECTED, /* No Connection */
138 MGMT_STATUS_FAILED, /* Hardware Failure */
139 MGMT_STATUS_CONNECT_FAILED, /* Page Timeout */
140 MGMT_STATUS_AUTH_FAILED, /* Authentication Failed */
141 MGMT_STATUS_NOT_PAIRED, /* PIN or Key Missing */
142 MGMT_STATUS_NO_RESOURCES, /* Memory Full */
143 MGMT_STATUS_TIMEOUT, /* Connection Timeout */
144 MGMT_STATUS_NO_RESOURCES, /* Max Number of Connections */
145 MGMT_STATUS_NO_RESOURCES, /* Max Number of SCO Connections */
146 MGMT_STATUS_ALREADY_CONNECTED, /* ACL Connection Exists */
147 MGMT_STATUS_BUSY, /* Command Disallowed */
148 MGMT_STATUS_NO_RESOURCES, /* Rejected Limited Resources */
149 MGMT_STATUS_REJECTED, /* Rejected Security */
150 MGMT_STATUS_REJECTED, /* Rejected Personal */
151 MGMT_STATUS_TIMEOUT, /* Host Timeout */
152 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Feature */
153 MGMT_STATUS_INVALID_PARAMS, /* Invalid Parameters */
154 MGMT_STATUS_DISCONNECTED, /* OE User Ended Connection */
155 MGMT_STATUS_NO_RESOURCES, /* OE Low Resources */
156 MGMT_STATUS_DISCONNECTED, /* OE Power Off */
157 MGMT_STATUS_DISCONNECTED, /* Connection Terminated */
158 MGMT_STATUS_BUSY, /* Repeated Attempts */
159 MGMT_STATUS_REJECTED, /* Pairing Not Allowed */
160 MGMT_STATUS_FAILED, /* Unknown LMP PDU */
161 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Remote Feature */
162 MGMT_STATUS_REJECTED, /* SCO Offset Rejected */
163 MGMT_STATUS_REJECTED, /* SCO Interval Rejected */
164 MGMT_STATUS_REJECTED, /* Air Mode Rejected */
165 MGMT_STATUS_INVALID_PARAMS, /* Invalid LMP Parameters */
166 MGMT_STATUS_FAILED, /* Unspecified Error */
167 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported LMP Parameter Value */
168 MGMT_STATUS_FAILED, /* Role Change Not Allowed */
169 MGMT_STATUS_TIMEOUT, /* LMP Response Timeout */
170 MGMT_STATUS_FAILED, /* LMP Error Transaction Collision */
171 MGMT_STATUS_FAILED, /* LMP PDU Not Allowed */
172 MGMT_STATUS_REJECTED, /* Encryption Mode Not Accepted */
173 MGMT_STATUS_FAILED, /* Unit Link Key Used */
174 MGMT_STATUS_NOT_SUPPORTED, /* QoS Not Supported */
175 MGMT_STATUS_TIMEOUT, /* Instant Passed */
176 MGMT_STATUS_NOT_SUPPORTED, /* Pairing Not Supported */
177 MGMT_STATUS_FAILED, /* Transaction Collision */
178 MGMT_STATUS_INVALID_PARAMS, /* Unacceptable Parameter */
179 MGMT_STATUS_REJECTED, /* QoS Rejected */
180 MGMT_STATUS_NOT_SUPPORTED, /* Classification Not Supported */
181 MGMT_STATUS_REJECTED, /* Insufficient Security */
182 MGMT_STATUS_INVALID_PARAMS, /* Parameter Out Of Range */
183 MGMT_STATUS_BUSY, /* Role Switch Pending */
184 MGMT_STATUS_FAILED, /* Slot Violation */
185 MGMT_STATUS_FAILED, /* Role Switch Failed */
186 MGMT_STATUS_INVALID_PARAMS, /* EIR Too Large */
187 MGMT_STATUS_NOT_SUPPORTED, /* Simple Pairing Not Supported */
188 MGMT_STATUS_BUSY, /* Host Busy Pairing */
189 MGMT_STATUS_REJECTED, /* Rejected, No Suitable Channel */
190 MGMT_STATUS_BUSY, /* Controller Busy */
191 MGMT_STATUS_INVALID_PARAMS, /* Unsuitable Connection Interval */
192 MGMT_STATUS_TIMEOUT, /* Directed Advertising Timeout */
193 MGMT_STATUS_AUTH_FAILED, /* Terminated Due to MIC Failure */
194 MGMT_STATUS_CONNECT_FAILED, /* Connection Establishment Failed */
195 MGMT_STATUS_CONNECT_FAILED, /* MAC Connection Failed */
196};
197
198static u8 mgmt_status(u8 hci_status)
199{
200 if (hci_status < ARRAY_SIZE(mgmt_status_table))
201 return mgmt_status_table[hci_status];
202
203 return MGMT_STATUS_FAILED;
204}
205
Szymon Janc4e51eae2011-02-25 19:05:48 +0100206static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200207{
208 struct sk_buff *skb;
209 struct mgmt_hdr *hdr;
210 struct mgmt_ev_cmd_status *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300211 int err;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200212
Szymon Janc34eb5252011-02-28 14:10:08 +0100213 BT_DBG("sock %p, index %u, cmd %u, status %u", sk, index, cmd, status);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200214
215 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_ATOMIC);
216 if (!skb)
217 return -ENOMEM;
218
219 hdr = (void *) skb_put(skb, sizeof(*hdr));
220
221 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_STATUS);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100222 hdr->index = cpu_to_le16(index);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200223 hdr->len = cpu_to_le16(sizeof(*ev));
224
225 ev = (void *) skb_put(skb, sizeof(*ev));
226 ev->status = status;
227 put_unaligned_le16(cmd, &ev->opcode);
228
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300229 err = sock_queue_rcv_skb(sk, skb);
230 if (err < 0)
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200231 kfree_skb(skb);
232
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300233 return err;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200234}
235
Johan Hedbergaee9b212012-02-18 15:07:59 +0200236static int cmd_complete(struct sock *sk, u16 index, u16 cmd, u8 status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300237 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
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300270static int read_version(struct sock *sk, struct hci_dev *hdev, void *data,
271 u16 data_len)
Johan Hedberga38528f2011-01-22 06:46:43 +0200272{
273 struct mgmt_rp_read_version rp;
274
275 BT_DBG("sock %p", sk);
276
277 rp.version = MGMT_VERSION;
278 put_unaligned_le16(MGMT_REVISION, &rp.revision);
279
Johan Hedbergaee9b212012-02-18 15:07:59 +0200280 return cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300281 sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200282}
283
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300284static int read_commands(struct sock *sk, struct hci_dev *hdev, void *data,
285 u16 data_len)
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200286{
287 struct mgmt_rp_read_commands *rp;
288 u16 num_commands = ARRAY_SIZE(mgmt_commands);
289 u16 num_events = ARRAY_SIZE(mgmt_events);
290 u16 *opcode;
291 size_t rp_size;
292 int i, err;
293
294 BT_DBG("sock %p", sk);
295
296 rp_size = sizeof(*rp) + ((num_commands + num_events) * sizeof(u16));
297
298 rp = kmalloc(rp_size, GFP_KERNEL);
299 if (!rp)
300 return -ENOMEM;
301
302 put_unaligned_le16(num_commands, &rp->num_commands);
303 put_unaligned_le16(num_events, &rp->num_events);
304
305 for (i = 0, opcode = rp->opcodes; i < num_commands; i++, opcode++)
306 put_unaligned_le16(mgmt_commands[i], opcode);
307
308 for (i = 0; i < num_events; i++, opcode++)
309 put_unaligned_le16(mgmt_events[i], opcode);
310
Johan Hedbergaee9b212012-02-18 15:07:59 +0200311 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_COMMANDS, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300312 rp_size);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200313 kfree(rp);
314
315 return err;
316}
317
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300318static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data,
319 u16 data_len)
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200320{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200321 struct mgmt_rp_read_index_list *rp;
322 struct list_head *p;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200323 struct hci_dev *d;
Johan Hedberga38528f2011-01-22 06:46:43 +0200324 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200325 u16 count;
Johan Hedberga38528f2011-01-22 06:46:43 +0200326 int i, err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200327
328 BT_DBG("sock %p", sk);
329
330 read_lock(&hci_dev_list_lock);
331
332 count = 0;
333 list_for_each(p, &hci_dev_list) {
334 count++;
335 }
336
Johan Hedberga38528f2011-01-22 06:46:43 +0200337 rp_len = sizeof(*rp) + (2 * count);
338 rp = kmalloc(rp_len, GFP_ATOMIC);
339 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100340 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200341 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100342 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200343
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200344 put_unaligned_le16(count, &rp->num_controllers);
345
346 i = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200347 list_for_each_entry(d, &hci_dev_list, list) {
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200348 if (test_bit(HCI_SETUP, &d->dev_flags))
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200349 continue;
350
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200351 put_unaligned_le16(d->id, &rp->index[i++]);
352 BT_DBG("Added hci%u", d->id);
353 }
354
355 read_unlock(&hci_dev_list_lock);
356
Johan Hedbergaee9b212012-02-18 15:07:59 +0200357 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300358 rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200359
Johan Hedberga38528f2011-01-22 06:46:43 +0200360 kfree(rp);
361
362 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200363}
364
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200365static u32 get_supported_settings(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +0200366{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200367 u32 settings = 0;
Johan Hedberg03811012010-12-08 00:21:06 +0200368
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200369 settings |= MGMT_SETTING_POWERED;
370 settings |= MGMT_SETTING_CONNECTABLE;
371 settings |= MGMT_SETTING_FAST_CONNECTABLE;
372 settings |= MGMT_SETTING_DISCOVERABLE;
373 settings |= MGMT_SETTING_PAIRABLE;
Johan Hedberg03811012010-12-08 00:21:06 +0200374
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200375 if (hdev->features[6] & LMP_SIMPLE_PAIR)
376 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200377
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200378 if (!(hdev->features[4] & LMP_NO_BREDR)) {
379 settings |= MGMT_SETTING_BREDR;
380 settings |= MGMT_SETTING_LINK_SECURITY;
381 }
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200382
Marcel Holtmannd7b7e792012-02-20 21:47:49 +0100383 if (enable_hs)
384 settings |= MGMT_SETTING_HS;
385
386 if (enable_le) {
387 if (hdev->features[4] & LMP_LE)
388 settings |= MGMT_SETTING_LE;
389 }
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200390
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200391 return settings;
392}
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200393
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200394static u32 get_current_settings(struct hci_dev *hdev)
395{
396 u32 settings = 0;
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200397
Johan Hedbergf1f0eb02012-02-21 17:15:41 +0200398 if (hdev_is_powered(hdev))
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100399 settings |= MGMT_SETTING_POWERED;
400
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200401 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200402 settings |= MGMT_SETTING_CONNECTABLE;
403
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200404 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200405 settings |= MGMT_SETTING_DISCOVERABLE;
406
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200407 if (test_bit(HCI_PAIRABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200408 settings |= MGMT_SETTING_PAIRABLE;
409
410 if (!(hdev->features[4] & LMP_NO_BREDR))
411 settings |= MGMT_SETTING_BREDR;
412
Johan Hedberg06199cf2012-02-22 16:37:11 +0200413 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200414 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200415
Johan Hedberg47990ea2012-02-22 11:58:37 +0200416 if (test_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200417 settings |= MGMT_SETTING_LINK_SECURITY;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200418
Johan Hedberg84bde9d6c2012-01-25 14:21:06 +0200419 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200420 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200421
Johan Hedberg6d80dfd2012-02-20 23:50:38 +0200422 if (test_bit(HCI_HS_ENABLED, &hdev->dev_flags))
423 settings |= MGMT_SETTING_HS;
424
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200425 return settings;
Johan Hedbergc542a062011-01-26 13:11:03 +0200426}
427
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300428#define PNP_INFO_SVCLASS_ID 0x1200
429
430static u8 bluetooth_base_uuid[] = {
431 0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80,
432 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
433};
434
435static u16 get_uuid16(u8 *uuid128)
436{
437 u32 val;
438 int i;
439
440 for (i = 0; i < 12; i++) {
441 if (bluetooth_base_uuid[i] != uuid128[i])
442 return 0;
443 }
444
445 memcpy(&val, &uuid128[12], 4);
446
447 val = le32_to_cpu(val);
448 if (val > 0xffff)
449 return 0;
450
451 return (u16) val;
452}
453
454static void create_eir(struct hci_dev *hdev, u8 *data)
455{
456 u8 *ptr = data;
457 u16 eir_len = 0;
458 u16 uuid16_list[HCI_MAX_EIR_LENGTH / sizeof(u16)];
459 int i, truncated = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200460 struct bt_uuid *uuid;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300461 size_t name_len;
462
463 name_len = strlen(hdev->dev_name);
464
465 if (name_len > 0) {
466 /* EIR Data type */
467 if (name_len > 48) {
468 name_len = 48;
469 ptr[1] = EIR_NAME_SHORT;
470 } else
471 ptr[1] = EIR_NAME_COMPLETE;
472
473 /* EIR Data length */
474 ptr[0] = name_len + 1;
475
476 memcpy(ptr + 2, hdev->dev_name, name_len);
477
478 eir_len += (name_len + 2);
479 ptr += (name_len + 2);
480 }
481
482 memset(uuid16_list, 0, sizeof(uuid16_list));
483
484 /* Group all UUID16 types */
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200485 list_for_each_entry(uuid, &hdev->uuids, list) {
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300486 u16 uuid16;
487
488 uuid16 = get_uuid16(uuid->uuid);
489 if (uuid16 == 0)
490 return;
491
492 if (uuid16 < 0x1100)
493 continue;
494
495 if (uuid16 == PNP_INFO_SVCLASS_ID)
496 continue;
497
498 /* Stop if not enough space to put next UUID */
499 if (eir_len + 2 + sizeof(u16) > HCI_MAX_EIR_LENGTH) {
500 truncated = 1;
501 break;
502 }
503
504 /* Check for duplicates */
505 for (i = 0; uuid16_list[i] != 0; i++)
506 if (uuid16_list[i] == uuid16)
507 break;
508
509 if (uuid16_list[i] == 0) {
510 uuid16_list[i] = uuid16;
511 eir_len += sizeof(u16);
512 }
513 }
514
515 if (uuid16_list[0] != 0) {
516 u8 *length = ptr;
517
518 /* EIR Data type */
519 ptr[1] = truncated ? EIR_UUID16_SOME : EIR_UUID16_ALL;
520
521 ptr += 2;
522 eir_len += 2;
523
524 for (i = 0; uuid16_list[i] != 0; i++) {
525 *ptr++ = (uuid16_list[i] & 0x00ff);
526 *ptr++ = (uuid16_list[i] & 0xff00) >> 8;
527 }
528
529 /* EIR Data length */
530 *length = (i * sizeof(u16)) + 1;
531 }
532}
533
534static int update_eir(struct hci_dev *hdev)
535{
536 struct hci_cp_write_eir cp;
537
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200538 if (!hdev_is_powered(hdev))
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200539 return 0;
540
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300541 if (!(hdev->features[6] & LMP_EXT_INQ))
542 return 0;
543
Johan Hedberg84bde9d6c2012-01-25 14:21:06 +0200544 if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300545 return 0;
546
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200547 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300548 return 0;
549
550 memset(&cp, 0, sizeof(cp));
551
552 create_eir(hdev, cp.data);
553
554 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
555 return 0;
556
557 memcpy(hdev->eir, cp.data, sizeof(cp.data));
558
559 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
560}
561
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200562static u8 get_service_classes(struct hci_dev *hdev)
563{
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300564 struct bt_uuid *uuid;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200565 u8 val = 0;
566
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300567 list_for_each_entry(uuid, &hdev->uuids, list)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200568 val |= uuid->svc_hint;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200569
570 return val;
571}
572
573static int update_class(struct hci_dev *hdev)
574{
575 u8 cod[3];
Johan Hedbergc95f0ba2012-02-23 22:54:38 +0200576 int err;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200577
578 BT_DBG("%s", hdev->name);
579
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200580 if (!hdev_is_powered(hdev))
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200581 return 0;
582
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200583 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200584 return 0;
585
586 cod[0] = hdev->minor_class;
587 cod[1] = hdev->major_class;
588 cod[2] = get_service_classes(hdev);
589
590 if (memcmp(cod, hdev->dev_class, 3) == 0)
591 return 0;
592
Johan Hedbergc95f0ba2012-02-23 22:54:38 +0200593 err = hci_send_cmd(hdev, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
594 if (err == 0)
595 set_bit(HCI_PENDING_CLASS, &hdev->dev_flags);
596
597 return err;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200598}
599
Johan Hedberg7d785252011-12-15 00:47:39 +0200600static void service_cache_off(struct work_struct *work)
601{
602 struct hci_dev *hdev = container_of(work, struct hci_dev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300603 service_cache.work);
Johan Hedberg7d785252011-12-15 00:47:39 +0200604
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200605 if (!test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200606 return;
607
608 hci_dev_lock(hdev);
609
610 update_eir(hdev);
611 update_class(hdev);
612
613 hci_dev_unlock(hdev);
614}
615
Johan Hedberg6a919082012-02-28 06:17:26 +0200616static void mgmt_init_hdev(struct sock *sk, struct hci_dev *hdev)
Johan Hedberg7d785252011-12-15 00:47:39 +0200617{
Johan Hedberg4f87da82012-03-02 19:55:56 +0200618 if (test_and_set_bit(HCI_MGMT, &hdev->dev_flags))
Johan Hedberg6a919082012-02-28 06:17:26 +0200619 return;
620
Johan Hedberg4f87da82012-03-02 19:55:56 +0200621 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
Johan Hedberg7d785252011-12-15 00:47:39 +0200622
Johan Hedberg4f87da82012-03-02 19:55:56 +0200623 /* Non-mgmt controlled devices get this bit set
624 * implicitly so that pairing works for them, however
625 * for mgmt we require user-space to explicitly enable
626 * it
627 */
628 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedberg7d785252011-12-15 00:47:39 +0200629}
630
Johan Hedberg0f4e68c2012-02-28 17:18:30 +0200631static int read_controller_info(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300632 void *data, u16 data_len)
Johan Hedberg03811012010-12-08 00:21:06 +0200633{
634 struct mgmt_rp_read_info rp;
Johan Hedberg03811012010-12-08 00:21:06 +0200635
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200636 BT_DBG("sock %p %s", sk, hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200637
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300638 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200639
Johan Hedberg03811012010-12-08 00:21:06 +0200640 memset(&rp, 0, sizeof(rp));
641
Johan Hedberg03811012010-12-08 00:21:06 +0200642 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200643
644 rp.version = hdev->hci_ver;
645
Johan Hedberg03811012010-12-08 00:21:06 +0200646 put_unaligned_le16(hdev->manufacturer, &rp.manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200647
648 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
649 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
650
651 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedberg03811012010-12-08 00:21:06 +0200652
653 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
Johan Hedberg27fcc362012-02-22 21:46:22 +0200654 memcpy(rp.short_name, hdev->short_name, sizeof(hdev->short_name));
Johan Hedberg03811012010-12-08 00:21:06 +0200655
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300656 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200657
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200658 return cmd_complete(sk, hdev->id, MGMT_OP_READ_INFO, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300659 sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +0200660}
661
662static void mgmt_pending_free(struct pending_cmd *cmd)
663{
664 sock_put(cmd->sk);
665 kfree(cmd->param);
666 kfree(cmd);
667}
668
669static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300670 struct hci_dev *hdev, void *data,
671 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200672{
673 struct pending_cmd *cmd;
674
675 cmd = kmalloc(sizeof(*cmd), GFP_ATOMIC);
676 if (!cmd)
677 return NULL;
678
679 cmd->opcode = opcode;
680 cmd->index = hdev->id;
681
682 cmd->param = kmalloc(len, GFP_ATOMIC);
683 if (!cmd->param) {
684 kfree(cmd);
685 return NULL;
686 }
687
688 if (data)
689 memcpy(cmd->param, data, len);
690
691 cmd->sk = sk;
692 sock_hold(sk);
693
694 list_add(&cmd->list, &hdev->mgmt_pending);
695
696 return cmd;
697}
698
699static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300700 void (*cb)(struct pending_cmd *cmd, void *data),
701 void *data)
Johan Hedberg03811012010-12-08 00:21:06 +0200702{
703 struct list_head *p, *n;
704
705 list_for_each_safe(p, n, &hdev->mgmt_pending) {
706 struct pending_cmd *cmd;
707
708 cmd = list_entry(p, struct pending_cmd, list);
709
710 if (opcode > 0 && cmd->opcode != opcode)
711 continue;
712
713 cb(cmd, data);
714 }
715}
716
717static struct pending_cmd *mgmt_pending_find(u16 opcode, struct hci_dev *hdev)
718{
719 struct pending_cmd *cmd;
720
721 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
722 if (cmd->opcode == opcode)
723 return cmd;
724 }
725
726 return NULL;
727}
728
729static void mgmt_pending_remove(struct pending_cmd *cmd)
730{
731 list_del(&cmd->list);
732 mgmt_pending_free(cmd);
733}
734
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200735static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +0200736{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200737 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +0200738
Johan Hedbergaee9b212012-02-18 15:07:59 +0200739 return cmd_complete(sk, hdev->id, opcode, 0, &settings,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300740 sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +0200741}
742
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200743static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300744 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200745{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300746 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200747 struct pending_cmd *cmd;
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200748 int err;
Johan Hedberg03811012010-12-08 00:21:06 +0200749
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200750 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200751
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300752 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200753
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100754 if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) {
755 cancel_delayed_work(&hdev->power_off);
756
757 if (cp->val) {
758 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
759 mgmt_powered(hdev, 1);
760 goto failed;
761 }
762 }
763
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200764 if (!!cp->val == hdev_is_powered(hdev)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200765 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200766 goto failed;
767 }
768
769 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200770 err = cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300771 MGMT_STATUS_BUSY);
Johan Hedberg03811012010-12-08 00:21:06 +0200772 goto failed;
773 }
774
775 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
776 if (!cmd) {
777 err = -ENOMEM;
778 goto failed;
779 }
780
781 if (cp->val)
Gustavo F. Padovan7f971042011-12-18 12:40:32 -0200782 schedule_work(&hdev->power_on);
Johan Hedberg03811012010-12-08 00:21:06 +0200783 else
Gustavo F. Padovan80b7ab32011-12-17 14:52:27 -0200784 schedule_work(&hdev->power_off.work);
Johan Hedberg03811012010-12-08 00:21:06 +0200785
786 err = 0;
787
788failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300789 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200790 return err;
791}
792
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300793static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, u16 data_len,
794 struct sock *skip_sk)
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200795{
796 struct sk_buff *skb;
797 struct mgmt_hdr *hdr;
798
799 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_ATOMIC);
800 if (!skb)
801 return -ENOMEM;
802
803 hdr = (void *) skb_put(skb, sizeof(*hdr));
804 hdr->opcode = cpu_to_le16(event);
805 if (hdev)
806 hdr->index = cpu_to_le16(hdev->id);
807 else
808 hdr->index = cpu_to_le16(MGMT_INDEX_NONE);
809 hdr->len = cpu_to_le16(data_len);
810
811 if (data)
812 memcpy(skb_put(skb, data_len), data, data_len);
813
Marcel Holtmann97e0bde2012-02-22 13:49:28 +0100814 /* Time stamp */
815 __net_timestamp(skb);
816
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200817 hci_send_to_control(skb, skip_sk);
818 kfree_skb(skb);
819
820 return 0;
821}
822
823static int new_settings(struct hci_dev *hdev, struct sock *skip)
824{
825 __le32 ev;
826
827 ev = cpu_to_le32(get_current_settings(hdev));
828
829 return mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), skip);
830}
831
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200832static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300833 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200834{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300835 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200836 struct pending_cmd *cmd;
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200837 u16 timeout;
Johan Hedberg03811012010-12-08 00:21:06 +0200838 u8 scan;
839 int err;
840
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200841 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200842
Marcel Holtmann24c54a92012-02-22 18:06:34 +0100843 timeout = get_unaligned_le16(&cp->timeout);
844 if (!cp->val && timeout > 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200845 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300846 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200847
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300848 hci_dev_lock(hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200849
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200850 if (!hdev_is_powered(hdev) && timeout > 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200851 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300852 MGMT_STATUS_NOT_POWERED);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200853 goto failed;
854 }
855
856 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
857 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200858 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300859 MGMT_STATUS_BUSY);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200860 goto failed;
861 }
862
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200863 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200864 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300865 MGMT_STATUS_REJECTED);
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200866 goto failed;
867 }
868
869 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200870 bool changed = false;
871
872 if (!!cp->val != test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
873 change_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
874 changed = true;
875 }
876
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200877 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200878 if (err < 0)
879 goto failed;
880
881 if (changed)
882 err = new_settings(hdev, sk);
883
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200884 goto failed;
885 }
886
887 if (!!cp->val == test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
Marcel Holtmann955638e2012-02-22 18:21:00 +0100888 if (hdev->discov_timeout > 0) {
889 cancel_delayed_work(&hdev->discov_off);
890 hdev->discov_timeout = 0;
891 }
892
893 if (cp->val && timeout > 0) {
894 hdev->discov_timeout = timeout;
895 queue_delayed_work(hdev->workqueue, &hdev->discov_off,
896 msecs_to_jiffies(hdev->discov_timeout * 1000));
897 }
898
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200899 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200900 goto failed;
901 }
902
903 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
904 if (!cmd) {
905 err = -ENOMEM;
906 goto failed;
907 }
908
909 scan = SCAN_PAGE;
910
911 if (cp->val)
912 scan |= SCAN_INQUIRY;
913 else
914 cancel_delayed_work(&hdev->discov_off);
915
916 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
917 if (err < 0)
918 mgmt_pending_remove(cmd);
919
Johan Hedberg03811012010-12-08 00:21:06 +0200920 if (cp->val)
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200921 hdev->discov_timeout = timeout;
Johan Hedberg03811012010-12-08 00:21:06 +0200922
923failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300924 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200925 return err;
926}
927
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200928static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300929 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200930{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300931 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200932 struct pending_cmd *cmd;
933 u8 scan;
934 int err;
935
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200936 BT_DBG("request for %s", hdev->name);
Johan Hedberge41d8b42010-12-13 21:07:03 +0200937
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300938 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200939
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200940 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200941 bool changed = false;
942
943 if (!!cp->val != test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
944 changed = true;
945
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +0200946 if (cp->val) {
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200947 set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +0200948 } else {
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200949 clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
950 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
951 }
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200952
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200953 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200954 if (err < 0)
955 goto failed;
956
957 if (changed)
958 err = new_settings(hdev, sk);
959
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200960 goto failed;
961 }
962
963 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
964 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200965 err = cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300966 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200967 goto failed;
968 }
969
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200970 if (!!cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200971 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200972 goto failed;
973 }
974
975 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
976 if (!cmd) {
977 err = -ENOMEM;
978 goto failed;
979 }
980
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +0200981 if (cp->val) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200982 scan = SCAN_PAGE;
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +0200983 } else {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200984 scan = 0;
985
Johan Hedbergdf2c6c52012-02-21 19:15:49 +0200986 if (test_bit(HCI_ISCAN, &hdev->flags) &&
987 hdev->discov_timeout > 0)
988 cancel_delayed_work(&hdev->discov_off);
989 }
990
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200991 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
992 if (err < 0)
993 mgmt_pending_remove(cmd);
994
995failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300996 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200997 return err;
998}
999
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001000static int set_pairable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001001 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001002{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001003 struct mgmt_mode *cp = data;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001004 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001005
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001006 BT_DBG("request for %s", hdev->name);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001007
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001008 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001009
1010 if (cp->val)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001011 set_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001012 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001013 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001014
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001015 err = send_settings_rsp(sk, MGMT_OP_SET_PAIRABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001016 if (err < 0)
1017 goto failed;
1018
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001019 err = new_settings(hdev, sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001020
1021failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001022 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001023 return err;
1024}
Johan Hedberg72a734e2010-12-30 00:38:22 +02001025
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001026static int set_link_security(struct sock *sk, struct hci_dev *hdev, void *data,
1027 u16 len)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001028{
1029 struct mgmt_mode *cp = data;
1030 struct pending_cmd *cmd;
Johan Hedberg816a11d2012-02-26 13:04:52 +02001031 u8 val;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001032 int err;
1033
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001034 BT_DBG("request for %s", hdev->name);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001035
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001036 hci_dev_lock(hdev);
1037
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001038 if (!hdev_is_powered(hdev)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001039 bool changed = false;
1040
1041 if (!!cp->val != test_bit(HCI_LINK_SECURITY,
1042 &hdev->dev_flags)) {
1043 change_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
1044 changed = true;
1045 }
1046
1047 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1048 if (err < 0)
1049 goto failed;
1050
1051 if (changed)
1052 err = new_settings(hdev, sk);
1053
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001054 goto failed;
1055 }
1056
1057 if (mgmt_pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001058 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001059 MGMT_STATUS_BUSY);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001060 goto failed;
1061 }
1062
1063 val = !!cp->val;
1064
1065 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1066 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1067 goto failed;
1068 }
1069
1070 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1071 if (!cmd) {
1072 err = -ENOMEM;
1073 goto failed;
1074 }
1075
1076 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1077 if (err < 0) {
1078 mgmt_pending_remove(cmd);
1079 goto failed;
1080 }
1081
1082failed:
1083 hci_dev_unlock(hdev);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001084 return err;
1085}
1086
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001087static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001088{
1089 struct mgmt_mode *cp = data;
1090 struct pending_cmd *cmd;
Johan Hedberg816a11d2012-02-26 13:04:52 +02001091 u8 val;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001092 int err;
1093
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001094 BT_DBG("request for %s", hdev->name);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001095
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001096 hci_dev_lock(hdev);
1097
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001098 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001099 err = cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001100 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001101 goto failed;
1102 }
1103
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001104 val = !!cp->val;
1105
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001106 if (!hdev_is_powered(hdev)) {
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001107 bool changed = false;
1108
1109 if (val != test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) {
1110 change_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
1111 changed = true;
1112 }
1113
1114 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1115 if (err < 0)
1116 goto failed;
1117
1118 if (changed)
1119 err = new_settings(hdev, sk);
1120
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001121 goto failed;
1122 }
1123
1124 if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev)) {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001125 err = cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1126 MGMT_STATUS_BUSY);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001127 goto failed;
1128 }
1129
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001130 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) == val) {
1131 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1132 goto failed;
1133 }
1134
1135 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1136 if (!cmd) {
1137 err = -ENOMEM;
1138 goto failed;
1139 }
1140
1141 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, sizeof(val), &val);
1142 if (err < 0) {
1143 mgmt_pending_remove(cmd);
1144 goto failed;
1145 }
1146
1147failed:
1148 hci_dev_unlock(hdev);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001149 return err;
1150}
1151
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001152static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001153{
1154 struct mgmt_mode *cp = data;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001155
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001156 BT_DBG("request for %s", hdev->name);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001157
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001158 if (!enable_hs)
1159 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001160 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001161
1162 if (cp->val)
1163 set_bit(HCI_HS_ENABLED, &hdev->dev_flags);
1164 else
1165 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
1166
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001167 return send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001168}
1169
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001170static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001171{
1172 struct mgmt_mode *cp = data;
1173 struct hci_cp_write_le_host_supported hci_cp;
1174 struct pending_cmd *cmd;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001175 int err;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001176 u8 val, enabled;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001177
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001178 BT_DBG("request for %s", hdev->name);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001179
Johan Hedberg1de028c2012-02-29 19:55:35 -08001180 hci_dev_lock(hdev);
1181
Johan Hedberg06199cf2012-02-22 16:37:11 +02001182 if (!enable_le || !(hdev->features[4] & LMP_LE)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001183 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001184 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001185 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001186 }
1187
1188 val = !!cp->val;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001189 enabled = !!(hdev->host_features[0] & LMP_HOST_LE);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001190
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001191 if (!hdev_is_powered(hdev) || val == enabled) {
Johan Hedberg06199cf2012-02-22 16:37:11 +02001192 bool changed = false;
1193
1194 if (val != test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
1195 change_bit(HCI_LE_ENABLED, &hdev->dev_flags);
1196 changed = true;
1197 }
1198
1199 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1200 if (err < 0)
Johan Hedberg1de028c2012-02-29 19:55:35 -08001201 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001202
1203 if (changed)
1204 err = new_settings(hdev, sk);
1205
Johan Hedberg1de028c2012-02-29 19:55:35 -08001206 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001207 }
1208
1209 if (mgmt_pending_find(MGMT_OP_SET_LE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001210 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001211 MGMT_STATUS_BUSY);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001212 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001213 }
1214
1215 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
1216 if (!cmd) {
1217 err = -ENOMEM;
Johan Hedberg1de028c2012-02-29 19:55:35 -08001218 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001219 }
1220
1221 memset(&hci_cp, 0, sizeof(hci_cp));
1222
1223 if (val) {
1224 hci_cp.le = val;
1225 hci_cp.simul = !!(hdev->features[6] & LMP_SIMUL_LE_BR);
1226 }
1227
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001228 err = hci_send_cmd(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp),
1229 &hci_cp);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001230 if (err < 0) {
1231 mgmt_pending_remove(cmd);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001232 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001233 }
1234
Johan Hedberg1de028c2012-02-29 19:55:35 -08001235unlock:
1236 hci_dev_unlock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001237 return err;
1238}
1239
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001240static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001241{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001242 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001243 struct pending_cmd *cmd;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001244 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001245 int err;
1246
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001247 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001248
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001249 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001250
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001251 if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001252 err = cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001253 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001254 goto failed;
1255 }
1256
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001257 uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC);
1258 if (!uuid) {
1259 err = -ENOMEM;
1260 goto failed;
1261 }
1262
1263 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001264 uuid->svc_hint = cp->svc_hint;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001265
1266 list_add(&uuid->list, &hdev->uuids);
1267
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001268 err = update_class(hdev);
1269 if (err < 0)
1270 goto failed;
1271
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001272 err = update_eir(hdev);
1273 if (err < 0)
1274 goto failed;
1275
Johan Hedberg90e70452012-02-23 23:09:40 +02001276 if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001277 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001278 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001279 goto failed;
1280 }
1281
1282 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len);
1283 if (!cmd) {
1284 err = -ENOMEM;
1285 goto failed;
1286 }
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001287
1288failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001289 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001290 return err;
1291}
1292
Johan Hedberg24b78d02012-02-23 23:24:30 +02001293static bool enable_service_cache(struct hci_dev *hdev)
1294{
1295 if (!hdev_is_powered(hdev))
1296 return false;
1297
1298 if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Marcel Holtmann17b02e62012-03-01 14:32:37 -08001299 schedule_delayed_work(&hdev->service_cache, CACHE_TIMEOUT);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001300 return true;
1301 }
1302
1303 return false;
1304}
1305
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001306static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
1307 u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001308{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001309 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001310 struct pending_cmd *cmd;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001311 struct list_head *p, *n;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001312 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 +02001313 int err, found;
1314
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001315 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001316
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001317 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001318
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001319 if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001320 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001321 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001322 goto unlock;
1323 }
1324
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001325 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
1326 err = hci_uuids_clear(hdev);
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001327
Johan Hedberg24b78d02012-02-23 23:24:30 +02001328 if (enable_service_cache(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001329 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001330 0, hdev->dev_class, 3);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001331 goto unlock;
1332 }
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001333
Johan Hedberg9246a862012-02-23 21:33:16 +02001334 goto update_class;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001335 }
1336
1337 found = 0;
1338
1339 list_for_each_safe(p, n, &hdev->uuids) {
1340 struct bt_uuid *match = list_entry(p, struct bt_uuid, list);
1341
1342 if (memcmp(match->uuid, cp->uuid, 16) != 0)
1343 continue;
1344
1345 list_del(&match->list);
1346 found++;
1347 }
1348
1349 if (found == 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001350 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001351 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001352 goto unlock;
1353 }
1354
Johan Hedberg9246a862012-02-23 21:33:16 +02001355update_class:
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001356 err = update_class(hdev);
1357 if (err < 0)
1358 goto unlock;
1359
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001360 err = update_eir(hdev);
1361 if (err < 0)
1362 goto unlock;
1363
Johan Hedberg90e70452012-02-23 23:09:40 +02001364 if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001365 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001366 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001367 goto unlock;
1368 }
1369
1370 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
1371 if (!cmd) {
1372 err = -ENOMEM;
1373 goto unlock;
1374 }
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001375
1376unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001377 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001378 return err;
1379}
1380
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001381static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001382 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001383{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001384 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001385 struct pending_cmd *cmd;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001386 int err;
1387
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001388 BT_DBG("request for %s", hdev->name);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001389
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001390 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001391
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001392 if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001393 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001394 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001395 goto unlock;
1396 }
1397
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001398 hdev->major_class = cp->major;
1399 hdev->minor_class = cp->minor;
1400
Johan Hedberg932f5ff2012-02-22 22:11:32 +02001401 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001402 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001403 hdev->dev_class, 3);
Johan Hedberg932f5ff2012-02-22 22:11:32 +02001404 goto unlock;
1405 }
1406
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001407 if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02001408 hci_dev_unlock(hdev);
1409 cancel_delayed_work_sync(&hdev->service_cache);
1410 hci_dev_lock(hdev);
Johan Hedberg14c0b602011-12-15 00:47:37 +02001411 update_eir(hdev);
Johan Hedberg7d785252011-12-15 00:47:39 +02001412 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02001413
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001414 err = update_class(hdev);
Johan Hedberg90e70452012-02-23 23:09:40 +02001415 if (err < 0)
1416 goto unlock;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001417
Johan Hedberg90e70452012-02-23 23:09:40 +02001418 if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001419 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001420 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001421 goto unlock;
1422 }
1423
1424 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
1425 if (!cmd) {
1426 err = -ENOMEM;
1427 goto unlock;
1428 }
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001429
Johan Hedbergb5235a62012-02-21 14:32:24 +02001430unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001431 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001432 return err;
1433}
1434
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001435static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
1436 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001437{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001438 struct mgmt_cp_load_link_keys *cp = data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001439 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001440 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001441
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001442 key_count = get_unaligned_le16(&cp->key_count);
1443
Johan Hedberg86742e12011-11-07 23:13:38 +02001444 expected_len = sizeof(*cp) + key_count *
1445 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001446 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001447 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001448 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001449 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001450 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001451 }
1452
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001453 BT_DBG("%s debug_keys %u key_count %u", hdev->name, cp->debug_keys,
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001454 key_count);
1455
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001456 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001457
1458 hci_link_keys_clear(hdev);
1459
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001460 set_bit(HCI_LINK_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001461
1462 if (cp->debug_keys)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001463 set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001464 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001465 clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001466
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001467 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001468 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001469
Johan Hedbergd753fdc2012-02-17 14:06:34 +02001470 hci_add_link_key(hdev, NULL, 0, &key->addr.bdaddr, key->val,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001471 key->type, key->pin_len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001472 }
1473
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001474 cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02001475
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001476 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001477
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001478 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001479}
1480
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001481static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001482 u8 addr_type, struct sock *skip_sk)
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001483{
1484 struct mgmt_ev_device_unpaired ev;
1485
1486 bacpy(&ev.addr.bdaddr, bdaddr);
1487 ev.addr.type = addr_type;
1488
1489 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001490 skip_sk);
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001491}
1492
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001493static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001494 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001495{
Johan Hedberg124f6e32012-02-09 13:50:12 +02001496 struct mgmt_cp_unpair_device *cp = data;
1497 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001498 struct hci_cp_disconnect dc;
1499 struct pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001500 struct hci_conn *conn;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001501 int err;
1502
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001503 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001504
Johan Hedberga8a1d192011-11-10 15:54:38 +02001505 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02001506 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1507 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001508
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001509 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001510 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001511 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001512 goto unlock;
1513 }
1514
Johan Hedberg124f6e32012-02-09 13:50:12 +02001515 if (cp->addr.type == MGMT_ADDR_BREDR)
1516 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
1517 else
1518 err = hci_remove_ltk(hdev, &cp->addr.bdaddr);
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03001519
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001520 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001521 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001522 MGMT_STATUS_NOT_PAIRED, &rp, sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001523 goto unlock;
1524 }
1525
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001526 if (cp->disconnect) {
1527 if (cp->addr.type == MGMT_ADDR_BREDR)
1528 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
1529 &cp->addr.bdaddr);
1530 else
1531 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
1532 &cp->addr.bdaddr);
1533 } else {
1534 conn = NULL;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001535 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001536
Johan Hedberga8a1d192011-11-10 15:54:38 +02001537 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001538 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001539 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001540 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001541 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001542 }
1543
Johan Hedberg124f6e32012-02-09 13:50:12 +02001544 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001545 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02001546 if (!cmd) {
1547 err = -ENOMEM;
1548 goto unlock;
1549 }
1550
1551 put_unaligned_le16(conn->handle, &dc.handle);
1552 dc.reason = 0x13; /* Remote User Terminated Connection */
1553 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1554 if (err < 0)
1555 mgmt_pending_remove(cmd);
1556
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001557unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001558 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001559 return err;
1560}
1561
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001562static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001563 u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02001564{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001565 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001566 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03001567 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001568 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001569 int err;
1570
1571 BT_DBG("");
1572
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001573 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001574
1575 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001576 err = cmd_status(sk, hdev->id, MGMT_OP_DISCONNECT,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001577 MGMT_STATUS_NOT_POWERED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001578 goto failed;
1579 }
1580
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001581 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001582 err = cmd_status(sk, hdev->id, MGMT_OP_DISCONNECT,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001583 MGMT_STATUS_BUSY);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001584 goto failed;
1585 }
1586
Johan Hedberg88c3df12012-02-09 14:27:38 +02001587 if (cp->addr.type == MGMT_ADDR_BREDR)
1588 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
1589 else
1590 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03001591
Johan Hedberg8962ee72011-01-20 12:40:27 +02001592 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001593 err = cmd_status(sk, hdev->id, MGMT_OP_DISCONNECT,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001594 MGMT_STATUS_NOT_CONNECTED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001595 goto failed;
1596 }
1597
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001598 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001599 if (!cmd) {
1600 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001601 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001602 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001603
1604 put_unaligned_le16(conn->handle, &dc.handle);
1605 dc.reason = 0x13; /* Remote User Terminated Connection */
1606
1607 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1608 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001609 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001610
1611failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001612 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001613 return err;
1614}
1615
Johan Hedberg48264f02011-11-09 13:58:58 +02001616static u8 link_to_mgmt(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02001617{
1618 switch (link_type) {
1619 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02001620 switch (addr_type) {
1621 case ADDR_LE_DEV_PUBLIC:
1622 return MGMT_ADDR_LE_PUBLIC;
1623 case ADDR_LE_DEV_RANDOM:
1624 return MGMT_ADDR_LE_RANDOM;
1625 default:
1626 return MGMT_ADDR_INVALID;
1627 }
Johan Hedberg4c659c32011-11-07 23:13:39 +02001628 case ACL_LINK:
1629 return MGMT_ADDR_BREDR;
1630 default:
1631 return MGMT_ADDR_INVALID;
1632 }
1633}
1634
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001635static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data,
1636 u16 data_len)
Johan Hedberg2784eb42011-01-21 13:56:35 +02001637{
Johan Hedberg2784eb42011-01-21 13:56:35 +02001638 struct mgmt_rp_get_connections *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001639 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02001640 size_t rp_len;
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001641 int err;
1642 u16 i;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001643
1644 BT_DBG("");
1645
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001646 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001647
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001648 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001649 err = cmd_status(sk, hdev->id, MGMT_OP_GET_CONNECTIONS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001650 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001651 goto unlock;
1652 }
1653
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001654 i = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02001655 list_for_each_entry(c, &hdev->conn_hash.list, list) {
1656 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001657 i++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001658 }
1659
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001660 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberga38528f2011-01-22 06:46:43 +02001661 rp = kmalloc(rp_len, GFP_ATOMIC);
1662 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02001663 err = -ENOMEM;
1664 goto unlock;
1665 }
1666
Johan Hedberg2784eb42011-01-21 13:56:35 +02001667 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001668 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02001669 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
1670 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001671 bacpy(&rp->addr[i].bdaddr, &c->dst);
Johan Hedberg48264f02011-11-09 13:58:58 +02001672 rp->addr[i].type = link_to_mgmt(c->type, c->dst_type);
Johan Hedberg4c659c32011-11-07 23:13:39 +02001673 if (rp->addr[i].type == MGMT_ADDR_INVALID)
1674 continue;
1675 i++;
1676 }
1677
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001678 put_unaligned_le16(i, &rp->conn_count);
1679
Johan Hedberg4c659c32011-11-07 23:13:39 +02001680 /* Recalculate length in case of filtered SCO connections, etc */
1681 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02001682
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001683 err = cmd_complete(sk, hdev->id, MGMT_OP_GET_CONNECTIONS, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001684 rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001685
Johan Hedberga38528f2011-01-22 06:46:43 +02001686 kfree(rp);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001687
1688unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001689 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001690 return err;
1691}
1692
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001693static int send_pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001694 struct mgmt_cp_pin_code_neg_reply *cp)
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001695{
1696 struct pending_cmd *cmd;
1697 int err;
1698
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001699 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001700 sizeof(*cp));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001701 if (!cmd)
1702 return -ENOMEM;
1703
Johan Hedbergd8457692012-02-17 14:24:57 +02001704 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001705 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001706 if (err < 0)
1707 mgmt_pending_remove(cmd);
1708
1709 return err;
1710}
1711
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001712static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001713 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001714{
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001715 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001716 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001717 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03001718 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001719 int err;
1720
1721 BT_DBG("");
1722
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001723 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001724
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001725 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001726 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001727 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001728 goto failed;
1729 }
1730
Johan Hedbergd8457692012-02-17 14:24:57 +02001731 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001732 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001733 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001734 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001735 goto failed;
1736 }
1737
1738 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02001739 struct mgmt_cp_pin_code_neg_reply ncp;
1740
1741 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001742
1743 BT_ERR("PIN code is not 16 bytes long");
1744
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001745 err = send_pin_code_neg_reply(sk, hdev, &ncp);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001746 if (err >= 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001747 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001748 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001749
1750 goto failed;
1751 }
1752
Gustavo F. Padovan00abfe42012-03-01 00:37:10 -03001753 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001754 if (!cmd) {
1755 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001756 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001757 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02001758
Johan Hedbergd8457692012-02-17 14:24:57 +02001759 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001760 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02001761 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02001762
1763 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
1764 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001765 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001766
1767failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001768 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001769 return err;
1770}
1771
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001772static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001773 void *data, u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001774{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001775 struct mgmt_cp_pin_code_neg_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001776 int err;
1777
1778 BT_DBG("");
1779
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001780 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001781
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001782 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001783 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001784 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001785 goto failed;
1786 }
1787
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001788 err = send_pin_code_neg_reply(sk, hdev, cp);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001789
1790failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001791 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001792 return err;
1793}
1794
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001795static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,
1796 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001797{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001798 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001799
1800 BT_DBG("");
1801
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001802 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001803
1804 hdev->io_capability = cp->io_capability;
1805
1806 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Szymon Jancb8534e02011-03-01 16:55:34 +01001807 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001808
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001809 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001810
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001811 return cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, 0, NULL,
1812 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001813}
1814
Johan Hedberge9a416b2011-02-19 12:05:56 -03001815static inline struct pending_cmd *find_pairing(struct hci_conn *conn)
1816{
1817 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001818 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001819
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001820 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03001821 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
1822 continue;
1823
Johan Hedberge9a416b2011-02-19 12:05:56 -03001824 if (cmd->user_data != conn)
1825 continue;
1826
1827 return cmd;
1828 }
1829
1830 return NULL;
1831}
1832
1833static void pairing_complete(struct pending_cmd *cmd, u8 status)
1834{
1835 struct mgmt_rp_pair_device rp;
1836 struct hci_conn *conn = cmd->user_data;
1837
Johan Hedbergba4e5642011-11-11 00:07:34 +02001838 bacpy(&rp.addr.bdaddr, &conn->dst);
1839 rp.addr.type = link_to_mgmt(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001840
Johan Hedbergaee9b212012-02-18 15:07:59 +02001841 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001842 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001843
1844 /* So we don't get further callbacks for this connection */
1845 conn->connect_cfm_cb = NULL;
1846 conn->security_cfm_cb = NULL;
1847 conn->disconn_cfm_cb = NULL;
1848
1849 hci_conn_put(conn);
1850
Johan Hedberga664b5b2011-02-19 12:06:02 -03001851 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001852}
1853
1854static void pairing_complete_cb(struct hci_conn *conn, u8 status)
1855{
1856 struct pending_cmd *cmd;
1857
1858 BT_DBG("status %u", status);
1859
Johan Hedberg56e5cb82011-11-08 20:40:16 +02001860 cmd = find_pairing(conn);
1861 if (!cmd)
1862 BT_DBG("Unable to find a pending command");
1863 else
Johan Hedberge2113262012-02-18 15:20:03 +02001864 pairing_complete(cmd, mgmt_status(status));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001865}
1866
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001867static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001868 u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001869{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001870 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02001871 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001872 struct pending_cmd *cmd;
1873 u8 sec_level, auth_type;
1874 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001875 int err;
1876
1877 BT_DBG("");
1878
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001879 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001880
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001881 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001882 err = cmd_status(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001883 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001884 goto unlock;
1885 }
1886
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001887 sec_level = BT_SECURITY_MEDIUM;
1888 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001889 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001890 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03001891 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001892
Johan Hedbergba4e5642011-11-11 00:07:34 +02001893 if (cp->addr.type == MGMT_ADDR_BREDR)
1894 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr, sec_level,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001895 auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001896 else
Johan Hedbergba4e5642011-11-11 00:07:34 +02001897 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr, sec_level,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001898 auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001899
Johan Hedberg1425acb2011-11-11 00:07:35 +02001900 memset(&rp, 0, sizeof(rp));
1901 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1902 rp.addr.type = cp->addr.type;
1903
Ville Tervo30e76272011-02-22 16:10:53 -03001904 if (IS_ERR(conn)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001905 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001906 MGMT_STATUS_CONNECT_FAILED, &rp,
1907 sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001908 goto unlock;
1909 }
1910
1911 if (conn->connect_cfm_cb) {
1912 hci_conn_put(conn);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001913 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001914 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001915 goto unlock;
1916 }
1917
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001918 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001919 if (!cmd) {
1920 err = -ENOMEM;
1921 hci_conn_put(conn);
1922 goto unlock;
1923 }
1924
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001925 /* For LE, just connecting isn't a proof that the pairing finished */
Johan Hedbergba4e5642011-11-11 00:07:34 +02001926 if (cp->addr.type == MGMT_ADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001927 conn->connect_cfm_cb = pairing_complete_cb;
1928
Johan Hedberge9a416b2011-02-19 12:05:56 -03001929 conn->security_cfm_cb = pairing_complete_cb;
1930 conn->disconn_cfm_cb = pairing_complete_cb;
1931 conn->io_capability = cp->io_cap;
1932 cmd->user_data = conn;
1933
1934 if (conn->state == BT_CONNECTED &&
1935 hci_conn_security(conn, sec_level, auth_type))
1936 pairing_complete(cmd, 0);
1937
1938 err = 0;
1939
1940unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001941 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001942 return err;
1943}
1944
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001945static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
1946 u16 len)
Johan Hedberg28424702012-02-02 04:02:29 +02001947{
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02001948 struct mgmt_addr_info *addr = data;
Johan Hedberg28424702012-02-02 04:02:29 +02001949 struct pending_cmd *cmd;
1950 struct hci_conn *conn;
1951 int err;
1952
1953 BT_DBG("");
1954
Johan Hedberg28424702012-02-02 04:02:29 +02001955 hci_dev_lock(hdev);
1956
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001957 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001958 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001959 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001960 goto unlock;
1961 }
1962
Johan Hedberg28424702012-02-02 04:02:29 +02001963 cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
1964 if (!cmd) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001965 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001966 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02001967 goto unlock;
1968 }
1969
1970 conn = cmd->user_data;
1971
1972 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001973 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001974 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02001975 goto unlock;
1976 }
1977
1978 pairing_complete(cmd, MGMT_STATUS_CANCELLED);
1979
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001980 err = cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001981 addr, sizeof(*addr));
Johan Hedberg28424702012-02-02 04:02:29 +02001982unlock:
1983 hci_dev_unlock(hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02001984 return err;
1985}
1986
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001987static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001988 bdaddr_t *bdaddr, u8 type, u16 mgmt_op,
1989 u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03001990{
Johan Hedberga5c29682011-02-19 12:05:57 -03001991 struct pending_cmd *cmd;
Brian Gix0df4c182011-11-16 13:53:13 -08001992 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03001993 int err;
1994
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001995 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02001996
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001997 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001998 err = cmd_status(sk, hdev->id, mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001999 MGMT_STATUS_NOT_POWERED);
Brian Gix0df4c182011-11-16 13:53:13 -08002000 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002001 }
2002
Johan Hedberg272d90d2012-02-09 15:26:12 +02002003 if (type == MGMT_ADDR_BREDR)
2004 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, bdaddr);
2005 else
Brian Gix47c15e22011-11-16 13:53:14 -08002006 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, bdaddr);
Brian Gix47c15e22011-11-16 13:53:14 -08002007
Johan Hedberg272d90d2012-02-09 15:26:12 +02002008 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002009 err = cmd_status(sk, hdev->id, mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002010 MGMT_STATUS_NOT_CONNECTED);
Johan Hedberg272d90d2012-02-09 15:26:12 +02002011 goto done;
2012 }
2013
2014 if (type == MGMT_ADDR_LE_PUBLIC || type == MGMT_ADDR_LE_RANDOM) {
Brian Gix47c15e22011-11-16 13:53:14 -08002015 /* Continue with pairing via SMP */
Brian Gix5fe57d92011-12-21 16:12:13 -08002016 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix47c15e22011-11-16 13:53:14 -08002017
Brian Gix5fe57d92011-12-21 16:12:13 -08002018 if (!err)
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002019 err = cmd_status(sk, hdev->id, mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002020 MGMT_STATUS_SUCCESS);
Brian Gix5fe57d92011-12-21 16:12:13 -08002021 else
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002022 err = cmd_status(sk, hdev->id, mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002023 MGMT_STATUS_FAILED);
Brian Gix5fe57d92011-12-21 16:12:13 -08002024
Brian Gix47c15e22011-11-16 13:53:14 -08002025 goto done;
2026 }
2027
Brian Gix0df4c182011-11-16 13:53:13 -08002028 cmd = mgmt_pending_add(sk, mgmt_op, hdev, bdaddr, sizeof(*bdaddr));
Johan Hedberga5c29682011-02-19 12:05:57 -03002029 if (!cmd) {
2030 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08002031 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002032 }
2033
Brian Gix0df4c182011-11-16 13:53:13 -08002034 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08002035 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
2036 struct hci_cp_user_passkey_reply cp;
2037
2038 bacpy(&cp.bdaddr, bdaddr);
2039 cp.passkey = passkey;
2040 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
2041 } else
2042 err = hci_send_cmd(hdev, hci_op, sizeof(*bdaddr), bdaddr);
2043
Johan Hedberga664b5b2011-02-19 12:06:02 -03002044 if (err < 0)
2045 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002046
Brian Gix0df4c182011-11-16 13:53:13 -08002047done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002048 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002049 return err;
2050}
2051
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002052static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2053 u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002054{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002055 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002056
2057 BT_DBG("");
2058
2059 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002060 return cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002061 MGMT_STATUS_INVALID_PARAMS);
Brian Gix0df4c182011-11-16 13:53:13 -08002062
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002063 return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002064 MGMT_OP_USER_CONFIRM_REPLY,
2065 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002066}
2067
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002068static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002069 void *data, u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002070{
Johan Hedbergc9c26592011-12-15 00:47:41 +02002071 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002072
2073 BT_DBG("");
2074
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002075 return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002076 MGMT_OP_USER_CONFIRM_NEG_REPLY,
2077 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002078}
2079
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002080static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2081 u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002082{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002083 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002084
2085 BT_DBG("");
2086
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002087 return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002088 MGMT_OP_USER_PASSKEY_REPLY,
2089 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08002090}
2091
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002092static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002093 void *data, u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002094{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002095 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002096
2097 BT_DBG("");
2098
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002099 return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002100 MGMT_OP_USER_PASSKEY_NEG_REPLY,
2101 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08002102}
2103
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002104static int update_name(struct hci_dev *hdev, const char *name)
2105{
2106 struct hci_cp_write_local_name cp;
2107
2108 memcpy(cp.name, name, sizeof(cp.name));
2109
2110 return hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(cp), &cp);
2111}
2112
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002113static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002114 u16 len)
Johan Hedbergb312b1612011-03-16 14:29:37 +02002115{
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002116 struct mgmt_cp_set_local_name *cp = data;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002117 struct pending_cmd *cmd;
2118 int err;
2119
2120 BT_DBG("");
2121
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002122 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002123
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002124 memcpy(hdev->short_name, cp->short_name, sizeof(hdev->short_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002125
Johan Hedbergb5235a62012-02-21 14:32:24 +02002126 if (!hdev_is_powered(hdev)) {
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002127 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002128
2129 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002130 data, len);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002131 if (err < 0)
2132 goto failed;
2133
2134 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data, len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002135 sk);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002136
Johan Hedbergb5235a62012-02-21 14:32:24 +02002137 goto failed;
2138 }
2139
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002140 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002141 if (!cmd) {
2142 err = -ENOMEM;
2143 goto failed;
2144 }
2145
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002146 err = update_name(hdev, cp->name);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002147 if (err < 0)
2148 mgmt_pending_remove(cmd);
2149
2150failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002151 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002152 return err;
2153}
2154
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002155static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002156 void *data, u16 data_len)
Szymon Jancc35938b2011-03-22 13:12:21 +01002157{
Szymon Jancc35938b2011-03-22 13:12:21 +01002158 struct pending_cmd *cmd;
2159 int err;
2160
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002161 BT_DBG("%s", hdev->name);
Szymon Jancc35938b2011-03-22 13:12:21 +01002162
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002163 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002164
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002165 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002166 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002167 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002168 goto unlock;
2169 }
2170
2171 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002172 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002173 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002174 goto unlock;
2175 }
2176
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002177 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002178 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002179 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01002180 goto unlock;
2181 }
2182
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002183 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01002184 if (!cmd) {
2185 err = -ENOMEM;
2186 goto unlock;
2187 }
2188
2189 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
2190 if (err < 0)
2191 mgmt_pending_remove(cmd);
2192
2193unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002194 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002195 return err;
2196}
2197
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002198static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002199 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002200{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002201 struct mgmt_cp_add_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002202 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002203 int err;
2204
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002205 BT_DBG("%s ", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01002206
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002207 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002208
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002209 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002210 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002211 MGMT_STATUS_NOT_POWERED, &cp->addr,
2212 sizeof(cp->addr));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002213 goto unlock;
2214 }
2215
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002216 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, cp->hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002217 cp->randomizer);
Szymon Janc2763eda2011-03-22 13:12:22 +01002218 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002219 status = MGMT_STATUS_FAILED;
Szymon Janc2763eda2011-03-22 13:12:22 +01002220 else
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002221 status = 0;
2222
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002223 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002224 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002225
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002226unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002227 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002228 return err;
2229}
2230
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002231static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002232 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002233{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002234 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002235 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002236 int err;
2237
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002238 BT_DBG("%s", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01002239
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002240 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002241
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002242 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002243 err = cmd_complete(sk, hdev->id,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002244 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2245 MGMT_STATUS_NOT_POWERED, &cp->addr,
2246 sizeof(cp->addr));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002247 goto unlock;
2248 }
2249
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002250 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr);
Szymon Janc2763eda2011-03-22 13:12:22 +01002251 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002252 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01002253 else
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002254 status = 0;
2255
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002256 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002257 status, &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002258
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002259unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002260 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002261 return err;
2262}
2263
Andre Guedes5e0452c2012-02-17 20:39:38 -03002264int mgmt_interleaved_discovery(struct hci_dev *hdev)
2265{
2266 int err;
2267
2268 BT_DBG("%s", hdev->name);
2269
2270 hci_dev_lock(hdev);
2271
2272 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR_LE);
2273 if (err < 0)
2274 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2275
2276 hci_dev_unlock(hdev);
2277
2278 return err;
2279}
2280
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002281static int start_discovery(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002282 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002283{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002284 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002285 struct pending_cmd *cmd;
Johan Hedberg14a53662011-04-27 10:29:56 -04002286 int err;
2287
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002288 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04002289
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002290 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002291
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002292 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002293 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002294 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02002295 goto failed;
2296 }
2297
Johan Hedbergff9ef572012-01-04 14:23:45 +02002298 if (hdev->discovery.state != DISCOVERY_STOPPED) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002299 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002300 MGMT_STATUS_BUSY);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002301 goto failed;
2302 }
2303
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002304 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002305 if (!cmd) {
2306 err = -ENOMEM;
2307 goto failed;
2308 }
2309
Andre Guedes4aab14e2012-02-17 20:39:36 -03002310 hdev->discovery.type = cp->type;
2311
2312 switch (hdev->discovery.type) {
Andre Guedesf39799f2012-02-17 20:39:35 -03002313 case DISCOV_TYPE_BREDR:
Andre Guedes8b901292012-02-23 18:09:27 -03002314 if (lmp_bredr_capable(hdev))
2315 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
2316 else
2317 err = -ENOTSUPP;
Andre Guedesf39799f2012-02-17 20:39:35 -03002318 break;
2319
2320 case DISCOV_TYPE_LE:
Andre Guedes8b901292012-02-23 18:09:27 -03002321 if (lmp_host_le_capable(hdev))
2322 err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002323 LE_SCAN_WIN, LE_SCAN_TIMEOUT_LE_ONLY);
Andre Guedes8b901292012-02-23 18:09:27 -03002324 else
2325 err = -ENOTSUPP;
Andre Guedesf39799f2012-02-17 20:39:35 -03002326 break;
2327
Andre Guedes5e0452c2012-02-17 20:39:38 -03002328 case DISCOV_TYPE_INTERLEAVED:
Andre Guedes426c1892012-02-24 11:41:04 -03002329 if (lmp_host_le_capable(hdev) && lmp_bredr_capable(hdev))
2330 err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002331 LE_SCAN_WIN,
2332 LE_SCAN_TIMEOUT_BREDR_LE);
Andre Guedes426c1892012-02-24 11:41:04 -03002333 else
2334 err = -ENOTSUPP;
Andre Guedes5e0452c2012-02-17 20:39:38 -03002335 break;
2336
Andre Guedesf39799f2012-02-17 20:39:35 -03002337 default:
Andre Guedes3fd24152012-02-03 17:48:01 -03002338 err = -EINVAL;
Andre Guedesf39799f2012-02-17 20:39:35 -03002339 }
Andre Guedes3fd24152012-02-03 17:48:01 -03002340
Johan Hedberg14a53662011-04-27 10:29:56 -04002341 if (err < 0)
2342 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002343 else
2344 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002345
2346failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002347 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002348 return err;
2349}
2350
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002351static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002352 u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002353{
Johan Hedbergd9306502012-02-20 23:25:18 +02002354 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002355 struct pending_cmd *cmd;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002356 struct hci_cp_remote_name_req_cancel cp;
2357 struct inquiry_entry *e;
Johan Hedberg14a53662011-04-27 10:29:56 -04002358 int err;
2359
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002360 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04002361
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002362 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002363
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002364 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002365 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002366 MGMT_STATUS_REJECTED, &mgmt_cp->type,
2367 sizeof(mgmt_cp->type));
Johan Hedbergd9306502012-02-20 23:25:18 +02002368 goto unlock;
2369 }
2370
2371 if (hdev->discovery.type != mgmt_cp->type) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002372 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002373 MGMT_STATUS_INVALID_PARAMS, &mgmt_cp->type,
2374 sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002375 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02002376 }
2377
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002378 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002379 if (!cmd) {
2380 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002381 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04002382 }
2383
Andre Guedes343f9352012-02-17 20:39:37 -03002384 if (hdev->discovery.state == DISCOVERY_FINDING) {
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002385 err = hci_cancel_inquiry(hdev);
2386 if (err < 0)
2387 mgmt_pending_remove(cmd);
2388 else
2389 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
2390 goto unlock;
2391 }
2392
2393 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY, NAME_PENDING);
2394 if (!e) {
2395 mgmt_pending_remove(cmd);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002396 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002397 &mgmt_cp->type, sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002398 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2399 goto unlock;
2400 }
2401
2402 bacpy(&cp.bdaddr, &e->data.bdaddr);
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002403 err = hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ_CANCEL, sizeof(cp),
2404 &cp);
Johan Hedberg14a53662011-04-27 10:29:56 -04002405 if (err < 0)
2406 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002407 else
2408 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002409
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002410unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002411 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002412 return err;
2413}
2414
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002415static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002416 u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02002417{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002418 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002419 struct inquiry_entry *e;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002420 int err;
2421
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002422 BT_DBG("%s", hdev->name);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002423
Johan Hedberg561aafb2012-01-04 13:31:59 +02002424 hci_dev_lock(hdev);
2425
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002426 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002427 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002428 MGMT_STATUS_FAILED);
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002429 goto failed;
2430 }
2431
Johan Hedberga198e7b2012-02-17 14:27:06 +02002432 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002433 if (!e) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002434 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002435 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002436 goto failed;
2437 }
2438
2439 if (cp->name_known) {
2440 e->name_state = NAME_KNOWN;
2441 list_del(&e->list);
2442 } else {
2443 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e202012-01-09 00:53:02 +02002444 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002445 }
2446
2447 err = 0;
2448
2449failed:
2450 hci_dev_unlock(hdev);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002451 return err;
2452}
2453
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002454static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002455 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002456{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002457 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002458 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03002459 int err;
2460
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002461 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03002462
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002463 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002464
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002465 err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002466 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002467 status = MGMT_STATUS_FAILED;
Antti Julku7fbec222011-06-15 12:01:15 +03002468 else
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002469 status = 0;
2470
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002471 err = cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002472 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03002473
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002474 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002475
2476 return err;
2477}
2478
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002479static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002480 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002481{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002482 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002483 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03002484 int err;
2485
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002486 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03002487
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002488 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002489
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002490 err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002491 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002492 status = MGMT_STATUS_INVALID_PARAMS;
Antti Julku7fbec222011-06-15 12:01:15 +03002493 else
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002494 status = 0;
2495
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002496 err = cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002497 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03002498
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002499 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002500
2501 return err;
2502}
2503
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002504static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002505 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03002506{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002507 struct mgmt_mode *cp = data;
Antti Julkuf6422ec2011-06-22 13:11:56 +03002508 struct hci_cp_write_page_scan_activity acp;
2509 u8 type;
2510 int err;
2511
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002512 BT_DBG("%s", hdev->name);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002513
Johan Hedberg5400c042012-02-21 16:40:33 +02002514 if (!hdev_is_powered(hdev))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002515 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002516 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5400c042012-02-21 16:40:33 +02002517
2518 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002519 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002520 MGMT_STATUS_REJECTED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002521
2522 hci_dev_lock(hdev);
2523
Johan Hedbergf7c6869ce2011-12-15 00:47:36 +02002524 if (cp->val) {
Antti Julkuf6422ec2011-06-22 13:11:56 +03002525 type = PAGE_SCAN_TYPE_INTERLACED;
2526 acp.interval = 0x0024; /* 22.5 msec page scan interval */
2527 } else {
2528 type = PAGE_SCAN_TYPE_STANDARD; /* default */
2529 acp.interval = 0x0800; /* default 1.28 sec page scan */
2530 }
2531
2532 acp.window = 0x0012; /* default 11.25 msec page scan window */
2533
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002534 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY, sizeof(acp),
2535 &acp);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002536 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002537 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002538 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002539 goto done;
2540 }
2541
2542 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
2543 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002544 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002545 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002546 goto done;
2547 }
2548
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002549 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002550 NULL, 0);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002551done:
2552 hci_dev_unlock(hdev);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002553 return err;
2554}
2555
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002556static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002557 void *cp_data, u16 len)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002558{
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002559 struct mgmt_cp_load_long_term_keys *cp = cp_data;
2560 u16 key_count, expected_len;
2561 int i;
2562
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002563 key_count = get_unaligned_le16(&cp->key_count);
2564
2565 expected_len = sizeof(*cp) + key_count *
2566 sizeof(struct mgmt_ltk_info);
2567 if (expected_len != len) {
2568 BT_ERR("load_keys: expected %u bytes, got %u bytes",
2569 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002570 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002571 EINVAL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002572 }
2573
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002574 BT_DBG("%s key_count %u", hdev->name, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002575
2576 hci_dev_lock(hdev);
2577
2578 hci_smp_ltks_clear(hdev);
2579
2580 for (i = 0; i < key_count; i++) {
2581 struct mgmt_ltk_info *key = &cp->keys[i];
2582 u8 type;
2583
2584 if (key->master)
2585 type = HCI_SMP_LTK;
2586 else
2587 type = HCI_SMP_LTK_SLAVE;
2588
2589 hci_add_ltk(hdev, &key->addr.bdaddr, key->addr.type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002590 type, 0, key->authenticated, key->val,
2591 key->enc_size, key->ediv, key->rand);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002592 }
2593
2594 hci_dev_unlock(hdev);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002595
2596 return 0;
2597}
2598
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002599struct mgmt_handler {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002600 int (*func) (struct sock *sk, struct hci_dev *hdev, void *data,
2601 u16 data_len);
Johan Hedbergbe22b542012-03-01 22:24:41 +02002602 bool var_len;
2603 size_t data_len;
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002604} mgmt_handlers[] = {
2605 { NULL }, /* 0x0000 (no command) */
Johan Hedbergbe22b542012-03-01 22:24:41 +02002606 { read_version, false, MGMT_READ_VERSION_SIZE },
2607 { read_commands, false, MGMT_READ_COMMANDS_SIZE },
2608 { read_index_list, false, MGMT_READ_INDEX_LIST_SIZE },
2609 { read_controller_info, false, MGMT_READ_INFO_SIZE },
2610 { set_powered, false, MGMT_SETTING_SIZE },
2611 { set_discoverable, false, MGMT_SET_DISCOVERABLE_SIZE },
2612 { set_connectable, false, MGMT_SETTING_SIZE },
2613 { set_fast_connectable, false, MGMT_SETTING_SIZE },
2614 { set_pairable, false, MGMT_SETTING_SIZE },
2615 { set_link_security, false, MGMT_SETTING_SIZE },
2616 { set_ssp, false, MGMT_SETTING_SIZE },
2617 { set_hs, false, MGMT_SETTING_SIZE },
2618 { set_le, false, MGMT_SETTING_SIZE },
2619 { set_dev_class, false, MGMT_SET_DEV_CLASS_SIZE },
2620 { set_local_name, false, MGMT_SET_LOCAL_NAME_SIZE },
2621 { add_uuid, false, MGMT_ADD_UUID_SIZE },
2622 { remove_uuid, false, MGMT_REMOVE_UUID_SIZE },
2623 { load_link_keys, true, MGMT_LOAD_LINK_KEYS_SIZE },
2624 { load_long_term_keys, true, MGMT_LOAD_LONG_TERM_KEYS_SIZE },
2625 { disconnect, false, MGMT_DISCONNECT_SIZE },
2626 { get_connections, false, MGMT_GET_CONNECTIONS_SIZE },
2627 { pin_code_reply, false, MGMT_PIN_CODE_REPLY_SIZE },
2628 { pin_code_neg_reply, false, MGMT_PIN_CODE_NEG_REPLY_SIZE },
2629 { set_io_capability, false, MGMT_SET_IO_CAPABILITY_SIZE },
2630 { pair_device, false, MGMT_PAIR_DEVICE_SIZE },
2631 { cancel_pair_device, false, MGMT_CANCEL_PAIR_DEVICE_SIZE },
2632 { unpair_device, false, MGMT_UNPAIR_DEVICE_SIZE },
2633 { user_confirm_reply, false, MGMT_USER_CONFIRM_REPLY_SIZE },
2634 { user_confirm_neg_reply, false, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
2635 { user_passkey_reply, false, MGMT_USER_PASSKEY_REPLY_SIZE },
2636 { user_passkey_neg_reply, false, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
2637 { read_local_oob_data, false, MGMT_READ_LOCAL_OOB_DATA_SIZE },
2638 { add_remote_oob_data, false, MGMT_ADD_REMOTE_OOB_DATA_SIZE },
2639 { remove_remote_oob_data, false, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
2640 { start_discovery, false, MGMT_START_DISCOVERY_SIZE },
2641 { stop_discovery, false, MGMT_STOP_DISCOVERY_SIZE },
2642 { confirm_name, false, MGMT_CONFIRM_NAME_SIZE },
2643 { block_device, false, MGMT_BLOCK_DEVICE_SIZE },
2644 { unblock_device, false, MGMT_UNBLOCK_DEVICE_SIZE },
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002645};
2646
2647
Johan Hedberg03811012010-12-08 00:21:06 +02002648int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
2649{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002650 void *buf;
2651 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02002652 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002653 u16 opcode, index, len;
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002654 struct hci_dev *hdev = NULL;
Johan Hedbergbe22b542012-03-01 22:24:41 +02002655 struct mgmt_handler *handler;
Johan Hedberg03811012010-12-08 00:21:06 +02002656 int err;
2657
2658 BT_DBG("got %zu bytes", msglen);
2659
2660 if (msglen < sizeof(*hdr))
2661 return -EINVAL;
2662
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03002663 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02002664 if (!buf)
2665 return -ENOMEM;
2666
2667 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
2668 err = -EFAULT;
2669 goto done;
2670 }
2671
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002672 hdr = buf;
Johan Hedberg03811012010-12-08 00:21:06 +02002673 opcode = get_unaligned_le16(&hdr->opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002674 index = get_unaligned_le16(&hdr->index);
Johan Hedberg03811012010-12-08 00:21:06 +02002675 len = get_unaligned_le16(&hdr->len);
2676
2677 if (len != msglen - sizeof(*hdr)) {
2678 err = -EINVAL;
2679 goto done;
2680 }
2681
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002682 if (index != MGMT_INDEX_NONE) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002683 hdev = hci_dev_get(index);
2684 if (!hdev) {
2685 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002686 MGMT_STATUS_INVALID_INDEX);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002687 goto done;
2688 }
2689 }
2690
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002691 if (opcode >= ARRAY_SIZE(mgmt_handlers) ||
2692 mgmt_handlers[opcode].func == NULL) {
Johan Hedberg03811012010-12-08 00:21:06 +02002693 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02002694 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002695 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002696 goto done;
Johan Hedberg03811012010-12-08 00:21:06 +02002697 }
2698
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002699 if ((hdev && opcode < MGMT_OP_READ_INFO) ||
2700 (!hdev && opcode >= MGMT_OP_READ_INFO)) {
2701 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002702 MGMT_STATUS_INVALID_INDEX);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002703 goto done;
2704 }
2705
Johan Hedbergbe22b542012-03-01 22:24:41 +02002706 handler = &mgmt_handlers[opcode];
2707
2708 if ((handler->var_len && len < handler->data_len) ||
2709 (!handler->var_len && len != handler->data_len)) {
2710 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002711 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergbe22b542012-03-01 22:24:41 +02002712 goto done;
2713 }
2714
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002715 if (hdev)
2716 mgmt_init_hdev(sk, hdev);
2717
2718 cp = buf + sizeof(*hdr);
2719
Johan Hedbergbe22b542012-03-01 22:24:41 +02002720 err = handler->func(sk, hdev, cp, len);
Johan Hedberge41d8b42010-12-13 21:07:03 +02002721 if (err < 0)
2722 goto done;
2723
Johan Hedberg03811012010-12-08 00:21:06 +02002724 err = msglen;
2725
2726done:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002727 if (hdev)
2728 hci_dev_put(hdev);
2729
Johan Hedberg03811012010-12-08 00:21:06 +02002730 kfree(buf);
2731 return err;
2732}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002733
Johan Hedbergb24752f2011-11-03 14:40:33 +02002734static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
2735{
2736 u8 *status = data;
2737
2738 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
2739 mgmt_pending_remove(cmd);
2740}
2741
Johan Hedberg744cf192011-11-08 20:40:14 +02002742int mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002743{
Johan Hedberg744cf192011-11-08 20:40:14 +02002744 return mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002745}
2746
Johan Hedberg744cf192011-11-08 20:40:14 +02002747int mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002748{
Johan Hedberg5f159032012-03-02 03:13:19 +02002749 u8 status = MGMT_STATUS_INVALID_INDEX;
Johan Hedbergb24752f2011-11-03 14:40:33 +02002750
Johan Hedberg744cf192011-11-08 20:40:14 +02002751 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002752
Johan Hedberg744cf192011-11-08 20:40:14 +02002753 return mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002754}
2755
Johan Hedberg73f22f62010-12-29 16:00:25 +02002756struct cmd_lookup {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002757 struct sock *sk;
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002758 struct hci_dev *hdev;
Johan Hedberg90e70452012-02-23 23:09:40 +02002759 u8 mgmt_status;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002760};
2761
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002762static void settings_rsp(struct pending_cmd *cmd, void *data)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002763{
Johan Hedberg73f22f62010-12-29 16:00:25 +02002764 struct cmd_lookup *match = data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002765
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002766 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002767
2768 list_del(&cmd->list);
2769
2770 if (match->sk == NULL) {
2771 match->sk = cmd->sk;
2772 sock_hold(match->sk);
2773 }
2774
2775 mgmt_pending_free(cmd);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002776}
Johan Hedberg5add6af2010-12-16 10:00:37 +02002777
Johan Hedberg744cf192011-11-08 20:40:14 +02002778int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg5add6af2010-12-16 10:00:37 +02002779{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002780 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002781 int err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002782
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002783 if (!test_bit(HCI_MGMT, &hdev->dev_flags))
2784 return 0;
2785
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002786 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
Johan Hedberg5add6af2010-12-16 10:00:37 +02002787
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002788 if (powered) {
2789 u8 scan = 0;
2790
2791 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
2792 scan |= SCAN_PAGE;
2793 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
2794 scan |= SCAN_INQUIRY;
2795
2796 if (scan)
2797 hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
Johan Hedberg504c8dc2012-02-23 13:30:41 +02002798
2799 update_class(hdev);
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002800 update_name(hdev, hdev->dev_name);
Johan Hedberg504c8dc2012-02-23 13:30:41 +02002801 update_eir(hdev);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002802 } else {
Johan Hedbergd4f68522012-03-02 03:07:07 +02002803 u8 status = MGMT_STATUS_NOT_POWERED;
Johan Hedberg744cf192011-11-08 20:40:14 +02002804 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002805 }
2806
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02002807 err = new_settings(hdev, match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002808
2809 if (match.sk)
2810 sock_put(match.sk);
2811
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002812 return err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002813}
Johan Hedberg73f22f62010-12-29 16:00:25 +02002814
Johan Hedberg744cf192011-11-08 20:40:14 +02002815int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg73f22f62010-12-29 16:00:25 +02002816{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002817 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002818 bool changed = false;
2819 int err = 0;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002820
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002821 if (discoverable) {
2822 if (!test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
2823 changed = true;
2824 } else {
2825 if (test_and_clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
2826 changed = true;
2827 }
Johan Hedberg73f22f62010-12-29 16:00:25 +02002828
Johan Hedberged9b5f22012-02-21 20:47:06 +02002829 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002830 &match);
Johan Hedberged9b5f22012-02-21 20:47:06 +02002831
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02002832 if (changed)
2833 err = new_settings(hdev, match.sk);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002834
Johan Hedberg73f22f62010-12-29 16:00:25 +02002835 if (match.sk)
2836 sock_put(match.sk);
2837
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002838 return err;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002839}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002840
Johan Hedberg744cf192011-11-08 20:40:14 +02002841int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002842{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002843 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002844 bool changed = false;
2845 int err = 0;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002846
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002847 if (connectable) {
2848 if (!test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags))
2849 changed = true;
2850 } else {
2851 if (test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags))
2852 changed = true;
2853 }
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002854
Johan Hedberged9b5f22012-02-21 20:47:06 +02002855 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002856 &match);
Johan Hedberged9b5f22012-02-21 20:47:06 +02002857
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02002858 if (changed)
2859 err = new_settings(hdev, match.sk);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002860
2861 if (match.sk)
2862 sock_put(match.sk);
2863
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002864 return err;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002865}
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002866
Johan Hedberg744cf192011-11-08 20:40:14 +02002867int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002868{
Johan Hedbergca69b792011-11-11 18:10:00 +02002869 u8 mgmt_err = mgmt_status(status);
2870
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002871 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02002872 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002873 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002874
2875 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02002876 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002877 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002878
2879 return 0;
2880}
2881
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002882int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key, u8 persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002883{
Johan Hedberg86742e12011-11-07 23:13:38 +02002884 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002885
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002886 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002887
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002888 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02002889 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
2890 ev.key.addr.type = MGMT_ADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002891 ev.key.type = key->type;
2892 memcpy(ev.key.val, key->val, 16);
2893 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002894
Johan Hedberg744cf192011-11-08 20:40:14 +02002895 return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002896}
Johan Hedbergf7520542011-01-20 12:34:39 +02002897
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002898int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
2899{
2900 struct mgmt_ev_new_long_term_key ev;
2901
2902 memset(&ev, 0, sizeof(ev));
2903
2904 ev.store_hint = persistent;
2905 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
2906 ev.key.addr.type = key->bdaddr_type;
2907 ev.key.authenticated = key->authenticated;
2908 ev.key.enc_size = key->enc_size;
2909 ev.key.ediv = key->ediv;
2910
2911 if (key->type == HCI_SMP_LTK)
2912 ev.key.master = 1;
2913
2914 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
2915 memcpy(ev.key.val, key->val, sizeof(key->val));
2916
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002917 return mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev),
2918 NULL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002919}
2920
Johan Hedbergafc747a2012-01-15 18:11:07 +02002921int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002922 u8 addr_type, u32 flags, u8 *name, u8 name_len,
2923 u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02002924{
Johan Hedbergb644ba32012-01-17 21:48:47 +02002925 char buf[512];
2926 struct mgmt_ev_device_connected *ev = (void *) buf;
2927 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02002928
Johan Hedbergb644ba32012-01-17 21:48:47 +02002929 bacpy(&ev->addr.bdaddr, bdaddr);
2930 ev->addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02002931
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02002932 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02002933
Johan Hedbergb644ba32012-01-17 21:48:47 +02002934 if (name_len > 0)
2935 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002936 name, name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02002937
2938 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
Brian Gix53156382012-03-09 14:07:03 -08002939 eir_len = eir_append_data(ev->eir, eir_len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002940 EIR_CLASS_OF_DEV, dev_class, 3);
Johan Hedbergb644ba32012-01-17 21:48:47 +02002941
2942 put_unaligned_le16(eir_len, &ev->eir_len);
2943
2944 return mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002945 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02002946}
2947
Johan Hedberg8962ee72011-01-20 12:40:27 +02002948static void disconnect_rsp(struct pending_cmd *cmd, void *data)
2949{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01002950 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002951 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02002952 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002953
Johan Hedberg88c3df12012-02-09 14:27:38 +02002954 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2955 rp.addr.type = cp->addr.type;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002956
Johan Hedbergaee9b212012-02-18 15:07:59 +02002957 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002958 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002959
2960 *sk = cmd->sk;
2961 sock_hold(*sk);
2962
Johan Hedberga664b5b2011-02-19 12:06:02 -03002963 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002964}
2965
Johan Hedberg124f6e32012-02-09 13:50:12 +02002966static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02002967{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002968 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02002969 struct mgmt_cp_unpair_device *cp = cmd->param;
2970 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002971
2972 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02002973 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2974 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002975
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002976 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
2977
Johan Hedbergaee9b212012-02-18 15:07:59 +02002978 cmd_complete(cmd->sk, cmd->index, cmd->opcode, 0, &rp, sizeof(rp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02002979
2980 mgmt_pending_remove(cmd);
2981}
2982
Johan Hedbergafc747a2012-01-15 18:11:07 +02002983int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002984 u8 link_type, u8 addr_type)
Johan Hedbergf7520542011-01-20 12:34:39 +02002985{
Johan Hedberg4c659c32011-11-07 23:13:39 +02002986 struct mgmt_addr_info ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002987 struct sock *sk = NULL;
2988 int err;
2989
Johan Hedberg744cf192011-11-08 20:40:14 +02002990 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02002991
Johan Hedbergf7520542011-01-20 12:34:39 +02002992 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02002993 ev.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02002994
Johan Hedbergafc747a2012-01-15 18:11:07 +02002995 err = mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002996 sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002997
2998 if (sk)
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002999 sock_put(sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003000
Johan Hedberg124f6e32012-02-09 13:50:12 +02003001 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003002 hdev);
Johan Hedberga8a1d192011-11-10 15:54:38 +02003003
Johan Hedberg8962ee72011-01-20 12:40:27 +02003004 return err;
3005}
3006
Johan Hedberg88c3df12012-02-09 14:27:38 +02003007int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003008 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02003009{
Johan Hedberg88c3df12012-02-09 14:27:38 +02003010 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003011 struct pending_cmd *cmd;
3012 int err;
3013
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003014 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003015 if (!cmd)
3016 return -ENOENT;
3017
Johan Hedberg88c3df12012-02-09 14:27:38 +02003018 bacpy(&rp.addr.bdaddr, bdaddr);
3019 rp.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02003020
Johan Hedberg88c3df12012-02-09 14:27:38 +02003021 err = cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003022 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003023
Johan Hedberga664b5b2011-02-19 12:06:02 -03003024 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003025
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003026 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
3027 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003028 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02003029}
Johan Hedberg17d5c042011-01-22 06:09:08 +02003030
Johan Hedberg48264f02011-11-09 13:58:58 +02003031int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003032 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02003033{
3034 struct mgmt_ev_connect_failed ev;
3035
Johan Hedberg4c659c32011-11-07 23:13:39 +02003036 bacpy(&ev.addr.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02003037 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003038 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003039
Johan Hedberg744cf192011-11-08 20:40:14 +02003040 return mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003041}
Johan Hedberg980e1a52011-01-22 06:10:07 +02003042
Johan Hedberg744cf192011-11-08 20:40:14 +02003043int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003044{
3045 struct mgmt_ev_pin_code_request ev;
3046
Johan Hedbergd8457692012-02-17 14:24:57 +02003047 bacpy(&ev.addr.bdaddr, bdaddr);
3048 ev.addr.type = MGMT_ADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02003049 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003050
Johan Hedberg744cf192011-11-08 20:40:14 +02003051 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003052 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003053}
3054
Johan Hedberg744cf192011-11-08 20:40:14 +02003055int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003056 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003057{
3058 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003059 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003060 int err;
3061
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003062 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003063 if (!cmd)
3064 return -ENOENT;
3065
Johan Hedbergd8457692012-02-17 14:24:57 +02003066 bacpy(&rp.addr.bdaddr, bdaddr);
3067 rp.addr.type = MGMT_ADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003068
Johan Hedbergaee9b212012-02-18 15:07:59 +02003069 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003070 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003071
Johan Hedberga664b5b2011-02-19 12:06:02 -03003072 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003073
3074 return err;
3075}
3076
Johan Hedberg744cf192011-11-08 20:40:14 +02003077int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003078 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003079{
3080 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003081 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003082 int err;
3083
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003084 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003085 if (!cmd)
3086 return -ENOENT;
3087
Johan Hedbergd8457692012-02-17 14:24:57 +02003088 bacpy(&rp.addr.bdaddr, bdaddr);
3089 rp.addr.type = MGMT_ADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003090
Johan Hedbergaee9b212012-02-18 15:07:59 +02003091 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003092 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003093
Johan Hedberga664b5b2011-02-19 12:06:02 -03003094 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003095
3096 return err;
3097}
Johan Hedberga5c29682011-02-19 12:05:57 -03003098
Johan Hedberg744cf192011-11-08 20:40:14 +02003099int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003100 u8 link_type, u8 addr_type, __le32 value,
3101 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03003102{
3103 struct mgmt_ev_user_confirm_request ev;
3104
Johan Hedberg744cf192011-11-08 20:40:14 +02003105 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03003106
Johan Hedberg272d90d2012-02-09 15:26:12 +02003107 bacpy(&ev.addr.bdaddr, bdaddr);
3108 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07003109 ev.confirm_hint = confirm_hint;
Johan Hedberga5c29682011-02-19 12:05:57 -03003110 put_unaligned_le32(value, &ev.value);
3111
Johan Hedberg744cf192011-11-08 20:40:14 +02003112 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003113 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03003114}
3115
Johan Hedberg272d90d2012-02-09 15:26:12 +02003116int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
3117 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08003118{
3119 struct mgmt_ev_user_passkey_request ev;
3120
3121 BT_DBG("%s", hdev->name);
3122
Johan Hedberg272d90d2012-02-09 15:26:12 +02003123 bacpy(&ev.addr.bdaddr, bdaddr);
3124 ev.addr.type = link_to_mgmt(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08003125
3126 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003127 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08003128}
3129
Brian Gix0df4c182011-11-16 13:53:13 -08003130static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003131 u8 link_type, u8 addr_type, u8 status,
3132 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03003133{
3134 struct pending_cmd *cmd;
3135 struct mgmt_rp_user_confirm_reply rp;
3136 int err;
3137
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003138 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03003139 if (!cmd)
3140 return -ENOENT;
3141
Johan Hedberg272d90d2012-02-09 15:26:12 +02003142 bacpy(&rp.addr.bdaddr, bdaddr);
3143 rp.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergaee9b212012-02-18 15:07:59 +02003144 err = cmd_complete(cmd->sk, hdev->id, opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003145 &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03003146
Johan Hedberga664b5b2011-02-19 12:06:02 -03003147 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03003148
3149 return err;
3150}
3151
Johan Hedberg744cf192011-11-08 20:40:14 +02003152int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003153 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003154{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003155 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003156 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003157}
3158
Johan Hedberg272d90d2012-02-09 15:26:12 +02003159int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003160 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003161{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003162 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003163 status, MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003164}
Johan Hedberg2a611692011-02-19 12:06:00 -03003165
Brian Gix604086b2011-11-23 08:28:33 -08003166int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003167 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003168{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003169 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003170 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003171}
3172
Johan Hedberg272d90d2012-02-09 15:26:12 +02003173int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003174 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003175{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003176 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003177 status, MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003178}
3179
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003180int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003181 u8 addr_type, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03003182{
3183 struct mgmt_ev_auth_failed ev;
3184
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003185 bacpy(&ev.addr.bdaddr, bdaddr);
3186 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003187 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03003188
Johan Hedberg744cf192011-11-08 20:40:14 +02003189 return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03003190}
Johan Hedbergb312b1612011-03-16 14:29:37 +02003191
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003192int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
3193{
3194 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg47990ea2012-02-22 11:58:37 +02003195 bool changed = false;
3196 int err = 0;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003197
3198 if (status) {
3199 u8 mgmt_err = mgmt_status(status);
3200 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003201 cmd_status_rsp, &mgmt_err);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003202 return 0;
3203 }
3204
Johan Hedberg47990ea2012-02-22 11:58:37 +02003205 if (test_bit(HCI_AUTH, &hdev->flags)) {
3206 if (!test_and_set_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
3207 changed = true;
3208 } else {
3209 if (test_and_clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
3210 changed = true;
3211 }
3212
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003213 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003214 &match);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003215
Johan Hedberg47990ea2012-02-22 11:58:37 +02003216 if (changed)
3217 err = new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003218
3219 if (match.sk)
3220 sock_put(match.sk);
3221
3222 return err;
3223}
3224
Johan Hedbergcacaf522012-02-21 00:52:42 +02003225static int clear_eir(struct hci_dev *hdev)
3226{
3227 struct hci_cp_write_eir cp;
3228
3229 if (!(hdev->features[6] & LMP_EXT_INQ))
3230 return 0;
3231
Johan Hedbergc80da272012-02-22 15:38:48 +02003232 memset(hdev->eir, 0, sizeof(hdev->eir));
3233
Johan Hedbergcacaf522012-02-21 00:52:42 +02003234 memset(&cp, 0, sizeof(cp));
3235
3236 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
3237}
3238
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003239int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003240{
3241 struct cmd_lookup match = { NULL, hdev };
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003242 bool changed = false;
3243 int err = 0;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003244
3245 if (status) {
3246 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003247
3248 if (enable && test_and_clear_bit(HCI_SSP_ENABLED,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003249 &hdev->dev_flags))
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003250 err = new_settings(hdev, NULL);
3251
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003252 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
3253 &mgmt_err);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003254
3255 return err;
3256 }
3257
3258 if (enable) {
3259 if (!test_and_set_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3260 changed = true;
3261 } else {
3262 if (test_and_clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3263 changed = true;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003264 }
3265
3266 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
3267
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003268 if (changed)
3269 err = new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003270
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02003271 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003272 sock_put(match.sk);
3273
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02003274 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3275 update_eir(hdev);
3276 else
3277 clear_eir(hdev);
Johan Hedbergcacaf522012-02-21 00:52:42 +02003278
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003279 return err;
3280}
3281
Johan Hedberg90e70452012-02-23 23:09:40 +02003282static void class_rsp(struct pending_cmd *cmd, void *data)
3283{
3284 struct cmd_lookup *match = data;
3285
3286 cmd_complete(cmd->sk, cmd->index, cmd->opcode, match->mgmt_status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003287 match->hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02003288
3289 list_del(&cmd->list);
3290
3291 if (match->sk == NULL) {
3292 match->sk = cmd->sk;
3293 sock_hold(match->sk);
3294 }
3295
3296 mgmt_pending_free(cmd);
3297}
3298
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003299int mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003300 u8 status)
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003301{
Johan Hedberg90e70452012-02-23 23:09:40 +02003302 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
3303 int err = 0;
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003304
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02003305 clear_bit(HCI_PENDING_CLASS, &hdev->dev_flags);
3306
Johan Hedberg90e70452012-02-23 23:09:40 +02003307 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, class_rsp, &match);
3308 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, class_rsp, &match);
3309 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, class_rsp, &match);
3310
3311 if (!status)
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003312 err = mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class,
3313 3, NULL);
Johan Hedberg90e70452012-02-23 23:09:40 +02003314
3315 if (match.sk)
3316 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003317
3318 return err;
3319}
3320
Johan Hedberg744cf192011-11-08 20:40:14 +02003321int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02003322{
3323 struct pending_cmd *cmd;
3324 struct mgmt_cp_set_local_name ev;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003325 bool changed = false;
3326 int err = 0;
3327
3328 if (memcmp(name, hdev->dev_name, sizeof(hdev->dev_name)) != 0) {
3329 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
3330 changed = true;
3331 }
Johan Hedbergb312b1612011-03-16 14:29:37 +02003332
3333 memset(&ev, 0, sizeof(ev));
3334 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003335 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003336
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003337 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003338 if (!cmd)
3339 goto send_event;
3340
Johan Hedberg7bdaae42012-02-22 21:39:58 +02003341 /* Always assume that either the short or the complete name has
3342 * changed if there was a pending mgmt command */
3343 changed = true;
3344
Johan Hedbergb312b1612011-03-16 14:29:37 +02003345 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02003346 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003347 mgmt_status(status));
Johan Hedbergb312b1612011-03-16 14:29:37 +02003348 goto failed;
3349 }
3350
Johan Hedbergaee9b212012-02-18 15:07:59 +02003351 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0, &ev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003352 sizeof(ev));
Johan Hedbergb312b1612011-03-16 14:29:37 +02003353 if (err < 0)
3354 goto failed;
3355
3356send_event:
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003357 if (changed)
3358 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003359 sizeof(ev), cmd ? cmd->sk : NULL);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003360
Johan Hedbergf51d5b22012-02-22 18:17:32 +02003361 update_eir(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003362
3363failed:
3364 if (cmd)
3365 mgmt_pending_remove(cmd);
3366 return err;
3367}
Szymon Jancc35938b2011-03-22 13:12:21 +01003368
Johan Hedberg744cf192011-11-08 20:40:14 +02003369int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003370 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01003371{
3372 struct pending_cmd *cmd;
3373 int err;
3374
Johan Hedberg744cf192011-11-08 20:40:14 +02003375 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01003376
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003377 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003378 if (!cmd)
3379 return -ENOENT;
3380
3381 if (status) {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003382 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3383 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01003384 } else {
3385 struct mgmt_rp_read_local_oob_data rp;
3386
3387 memcpy(rp.hash, hash, sizeof(rp.hash));
3388 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
3389
Johan Hedberg744cf192011-11-08 20:40:14 +02003390 err = cmd_complete(cmd->sk, hdev->id,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003391 MGMT_OP_READ_LOCAL_OOB_DATA, 0, &rp,
3392 sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01003393 }
3394
3395 mgmt_pending_remove(cmd);
3396
3397 return err;
3398}
Johan Hedberge17acd42011-03-30 23:57:16 +03003399
Johan Hedberg06199cf2012-02-22 16:37:11 +02003400int mgmt_le_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
3401{
3402 struct cmd_lookup match = { NULL, hdev };
3403 bool changed = false;
3404 int err = 0;
3405
3406 if (status) {
3407 u8 mgmt_err = mgmt_status(status);
3408
3409 if (enable && test_and_clear_bit(HCI_LE_ENABLED,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003410 &hdev->dev_flags))
3411 err = new_settings(hdev, NULL);
Johan Hedberg06199cf2012-02-22 16:37:11 +02003412
3413 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003414 cmd_status_rsp, &mgmt_err);
Johan Hedberg06199cf2012-02-22 16:37:11 +02003415
3416 return err;
3417 }
3418
3419 if (enable) {
3420 if (!test_and_set_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3421 changed = true;
3422 } else {
3423 if (test_and_clear_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3424 changed = true;
3425 }
3426
3427 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
3428
3429 if (changed)
3430 err = new_settings(hdev, match.sk);
3431
3432 if (match.sk)
3433 sock_put(match.sk);
3434
3435 return err;
3436}
3437
Johan Hedberg48264f02011-11-09 13:58:58 +02003438int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003439 u8 addr_type, u8 *dev_class, s8 rssi, u8 cfm_name, u8
3440 ssp, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03003441{
Johan Hedberge319d2e2012-01-15 19:51:59 +02003442 char buf[512];
3443 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02003444 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03003445
Johan Hedberg1dc06092012-01-15 21:01:23 +02003446 /* Leave 5 bytes for a potential CoD field */
3447 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Andre Guedes7d262f82012-01-10 18:20:49 -03003448 return -EINVAL;
3449
Johan Hedberg1dc06092012-01-15 21:01:23 +02003450 memset(buf, 0, sizeof(buf));
3451
Johan Hedberge319d2e2012-01-15 19:51:59 +02003452 bacpy(&ev->addr.bdaddr, bdaddr);
3453 ev->addr.type = link_to_mgmt(link_type, addr_type);
3454 ev->rssi = rssi;
Johan Hedberg9a395a82012-02-23 00:00:32 +02003455 if (cfm_name)
3456 ev->flags[0] |= MGMT_DEV_FOUND_CONFIRM_NAME;
Johan Hedberg388fc8f2012-02-23 00:38:59 +02003457 if (!ssp)
3458 ev->flags[0] |= MGMT_DEV_FOUND_LEGACY_PAIRING;
Johan Hedberge17acd42011-03-30 23:57:16 +03003459
Johan Hedberg1dc06092012-01-15 21:01:23 +02003460 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02003461 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03003462
Johan Hedberg1dc06092012-01-15 21:01:23 +02003463 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
3464 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003465 dev_class, 3);
Johan Hedberg1dc06092012-01-15 21:01:23 +02003466
3467 put_unaligned_le16(eir_len, &ev->eir_len);
3468
3469 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03003470
Johan Hedberge319d2e2012-01-15 19:51:59 +02003471 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03003472}
Johan Hedberga88a9652011-03-30 13:18:12 +03003473
Johan Hedbergb644ba32012-01-17 21:48:47 +02003474int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003475 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03003476{
Johan Hedbergb644ba32012-01-17 21:48:47 +02003477 struct mgmt_ev_device_found *ev;
3478 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
3479 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03003480
Johan Hedbergb644ba32012-01-17 21:48:47 +02003481 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03003482
Johan Hedbergb644ba32012-01-17 21:48:47 +02003483 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03003484
Johan Hedbergb644ba32012-01-17 21:48:47 +02003485 bacpy(&ev->addr.bdaddr, bdaddr);
3486 ev->addr.type = link_to_mgmt(link_type, addr_type);
3487 ev->rssi = rssi;
3488
3489 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003490 name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003491
3492 put_unaligned_le16(eir_len, &ev->eir_len);
3493
Johan Hedberg053c7e02012-02-04 00:06:00 +02003494 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003495 sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03003496}
Johan Hedberg314b2382011-04-27 10:29:57 -04003497
Andre Guedes7a135102011-11-09 17:14:25 -03003498int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
Johan Hedberg164a6e72011-11-01 17:06:44 +02003499{
3500 struct pending_cmd *cmd;
Johan Hedbergf808e162012-02-19 12:52:07 +02003501 u8 type;
Johan Hedberg164a6e72011-11-01 17:06:44 +02003502 int err;
3503
Andre Guedes203159d2012-02-13 15:41:01 -03003504 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3505
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003506 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003507 if (!cmd)
3508 return -ENOENT;
3509
Johan Hedbergf808e162012-02-19 12:52:07 +02003510 type = hdev->discovery.type;
3511
3512 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003513 &type, sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02003514 mgmt_pending_remove(cmd);
3515
3516 return err;
3517}
3518
Andre Guedese6d465c2011-11-09 17:14:26 -03003519int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
3520{
3521 struct pending_cmd *cmd;
3522 int err;
3523
3524 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
3525 if (!cmd)
3526 return -ENOENT;
3527
Johan Hedbergd9306502012-02-20 23:25:18 +02003528 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003529 &hdev->discovery.type, sizeof(hdev->discovery.type));
Johan Hedberg03811012010-12-08 00:21:06 +02003530 mgmt_pending_remove(cmd);
3531
3532 return err;
3533}
Johan Hedberg314b2382011-04-27 10:29:57 -04003534
Johan Hedberg744cf192011-11-08 20:40:14 +02003535int mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04003536{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02003537 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02003538 struct pending_cmd *cmd;
3539
Andre Guedes343fb142011-11-22 17:14:19 -03003540 BT_DBG("%s discovering %u", hdev->name, discovering);
3541
Johan Hedberg164a6e72011-11-01 17:06:44 +02003542 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003543 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003544 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003545 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003546
3547 if (cmd != NULL) {
Johan Hedbergf808e162012-02-19 12:52:07 +02003548 u8 type = hdev->discovery.type;
3549
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003550 cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0, &type,
3551 sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02003552 mgmt_pending_remove(cmd);
3553 }
3554
Johan Hedbergf963e8e2012-02-20 23:30:44 +02003555 memset(&ev, 0, sizeof(ev));
3556 ev.type = hdev->discovery.type;
3557 ev.discovering = discovering;
3558
3559 return mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04003560}
Antti Julku5e762442011-08-25 16:48:02 +03003561
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003562int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003563{
3564 struct pending_cmd *cmd;
3565 struct mgmt_ev_device_blocked ev;
3566
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003567 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003568
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003569 bacpy(&ev.addr.bdaddr, bdaddr);
3570 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003571
Johan Hedberg744cf192011-11-08 20:40:14 +02003572 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003573 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003574}
3575
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003576int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003577{
3578 struct pending_cmd *cmd;
3579 struct mgmt_ev_device_unblocked ev;
3580
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003581 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003582
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003583 bacpy(&ev.addr.bdaddr, bdaddr);
3584 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003585
Johan Hedberg744cf192011-11-08 20:40:14 +02003586 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003587 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003588}
Marcel Holtmannd7b7e792012-02-20 21:47:49 +01003589
3590module_param(enable_hs, bool, 0644);
3591MODULE_PARM_DESC(enable_hs, "Enable High Speed support");
3592
3593module_param(enable_le, bool, 0644);
3594MODULE_PARM_DESC(enable_le, "Enable Low Energy support");