blob: 4ef275c69675ab116897da18663626a53ab6c6fe [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 Hedbergf7b64e62010-12-13 21:07:06 +0200207{
208 struct sk_buff *skb;
209 struct mgmt_hdr *hdr;
210 struct mgmt_ev_cmd_status *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300211 int err;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200212
Szymon Janc34eb5252011-02-28 14:10:08 +0100213 BT_DBG("sock %p, index %u, cmd %u, status %u", sk, index, cmd, status);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200214
215 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_ATOMIC);
216 if (!skb)
217 return -ENOMEM;
218
219 hdr = (void *) skb_put(skb, sizeof(*hdr));
220
221 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_STATUS);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100222 hdr->index = cpu_to_le16(index);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200223 hdr->len = cpu_to_le16(sizeof(*ev));
224
225 ev = (void *) skb_put(skb, sizeof(*ev));
226 ev->status = status;
227 put_unaligned_le16(cmd, &ev->opcode);
228
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300229 err = sock_queue_rcv_skb(sk, skb);
230 if (err < 0)
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200231 kfree_skb(skb);
232
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300233 return err;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200234}
235
Johan Hedbergaee9b2182012-02-18 15:07:59 +0200236static int cmd_complete(struct sock *sk, u16 index, u16 cmd, u8 status,
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 Hedbergaee9b2182012-02-18 15:07:59 +0200258 ev->status = status;
Szymon Janc8020c162011-02-28 14:09:50 +0100259
260 if (rp)
261 memcpy(ev->data, rp, rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200262
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300263 err = sock_queue_rcv_skb(sk, skb);
264 if (err < 0)
Johan Hedberg02d98122010-12-13 21:07:04 +0200265 kfree_skb(skb);
266
Marcel Holtmanne5f0e152012-02-22 11:59:01 +0100267 return err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200268}
269
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 Hedbergaee9b2182012-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 Hedbergaee9b2182012-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 Hedbergaee9b2182012-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 Hedbergf7b64e62010-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 Hedbergf7b64e62010-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 Hedbergf7b64e62010-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 Hedbergf7b64e62010-12-13 21:07:06 +0200418
Johan Hedberg84bde9d2012-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 Hedbergf7b64e62010-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 Hedberg84bde9d2012-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 Hedbergaee9b2182012-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 Hedbergf7b64e62010-12-13 21:07:06 +0200847
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300848 hci_dev_lock(hdev);
Johan Hedbergf7b64e62010-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 Hedbergf7b64e62010-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 Hedbergf7b64e62010-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 Hedbergf7b64e62010-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 Hedbergaee9b2182012-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 Hedbergf7c68692011-12-15 00:47:36 +02002524 if (cp->val) {
Antti Julkuf6422ec2011-06-22 13:11:56 +03002525 type = PAGE_SCAN_TYPE_INTERLACED;
Andrei Emeltchenko76ec9de2012-03-12 12:13:11 +02002526
2527 /* 22.5 msec page scan interval */
2528 acp.interval = __constant_cpu_to_le16(0x0024);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002529 } else {
2530 type = PAGE_SCAN_TYPE_STANDARD; /* default */
Andrei Emeltchenko76ec9de2012-03-12 12:13:11 +02002531
2532 /* default 1.28 sec page scan */
2533 acp.interval = __constant_cpu_to_le16(0x0800);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002534 }
2535
Andrei Emeltchenko76ec9de2012-03-12 12:13:11 +02002536 /* default 11.25 msec page scan window */
2537 acp.window = __constant_cpu_to_le16(0x0012);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002538
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002539 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY, sizeof(acp),
2540 &acp);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002541 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002542 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002543 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002544 goto done;
2545 }
2546
2547 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
2548 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002549 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002550 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002551 goto done;
2552 }
2553
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002554 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002555 NULL, 0);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002556done:
2557 hci_dev_unlock(hdev);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002558 return err;
2559}
2560
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002561static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002562 void *cp_data, u16 len)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002563{
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002564 struct mgmt_cp_load_long_term_keys *cp = cp_data;
2565 u16 key_count, expected_len;
2566 int i;
2567
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002568 key_count = get_unaligned_le16(&cp->key_count);
2569
2570 expected_len = sizeof(*cp) + key_count *
2571 sizeof(struct mgmt_ltk_info);
2572 if (expected_len != len) {
2573 BT_ERR("load_keys: expected %u bytes, got %u bytes",
2574 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002575 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002576 EINVAL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002577 }
2578
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002579 BT_DBG("%s key_count %u", hdev->name, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002580
2581 hci_dev_lock(hdev);
2582
2583 hci_smp_ltks_clear(hdev);
2584
2585 for (i = 0; i < key_count; i++) {
2586 struct mgmt_ltk_info *key = &cp->keys[i];
2587 u8 type;
2588
2589 if (key->master)
2590 type = HCI_SMP_LTK;
2591 else
2592 type = HCI_SMP_LTK_SLAVE;
2593
2594 hci_add_ltk(hdev, &key->addr.bdaddr, key->addr.type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002595 type, 0, key->authenticated, key->val,
2596 key->enc_size, key->ediv, key->rand);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002597 }
2598
2599 hci_dev_unlock(hdev);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002600
2601 return 0;
2602}
2603
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002604struct mgmt_handler {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002605 int (*func) (struct sock *sk, struct hci_dev *hdev, void *data,
2606 u16 data_len);
Johan Hedbergbe22b542012-03-01 22:24:41 +02002607 bool var_len;
2608 size_t data_len;
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002609} mgmt_handlers[] = {
2610 { NULL }, /* 0x0000 (no command) */
Johan Hedbergbe22b542012-03-01 22:24:41 +02002611 { read_version, false, MGMT_READ_VERSION_SIZE },
2612 { read_commands, false, MGMT_READ_COMMANDS_SIZE },
2613 { read_index_list, false, MGMT_READ_INDEX_LIST_SIZE },
2614 { read_controller_info, false, MGMT_READ_INFO_SIZE },
2615 { set_powered, false, MGMT_SETTING_SIZE },
2616 { set_discoverable, false, MGMT_SET_DISCOVERABLE_SIZE },
2617 { set_connectable, false, MGMT_SETTING_SIZE },
2618 { set_fast_connectable, false, MGMT_SETTING_SIZE },
2619 { set_pairable, false, MGMT_SETTING_SIZE },
2620 { set_link_security, false, MGMT_SETTING_SIZE },
2621 { set_ssp, false, MGMT_SETTING_SIZE },
2622 { set_hs, false, MGMT_SETTING_SIZE },
2623 { set_le, false, MGMT_SETTING_SIZE },
2624 { set_dev_class, false, MGMT_SET_DEV_CLASS_SIZE },
2625 { set_local_name, false, MGMT_SET_LOCAL_NAME_SIZE },
2626 { add_uuid, false, MGMT_ADD_UUID_SIZE },
2627 { remove_uuid, false, MGMT_REMOVE_UUID_SIZE },
2628 { load_link_keys, true, MGMT_LOAD_LINK_KEYS_SIZE },
2629 { load_long_term_keys, true, MGMT_LOAD_LONG_TERM_KEYS_SIZE },
2630 { disconnect, false, MGMT_DISCONNECT_SIZE },
2631 { get_connections, false, MGMT_GET_CONNECTIONS_SIZE },
2632 { pin_code_reply, false, MGMT_PIN_CODE_REPLY_SIZE },
2633 { pin_code_neg_reply, false, MGMT_PIN_CODE_NEG_REPLY_SIZE },
2634 { set_io_capability, false, MGMT_SET_IO_CAPABILITY_SIZE },
2635 { pair_device, false, MGMT_PAIR_DEVICE_SIZE },
2636 { cancel_pair_device, false, MGMT_CANCEL_PAIR_DEVICE_SIZE },
2637 { unpair_device, false, MGMT_UNPAIR_DEVICE_SIZE },
2638 { user_confirm_reply, false, MGMT_USER_CONFIRM_REPLY_SIZE },
2639 { user_confirm_neg_reply, false, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
2640 { user_passkey_reply, false, MGMT_USER_PASSKEY_REPLY_SIZE },
2641 { user_passkey_neg_reply, false, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
2642 { read_local_oob_data, false, MGMT_READ_LOCAL_OOB_DATA_SIZE },
2643 { add_remote_oob_data, false, MGMT_ADD_REMOTE_OOB_DATA_SIZE },
2644 { remove_remote_oob_data, false, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
2645 { start_discovery, false, MGMT_START_DISCOVERY_SIZE },
2646 { stop_discovery, false, MGMT_STOP_DISCOVERY_SIZE },
2647 { confirm_name, false, MGMT_CONFIRM_NAME_SIZE },
2648 { block_device, false, MGMT_BLOCK_DEVICE_SIZE },
2649 { unblock_device, false, MGMT_UNBLOCK_DEVICE_SIZE },
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002650};
2651
2652
Johan Hedberg03811012010-12-08 00:21:06 +02002653int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
2654{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002655 void *buf;
2656 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02002657 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002658 u16 opcode, index, len;
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002659 struct hci_dev *hdev = NULL;
Johan Hedbergbe22b542012-03-01 22:24:41 +02002660 struct mgmt_handler *handler;
Johan Hedberg03811012010-12-08 00:21:06 +02002661 int err;
2662
2663 BT_DBG("got %zu bytes", msglen);
2664
2665 if (msglen < sizeof(*hdr))
2666 return -EINVAL;
2667
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03002668 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02002669 if (!buf)
2670 return -ENOMEM;
2671
2672 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
2673 err = -EFAULT;
2674 goto done;
2675 }
2676
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002677 hdr = buf;
Johan Hedberg03811012010-12-08 00:21:06 +02002678 opcode = get_unaligned_le16(&hdr->opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002679 index = get_unaligned_le16(&hdr->index);
Johan Hedberg03811012010-12-08 00:21:06 +02002680 len = get_unaligned_le16(&hdr->len);
2681
2682 if (len != msglen - sizeof(*hdr)) {
2683 err = -EINVAL;
2684 goto done;
2685 }
2686
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002687 if (index != MGMT_INDEX_NONE) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002688 hdev = hci_dev_get(index);
2689 if (!hdev) {
2690 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002691 MGMT_STATUS_INVALID_INDEX);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002692 goto done;
2693 }
2694 }
2695
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002696 if (opcode >= ARRAY_SIZE(mgmt_handlers) ||
2697 mgmt_handlers[opcode].func == NULL) {
Johan Hedberg03811012010-12-08 00:21:06 +02002698 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02002699 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002700 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002701 goto done;
Johan Hedberg03811012010-12-08 00:21:06 +02002702 }
2703
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002704 if ((hdev && opcode < MGMT_OP_READ_INFO) ||
2705 (!hdev && opcode >= MGMT_OP_READ_INFO)) {
2706 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002707 MGMT_STATUS_INVALID_INDEX);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002708 goto done;
2709 }
2710
Johan Hedbergbe22b542012-03-01 22:24:41 +02002711 handler = &mgmt_handlers[opcode];
2712
2713 if ((handler->var_len && len < handler->data_len) ||
2714 (!handler->var_len && len != handler->data_len)) {
2715 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002716 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergbe22b542012-03-01 22:24:41 +02002717 goto done;
2718 }
2719
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002720 if (hdev)
2721 mgmt_init_hdev(sk, hdev);
2722
2723 cp = buf + sizeof(*hdr);
2724
Johan Hedbergbe22b542012-03-01 22:24:41 +02002725 err = handler->func(sk, hdev, cp, len);
Johan Hedberge41d8b42010-12-13 21:07:03 +02002726 if (err < 0)
2727 goto done;
2728
Johan Hedberg03811012010-12-08 00:21:06 +02002729 err = msglen;
2730
2731done:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002732 if (hdev)
2733 hci_dev_put(hdev);
2734
Johan Hedberg03811012010-12-08 00:21:06 +02002735 kfree(buf);
2736 return err;
2737}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002738
Johan Hedbergb24752f2011-11-03 14:40:33 +02002739static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
2740{
2741 u8 *status = data;
2742
2743 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
2744 mgmt_pending_remove(cmd);
2745}
2746
Johan Hedberg744cf192011-11-08 20:40:14 +02002747int mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002748{
Johan Hedberg744cf192011-11-08 20:40:14 +02002749 return mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002750}
2751
Johan Hedberg744cf192011-11-08 20:40:14 +02002752int mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002753{
Johan Hedberg5f159032012-03-02 03:13:19 +02002754 u8 status = MGMT_STATUS_INVALID_INDEX;
Johan Hedbergb24752f2011-11-03 14:40:33 +02002755
Johan Hedberg744cf192011-11-08 20:40:14 +02002756 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002757
Johan Hedberg744cf192011-11-08 20:40:14 +02002758 return mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002759}
2760
Johan Hedberg73f22f62010-12-29 16:00:25 +02002761struct cmd_lookup {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002762 struct sock *sk;
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002763 struct hci_dev *hdev;
Johan Hedberg90e70452012-02-23 23:09:40 +02002764 u8 mgmt_status;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002765};
2766
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002767static void settings_rsp(struct pending_cmd *cmd, void *data)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002768{
Johan Hedberg73f22f62010-12-29 16:00:25 +02002769 struct cmd_lookup *match = data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002770
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002771 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002772
2773 list_del(&cmd->list);
2774
2775 if (match->sk == NULL) {
2776 match->sk = cmd->sk;
2777 sock_hold(match->sk);
2778 }
2779
2780 mgmt_pending_free(cmd);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002781}
Johan Hedberg5add6af2010-12-16 10:00:37 +02002782
Johan Hedberg744cf192011-11-08 20:40:14 +02002783int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg5add6af2010-12-16 10:00:37 +02002784{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002785 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002786 int err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002787
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002788 if (!test_bit(HCI_MGMT, &hdev->dev_flags))
2789 return 0;
2790
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002791 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
Johan Hedberg5add6af2010-12-16 10:00:37 +02002792
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002793 if (powered) {
2794 u8 scan = 0;
2795
2796 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
2797 scan |= SCAN_PAGE;
2798 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
2799 scan |= SCAN_INQUIRY;
2800
2801 if (scan)
2802 hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
Johan Hedberg504c8dc2012-02-23 13:30:41 +02002803
2804 update_class(hdev);
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002805 update_name(hdev, hdev->dev_name);
Johan Hedberg504c8dc2012-02-23 13:30:41 +02002806 update_eir(hdev);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002807 } else {
Johan Hedbergd4f68522012-03-02 03:07:07 +02002808 u8 status = MGMT_STATUS_NOT_POWERED;
Johan Hedberg744cf192011-11-08 20:40:14 +02002809 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002810 }
2811
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02002812 err = new_settings(hdev, match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002813
2814 if (match.sk)
2815 sock_put(match.sk);
2816
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002817 return err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002818}
Johan Hedberg73f22f62010-12-29 16:00:25 +02002819
Johan Hedberg744cf192011-11-08 20:40:14 +02002820int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg73f22f62010-12-29 16:00:25 +02002821{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002822 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002823 bool changed = false;
2824 int err = 0;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002825
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002826 if (discoverable) {
2827 if (!test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
2828 changed = true;
2829 } else {
2830 if (test_and_clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
2831 changed = true;
2832 }
Johan Hedberg73f22f62010-12-29 16:00:25 +02002833
Johan Hedberged9b5f22012-02-21 20:47:06 +02002834 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002835 &match);
Johan Hedberged9b5f22012-02-21 20:47:06 +02002836
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02002837 if (changed)
2838 err = new_settings(hdev, match.sk);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002839
Johan Hedberg73f22f62010-12-29 16:00:25 +02002840 if (match.sk)
2841 sock_put(match.sk);
2842
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002843 return err;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002844}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002845
Johan Hedberg744cf192011-11-08 20:40:14 +02002846int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002847{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002848 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002849 bool changed = false;
2850 int err = 0;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002851
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002852 if (connectable) {
2853 if (!test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags))
2854 changed = true;
2855 } else {
2856 if (test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags))
2857 changed = true;
2858 }
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002859
Johan Hedberged9b5f22012-02-21 20:47:06 +02002860 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002861 &match);
Johan Hedberged9b5f22012-02-21 20:47:06 +02002862
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02002863 if (changed)
2864 err = new_settings(hdev, match.sk);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002865
2866 if (match.sk)
2867 sock_put(match.sk);
2868
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002869 return err;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002870}
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002871
Johan Hedberg744cf192011-11-08 20:40:14 +02002872int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002873{
Johan Hedbergca69b792011-11-11 18:10:00 +02002874 u8 mgmt_err = mgmt_status(status);
2875
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002876 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02002877 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002878 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002879
2880 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02002881 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002882 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002883
2884 return 0;
2885}
2886
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002887int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key, u8 persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002888{
Johan Hedberg86742e12011-11-07 23:13:38 +02002889 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002890
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002891 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002892
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002893 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02002894 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
2895 ev.key.addr.type = MGMT_ADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002896 ev.key.type = key->type;
2897 memcpy(ev.key.val, key->val, 16);
2898 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002899
Johan Hedberg744cf192011-11-08 20:40:14 +02002900 return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002901}
Johan Hedbergf7520542011-01-20 12:34:39 +02002902
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002903int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
2904{
2905 struct mgmt_ev_new_long_term_key ev;
2906
2907 memset(&ev, 0, sizeof(ev));
2908
2909 ev.store_hint = persistent;
2910 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
2911 ev.key.addr.type = key->bdaddr_type;
2912 ev.key.authenticated = key->authenticated;
2913 ev.key.enc_size = key->enc_size;
2914 ev.key.ediv = key->ediv;
2915
2916 if (key->type == HCI_SMP_LTK)
2917 ev.key.master = 1;
2918
2919 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
2920 memcpy(ev.key.val, key->val, sizeof(key->val));
2921
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002922 return mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev),
2923 NULL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002924}
2925
Johan Hedbergafc747a2012-01-15 18:11:07 +02002926int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002927 u8 addr_type, u32 flags, u8 *name, u8 name_len,
2928 u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02002929{
Johan Hedbergb644ba32012-01-17 21:48:47 +02002930 char buf[512];
2931 struct mgmt_ev_device_connected *ev = (void *) buf;
2932 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02002933
Johan Hedbergb644ba32012-01-17 21:48:47 +02002934 bacpy(&ev->addr.bdaddr, bdaddr);
2935 ev->addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02002936
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02002937 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02002938
Johan Hedbergb644ba32012-01-17 21:48:47 +02002939 if (name_len > 0)
2940 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002941 name, name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02002942
2943 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
Brian Gix53156382012-03-09 14:07:03 -08002944 eir_len = eir_append_data(ev->eir, eir_len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002945 EIR_CLASS_OF_DEV, dev_class, 3);
Johan Hedbergb644ba32012-01-17 21:48:47 +02002946
2947 put_unaligned_le16(eir_len, &ev->eir_len);
2948
2949 return mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002950 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02002951}
2952
Johan Hedberg8962ee72011-01-20 12:40:27 +02002953static void disconnect_rsp(struct pending_cmd *cmd, void *data)
2954{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01002955 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002956 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02002957 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002958
Johan Hedberg88c3df12012-02-09 14:27:38 +02002959 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2960 rp.addr.type = cp->addr.type;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002961
Johan Hedbergaee9b2182012-02-18 15:07:59 +02002962 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002963 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002964
2965 *sk = cmd->sk;
2966 sock_hold(*sk);
2967
Johan Hedberga664b5b2011-02-19 12:06:02 -03002968 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002969}
2970
Johan Hedberg124f6e32012-02-09 13:50:12 +02002971static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02002972{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002973 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02002974 struct mgmt_cp_unpair_device *cp = cmd->param;
2975 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002976
2977 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02002978 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2979 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002980
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002981 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
2982
Johan Hedbergaee9b2182012-02-18 15:07:59 +02002983 cmd_complete(cmd->sk, cmd->index, cmd->opcode, 0, &rp, sizeof(rp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02002984
2985 mgmt_pending_remove(cmd);
2986}
2987
Johan Hedbergafc747a2012-01-15 18:11:07 +02002988int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002989 u8 link_type, u8 addr_type)
Johan Hedbergf7520542011-01-20 12:34:39 +02002990{
Johan Hedberg4c659c32011-11-07 23:13:39 +02002991 struct mgmt_addr_info ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002992 struct sock *sk = NULL;
2993 int err;
2994
Johan Hedberg744cf192011-11-08 20:40:14 +02002995 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02002996
Johan Hedbergf7520542011-01-20 12:34:39 +02002997 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02002998 ev.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02002999
Johan Hedbergafc747a2012-01-15 18:11:07 +02003000 err = mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003001 sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003002
3003 if (sk)
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003004 sock_put(sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003005
Johan Hedberg124f6e32012-02-09 13:50:12 +02003006 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003007 hdev);
Johan Hedberga8a1d192011-11-10 15:54:38 +02003008
Johan Hedberg8962ee72011-01-20 12:40:27 +02003009 return err;
3010}
3011
Johan Hedberg88c3df12012-02-09 14:27:38 +02003012int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003013 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02003014{
Johan Hedberg88c3df12012-02-09 14:27:38 +02003015 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003016 struct pending_cmd *cmd;
3017 int err;
3018
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003019 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003020 if (!cmd)
3021 return -ENOENT;
3022
Johan Hedberg88c3df12012-02-09 14:27:38 +02003023 bacpy(&rp.addr.bdaddr, bdaddr);
3024 rp.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02003025
Johan Hedberg88c3df12012-02-09 14:27:38 +02003026 err = cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003027 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003028
Johan Hedberga664b5b2011-02-19 12:06:02 -03003029 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003030
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003031 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
3032 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003033 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02003034}
Johan Hedberg17d5c042011-01-22 06:09:08 +02003035
Johan Hedberg48264f02011-11-09 13:58:58 +02003036int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003037 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02003038{
3039 struct mgmt_ev_connect_failed ev;
3040
Johan Hedberg4c659c32011-11-07 23:13:39 +02003041 bacpy(&ev.addr.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02003042 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003043 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003044
Johan Hedberg744cf192011-11-08 20:40:14 +02003045 return mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003046}
Johan Hedberg980e1a52011-01-22 06:10:07 +02003047
Johan Hedberg744cf192011-11-08 20:40:14 +02003048int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003049{
3050 struct mgmt_ev_pin_code_request ev;
3051
Johan Hedbergd8457692012-02-17 14:24:57 +02003052 bacpy(&ev.addr.bdaddr, bdaddr);
3053 ev.addr.type = MGMT_ADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02003054 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003055
Johan Hedberg744cf192011-11-08 20:40:14 +02003056 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003057 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003058}
3059
Johan Hedberg744cf192011-11-08 20:40:14 +02003060int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003061 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003062{
3063 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003064 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003065 int err;
3066
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003067 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003068 if (!cmd)
3069 return -ENOENT;
3070
Johan Hedbergd8457692012-02-17 14:24:57 +02003071 bacpy(&rp.addr.bdaddr, bdaddr);
3072 rp.addr.type = MGMT_ADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003073
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003074 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003075 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003076
Johan Hedberga664b5b2011-02-19 12:06:02 -03003077 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003078
3079 return err;
3080}
3081
Johan Hedberg744cf192011-11-08 20:40:14 +02003082int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003083 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003084{
3085 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003086 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003087 int err;
3088
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003089 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003090 if (!cmd)
3091 return -ENOENT;
3092
Johan Hedbergd8457692012-02-17 14:24:57 +02003093 bacpy(&rp.addr.bdaddr, bdaddr);
3094 rp.addr.type = MGMT_ADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003095
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003096 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003097 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003098
Johan Hedberga664b5b2011-02-19 12:06:02 -03003099 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003100
3101 return err;
3102}
Johan Hedberga5c29682011-02-19 12:05:57 -03003103
Johan Hedberg744cf192011-11-08 20:40:14 +02003104int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003105 u8 link_type, u8 addr_type, __le32 value,
3106 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03003107{
3108 struct mgmt_ev_user_confirm_request ev;
3109
Johan Hedberg744cf192011-11-08 20:40:14 +02003110 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03003111
Johan Hedberg272d90d2012-02-09 15:26:12 +02003112 bacpy(&ev.addr.bdaddr, bdaddr);
3113 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07003114 ev.confirm_hint = confirm_hint;
Johan Hedberga5c29682011-02-19 12:05:57 -03003115 put_unaligned_le32(value, &ev.value);
3116
Johan Hedberg744cf192011-11-08 20:40:14 +02003117 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003118 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03003119}
3120
Johan Hedberg272d90d2012-02-09 15:26:12 +02003121int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
3122 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08003123{
3124 struct mgmt_ev_user_passkey_request ev;
3125
3126 BT_DBG("%s", hdev->name);
3127
Johan Hedberg272d90d2012-02-09 15:26:12 +02003128 bacpy(&ev.addr.bdaddr, bdaddr);
3129 ev.addr.type = link_to_mgmt(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08003130
3131 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003132 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08003133}
3134
Brian Gix0df4c182011-11-16 13:53:13 -08003135static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003136 u8 link_type, u8 addr_type, u8 status,
3137 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03003138{
3139 struct pending_cmd *cmd;
3140 struct mgmt_rp_user_confirm_reply rp;
3141 int err;
3142
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003143 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03003144 if (!cmd)
3145 return -ENOENT;
3146
Johan Hedberg272d90d2012-02-09 15:26:12 +02003147 bacpy(&rp.addr.bdaddr, bdaddr);
3148 rp.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003149 err = cmd_complete(cmd->sk, hdev->id, opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003150 &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03003151
Johan Hedberga664b5b2011-02-19 12:06:02 -03003152 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03003153
3154 return err;
3155}
3156
Johan Hedberg744cf192011-11-08 20:40:14 +02003157int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003158 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003159{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003160 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003161 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003162}
3163
Johan Hedberg272d90d2012-02-09 15:26:12 +02003164int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003165 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003166{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003167 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003168 status, MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003169}
Johan Hedberg2a611692011-02-19 12:06:00 -03003170
Brian Gix604086b2011-11-23 08:28:33 -08003171int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003172 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003173{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003174 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003175 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003176}
3177
Johan Hedberg272d90d2012-02-09 15:26:12 +02003178int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003179 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003180{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003181 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003182 status, MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003183}
3184
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003185int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003186 u8 addr_type, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03003187{
3188 struct mgmt_ev_auth_failed ev;
3189
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003190 bacpy(&ev.addr.bdaddr, bdaddr);
3191 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003192 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03003193
Johan Hedberg744cf192011-11-08 20:40:14 +02003194 return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03003195}
Johan Hedbergb312b1612011-03-16 14:29:37 +02003196
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003197int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
3198{
3199 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg47990ea2012-02-22 11:58:37 +02003200 bool changed = false;
3201 int err = 0;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003202
3203 if (status) {
3204 u8 mgmt_err = mgmt_status(status);
3205 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003206 cmd_status_rsp, &mgmt_err);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003207 return 0;
3208 }
3209
Johan Hedberg47990ea2012-02-22 11:58:37 +02003210 if (test_bit(HCI_AUTH, &hdev->flags)) {
3211 if (!test_and_set_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
3212 changed = true;
3213 } else {
3214 if (test_and_clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
3215 changed = true;
3216 }
3217
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003218 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003219 &match);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003220
Johan Hedberg47990ea2012-02-22 11:58:37 +02003221 if (changed)
3222 err = new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003223
3224 if (match.sk)
3225 sock_put(match.sk);
3226
3227 return err;
3228}
3229
Johan Hedbergcacaf522012-02-21 00:52:42 +02003230static int clear_eir(struct hci_dev *hdev)
3231{
3232 struct hci_cp_write_eir cp;
3233
3234 if (!(hdev->features[6] & LMP_EXT_INQ))
3235 return 0;
3236
Johan Hedbergc80da272012-02-22 15:38:48 +02003237 memset(hdev->eir, 0, sizeof(hdev->eir));
3238
Johan Hedbergcacaf522012-02-21 00:52:42 +02003239 memset(&cp, 0, sizeof(cp));
3240
3241 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
3242}
3243
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003244int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003245{
3246 struct cmd_lookup match = { NULL, hdev };
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003247 bool changed = false;
3248 int err = 0;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003249
3250 if (status) {
3251 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003252
3253 if (enable && test_and_clear_bit(HCI_SSP_ENABLED,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003254 &hdev->dev_flags))
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003255 err = new_settings(hdev, NULL);
3256
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003257 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
3258 &mgmt_err);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003259
3260 return err;
3261 }
3262
3263 if (enable) {
3264 if (!test_and_set_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3265 changed = true;
3266 } else {
3267 if (test_and_clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3268 changed = true;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003269 }
3270
3271 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
3272
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003273 if (changed)
3274 err = new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003275
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02003276 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003277 sock_put(match.sk);
3278
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02003279 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3280 update_eir(hdev);
3281 else
3282 clear_eir(hdev);
Johan Hedbergcacaf522012-02-21 00:52:42 +02003283
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003284 return err;
3285}
3286
Johan Hedberg90e70452012-02-23 23:09:40 +02003287static void class_rsp(struct pending_cmd *cmd, void *data)
3288{
3289 struct cmd_lookup *match = data;
3290
3291 cmd_complete(cmd->sk, cmd->index, cmd->opcode, match->mgmt_status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003292 match->hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02003293
3294 list_del(&cmd->list);
3295
3296 if (match->sk == NULL) {
3297 match->sk = cmd->sk;
3298 sock_hold(match->sk);
3299 }
3300
3301 mgmt_pending_free(cmd);
3302}
3303
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003304int mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003305 u8 status)
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003306{
Johan Hedberg90e70452012-02-23 23:09:40 +02003307 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
3308 int err = 0;
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003309
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02003310 clear_bit(HCI_PENDING_CLASS, &hdev->dev_flags);
3311
Johan Hedberg90e70452012-02-23 23:09:40 +02003312 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, class_rsp, &match);
3313 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, class_rsp, &match);
3314 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, class_rsp, &match);
3315
3316 if (!status)
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003317 err = mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class,
3318 3, NULL);
Johan Hedberg90e70452012-02-23 23:09:40 +02003319
3320 if (match.sk)
3321 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003322
3323 return err;
3324}
3325
Johan Hedberg744cf192011-11-08 20:40:14 +02003326int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02003327{
3328 struct pending_cmd *cmd;
3329 struct mgmt_cp_set_local_name ev;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003330 bool changed = false;
3331 int err = 0;
3332
3333 if (memcmp(name, hdev->dev_name, sizeof(hdev->dev_name)) != 0) {
3334 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
3335 changed = true;
3336 }
Johan Hedbergb312b1612011-03-16 14:29:37 +02003337
3338 memset(&ev, 0, sizeof(ev));
3339 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003340 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003341
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003342 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003343 if (!cmd)
3344 goto send_event;
3345
Johan Hedberg7bdaae42012-02-22 21:39:58 +02003346 /* Always assume that either the short or the complete name has
3347 * changed if there was a pending mgmt command */
3348 changed = true;
3349
Johan Hedbergb312b1612011-03-16 14:29:37 +02003350 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02003351 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003352 mgmt_status(status));
Johan Hedbergb312b1612011-03-16 14:29:37 +02003353 goto failed;
3354 }
3355
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003356 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0, &ev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003357 sizeof(ev));
Johan Hedbergb312b1612011-03-16 14:29:37 +02003358 if (err < 0)
3359 goto failed;
3360
3361send_event:
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003362 if (changed)
3363 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003364 sizeof(ev), cmd ? cmd->sk : NULL);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003365
Johan Hedbergf51d5b22012-02-22 18:17:32 +02003366 update_eir(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003367
3368failed:
3369 if (cmd)
3370 mgmt_pending_remove(cmd);
3371 return err;
3372}
Szymon Jancc35938b2011-03-22 13:12:21 +01003373
Johan Hedberg744cf192011-11-08 20:40:14 +02003374int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003375 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01003376{
3377 struct pending_cmd *cmd;
3378 int err;
3379
Johan Hedberg744cf192011-11-08 20:40:14 +02003380 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01003381
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003382 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003383 if (!cmd)
3384 return -ENOENT;
3385
3386 if (status) {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003387 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3388 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01003389 } else {
3390 struct mgmt_rp_read_local_oob_data rp;
3391
3392 memcpy(rp.hash, hash, sizeof(rp.hash));
3393 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
3394
Johan Hedberg744cf192011-11-08 20:40:14 +02003395 err = cmd_complete(cmd->sk, hdev->id,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003396 MGMT_OP_READ_LOCAL_OOB_DATA, 0, &rp,
3397 sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01003398 }
3399
3400 mgmt_pending_remove(cmd);
3401
3402 return err;
3403}
Johan Hedberge17acd42011-03-30 23:57:16 +03003404
Johan Hedberg06199cf2012-02-22 16:37:11 +02003405int mgmt_le_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
3406{
3407 struct cmd_lookup match = { NULL, hdev };
3408 bool changed = false;
3409 int err = 0;
3410
3411 if (status) {
3412 u8 mgmt_err = mgmt_status(status);
3413
3414 if (enable && test_and_clear_bit(HCI_LE_ENABLED,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003415 &hdev->dev_flags))
3416 err = new_settings(hdev, NULL);
Johan Hedberg06199cf2012-02-22 16:37:11 +02003417
3418 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003419 cmd_status_rsp, &mgmt_err);
Johan Hedberg06199cf2012-02-22 16:37:11 +02003420
3421 return err;
3422 }
3423
3424 if (enable) {
3425 if (!test_and_set_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3426 changed = true;
3427 } else {
3428 if (test_and_clear_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3429 changed = true;
3430 }
3431
3432 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
3433
3434 if (changed)
3435 err = new_settings(hdev, match.sk);
3436
3437 if (match.sk)
3438 sock_put(match.sk);
3439
3440 return err;
3441}
3442
Johan Hedberg48264f02011-11-09 13:58:58 +02003443int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003444 u8 addr_type, u8 *dev_class, s8 rssi, u8 cfm_name, u8
3445 ssp, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03003446{
Johan Hedberge319d2e2012-01-15 19:51:59 +02003447 char buf[512];
3448 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02003449 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03003450
Johan Hedberg1dc06092012-01-15 21:01:23 +02003451 /* Leave 5 bytes for a potential CoD field */
3452 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Andre Guedes7d262f82012-01-10 18:20:49 -03003453 return -EINVAL;
3454
Johan Hedberg1dc06092012-01-15 21:01:23 +02003455 memset(buf, 0, sizeof(buf));
3456
Johan Hedberge319d2e2012-01-15 19:51:59 +02003457 bacpy(&ev->addr.bdaddr, bdaddr);
3458 ev->addr.type = link_to_mgmt(link_type, addr_type);
3459 ev->rssi = rssi;
Johan Hedberg9a395a82012-02-23 00:00:32 +02003460 if (cfm_name)
3461 ev->flags[0] |= MGMT_DEV_FOUND_CONFIRM_NAME;
Johan Hedberg388fc8f2012-02-23 00:38:59 +02003462 if (!ssp)
3463 ev->flags[0] |= MGMT_DEV_FOUND_LEGACY_PAIRING;
Johan Hedberge17acd42011-03-30 23:57:16 +03003464
Johan Hedberg1dc06092012-01-15 21:01:23 +02003465 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02003466 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03003467
Johan Hedberg1dc06092012-01-15 21:01:23 +02003468 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
3469 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003470 dev_class, 3);
Johan Hedberg1dc06092012-01-15 21:01:23 +02003471
3472 put_unaligned_le16(eir_len, &ev->eir_len);
3473
3474 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03003475
Johan Hedberge319d2e2012-01-15 19:51:59 +02003476 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03003477}
Johan Hedberga88a9652011-03-30 13:18:12 +03003478
Johan Hedbergb644ba32012-01-17 21:48:47 +02003479int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003480 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03003481{
Johan Hedbergb644ba32012-01-17 21:48:47 +02003482 struct mgmt_ev_device_found *ev;
3483 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
3484 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03003485
Johan Hedbergb644ba32012-01-17 21:48:47 +02003486 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03003487
Johan Hedbergb644ba32012-01-17 21:48:47 +02003488 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03003489
Johan Hedbergb644ba32012-01-17 21:48:47 +02003490 bacpy(&ev->addr.bdaddr, bdaddr);
3491 ev->addr.type = link_to_mgmt(link_type, addr_type);
3492 ev->rssi = rssi;
3493
3494 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003495 name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003496
3497 put_unaligned_le16(eir_len, &ev->eir_len);
3498
Johan Hedberg053c7e02012-02-04 00:06:00 +02003499 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003500 sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03003501}
Johan Hedberg314b2382011-04-27 10:29:57 -04003502
Andre Guedes7a135102011-11-09 17:14:25 -03003503int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
Johan Hedberg164a6e72011-11-01 17:06:44 +02003504{
3505 struct pending_cmd *cmd;
Johan Hedbergf808e162012-02-19 12:52:07 +02003506 u8 type;
Johan Hedberg164a6e72011-11-01 17:06:44 +02003507 int err;
3508
Andre Guedes203159d2012-02-13 15:41:01 -03003509 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3510
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003511 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003512 if (!cmd)
3513 return -ENOENT;
3514
Johan Hedbergf808e162012-02-19 12:52:07 +02003515 type = hdev->discovery.type;
3516
3517 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003518 &type, sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02003519 mgmt_pending_remove(cmd);
3520
3521 return err;
3522}
3523
Andre Guedese6d465c2011-11-09 17:14:26 -03003524int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
3525{
3526 struct pending_cmd *cmd;
3527 int err;
3528
3529 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
3530 if (!cmd)
3531 return -ENOENT;
3532
Johan Hedbergd9306502012-02-20 23:25:18 +02003533 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003534 &hdev->discovery.type, sizeof(hdev->discovery.type));
Johan Hedberg03811012010-12-08 00:21:06 +02003535 mgmt_pending_remove(cmd);
3536
3537 return err;
3538}
Johan Hedberg314b2382011-04-27 10:29:57 -04003539
Johan Hedberg744cf192011-11-08 20:40:14 +02003540int mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04003541{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02003542 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02003543 struct pending_cmd *cmd;
3544
Andre Guedes343fb142011-11-22 17:14:19 -03003545 BT_DBG("%s discovering %u", hdev->name, discovering);
3546
Johan Hedberg164a6e72011-11-01 17:06:44 +02003547 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003548 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003549 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003550 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003551
3552 if (cmd != NULL) {
Johan Hedbergf808e162012-02-19 12:52:07 +02003553 u8 type = hdev->discovery.type;
3554
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003555 cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0, &type,
3556 sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02003557 mgmt_pending_remove(cmd);
3558 }
3559
Johan Hedbergf963e8e2012-02-20 23:30:44 +02003560 memset(&ev, 0, sizeof(ev));
3561 ev.type = hdev->discovery.type;
3562 ev.discovering = discovering;
3563
3564 return mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04003565}
Antti Julku5e762442011-08-25 16:48:02 +03003566
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003567int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003568{
3569 struct pending_cmd *cmd;
3570 struct mgmt_ev_device_blocked ev;
3571
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003572 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003573
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003574 bacpy(&ev.addr.bdaddr, bdaddr);
3575 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003576
Johan Hedberg744cf192011-11-08 20:40:14 +02003577 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003578 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003579}
3580
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003581int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003582{
3583 struct pending_cmd *cmd;
3584 struct mgmt_ev_device_unblocked ev;
3585
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003586 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003587
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003588 bacpy(&ev.addr.bdaddr, bdaddr);
3589 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003590
Johan Hedberg744cf192011-11-08 20:40:14 +02003591 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003592 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003593}
Marcel Holtmannd7b7e792012-02-20 21:47:49 +01003594
3595module_param(enable_hs, bool, 0644);
3596MODULE_PARM_DESC(enable_hs, "Enable High Speed support");
3597
3598module_param(enable_le, bool, 0644);
3599MODULE_PARM_DESC(enable_le, "Enable Low Energy support");