blob: 1da458d9b5ca8fe7af991bceaacf9b403a0ee272 [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
Marcel Holtmann91c4e9b2012-03-11 19:27:21 -0700482 if (hdev->inq_tx_power) {
483 ptr[0] = 2;
484 ptr[1] = EIR_TX_POWER;
485 ptr[2] = (u8) hdev->inq_tx_power;
486
487 eir_len += 3;
488 ptr += 3;
489 }
490
Marcel Holtmann2b9be132012-03-11 19:32:12 -0700491 if (hdev->devid_source > 0) {
492 ptr[0] = 9;
493 ptr[1] = EIR_DEVICE_ID;
494
495 put_unaligned_le16(hdev->devid_source, ptr + 2);
496 put_unaligned_le16(hdev->devid_vendor, ptr + 4);
497 put_unaligned_le16(hdev->devid_product, ptr + 6);
498 put_unaligned_le16(hdev->devid_version, ptr + 8);
499
500 eir_len += 10;
501 ptr += 10;
502 }
503
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300504 memset(uuid16_list, 0, sizeof(uuid16_list));
505
506 /* Group all UUID16 types */
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200507 list_for_each_entry(uuid, &hdev->uuids, list) {
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300508 u16 uuid16;
509
510 uuid16 = get_uuid16(uuid->uuid);
511 if (uuid16 == 0)
512 return;
513
514 if (uuid16 < 0x1100)
515 continue;
516
517 if (uuid16 == PNP_INFO_SVCLASS_ID)
518 continue;
519
520 /* Stop if not enough space to put next UUID */
521 if (eir_len + 2 + sizeof(u16) > HCI_MAX_EIR_LENGTH) {
522 truncated = 1;
523 break;
524 }
525
526 /* Check for duplicates */
527 for (i = 0; uuid16_list[i] != 0; i++)
528 if (uuid16_list[i] == uuid16)
529 break;
530
531 if (uuid16_list[i] == 0) {
532 uuid16_list[i] = uuid16;
533 eir_len += sizeof(u16);
534 }
535 }
536
537 if (uuid16_list[0] != 0) {
538 u8 *length = ptr;
539
540 /* EIR Data type */
541 ptr[1] = truncated ? EIR_UUID16_SOME : EIR_UUID16_ALL;
542
543 ptr += 2;
544 eir_len += 2;
545
546 for (i = 0; uuid16_list[i] != 0; i++) {
547 *ptr++ = (uuid16_list[i] & 0x00ff);
548 *ptr++ = (uuid16_list[i] & 0xff00) >> 8;
549 }
550
551 /* EIR Data length */
552 *length = (i * sizeof(u16)) + 1;
553 }
554}
555
556static int update_eir(struct hci_dev *hdev)
557{
558 struct hci_cp_write_eir cp;
559
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200560 if (!hdev_is_powered(hdev))
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200561 return 0;
562
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300563 if (!(hdev->features[6] & LMP_EXT_INQ))
564 return 0;
565
Johan Hedberg84bde9d2012-01-25 14:21:06 +0200566 if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300567 return 0;
568
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200569 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300570 return 0;
571
572 memset(&cp, 0, sizeof(cp));
573
574 create_eir(hdev, cp.data);
575
576 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
577 return 0;
578
579 memcpy(hdev->eir, cp.data, sizeof(cp.data));
580
581 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
582}
583
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200584static u8 get_service_classes(struct hci_dev *hdev)
585{
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300586 struct bt_uuid *uuid;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200587 u8 val = 0;
588
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300589 list_for_each_entry(uuid, &hdev->uuids, list)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200590 val |= uuid->svc_hint;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200591
592 return val;
593}
594
595static int update_class(struct hci_dev *hdev)
596{
597 u8 cod[3];
Johan Hedbergc95f0ba2012-02-23 22:54:38 +0200598 int err;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200599
600 BT_DBG("%s", hdev->name);
601
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200602 if (!hdev_is_powered(hdev))
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200603 return 0;
604
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200605 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200606 return 0;
607
608 cod[0] = hdev->minor_class;
609 cod[1] = hdev->major_class;
610 cod[2] = get_service_classes(hdev);
611
612 if (memcmp(cod, hdev->dev_class, 3) == 0)
613 return 0;
614
Johan Hedbergc95f0ba2012-02-23 22:54:38 +0200615 err = hci_send_cmd(hdev, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
616 if (err == 0)
617 set_bit(HCI_PENDING_CLASS, &hdev->dev_flags);
618
619 return err;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200620}
621
Johan Hedberg7d785252011-12-15 00:47:39 +0200622static void service_cache_off(struct work_struct *work)
623{
624 struct hci_dev *hdev = container_of(work, struct hci_dev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300625 service_cache.work);
Johan Hedberg7d785252011-12-15 00:47:39 +0200626
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200627 if (!test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200628 return;
629
630 hci_dev_lock(hdev);
631
632 update_eir(hdev);
633 update_class(hdev);
634
635 hci_dev_unlock(hdev);
636}
637
Johan Hedberg6a919082012-02-28 06:17:26 +0200638static void mgmt_init_hdev(struct sock *sk, struct hci_dev *hdev)
Johan Hedberg7d785252011-12-15 00:47:39 +0200639{
Johan Hedberg4f87da82012-03-02 19:55:56 +0200640 if (test_and_set_bit(HCI_MGMT, &hdev->dev_flags))
Johan Hedberg6a919082012-02-28 06:17:26 +0200641 return;
642
Johan Hedberg4f87da82012-03-02 19:55:56 +0200643 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
Johan Hedberg7d785252011-12-15 00:47:39 +0200644
Johan Hedberg4f87da82012-03-02 19:55:56 +0200645 /* Non-mgmt controlled devices get this bit set
646 * implicitly so that pairing works for them, however
647 * for mgmt we require user-space to explicitly enable
648 * it
649 */
650 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedberg7d785252011-12-15 00:47:39 +0200651}
652
Johan Hedberg0f4e68c2012-02-28 17:18:30 +0200653static int read_controller_info(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300654 void *data, u16 data_len)
Johan Hedberg03811012010-12-08 00:21:06 +0200655{
656 struct mgmt_rp_read_info rp;
Johan Hedberg03811012010-12-08 00:21:06 +0200657
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200658 BT_DBG("sock %p %s", sk, hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200659
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300660 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200661
Johan Hedberg03811012010-12-08 00:21:06 +0200662 memset(&rp, 0, sizeof(rp));
663
Johan Hedberg03811012010-12-08 00:21:06 +0200664 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200665
666 rp.version = hdev->hci_ver;
667
Johan Hedberg03811012010-12-08 00:21:06 +0200668 put_unaligned_le16(hdev->manufacturer, &rp.manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200669
670 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
671 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
672
673 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedberg03811012010-12-08 00:21:06 +0200674
675 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
Johan Hedberg27fcc362012-02-22 21:46:22 +0200676 memcpy(rp.short_name, hdev->short_name, sizeof(hdev->short_name));
Johan Hedberg03811012010-12-08 00:21:06 +0200677
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300678 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200679
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200680 return cmd_complete(sk, hdev->id, MGMT_OP_READ_INFO, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300681 sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +0200682}
683
684static void mgmt_pending_free(struct pending_cmd *cmd)
685{
686 sock_put(cmd->sk);
687 kfree(cmd->param);
688 kfree(cmd);
689}
690
691static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300692 struct hci_dev *hdev, void *data,
693 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200694{
695 struct pending_cmd *cmd;
696
697 cmd = kmalloc(sizeof(*cmd), GFP_ATOMIC);
698 if (!cmd)
699 return NULL;
700
701 cmd->opcode = opcode;
702 cmd->index = hdev->id;
703
704 cmd->param = kmalloc(len, GFP_ATOMIC);
705 if (!cmd->param) {
706 kfree(cmd);
707 return NULL;
708 }
709
710 if (data)
711 memcpy(cmd->param, data, len);
712
713 cmd->sk = sk;
714 sock_hold(sk);
715
716 list_add(&cmd->list, &hdev->mgmt_pending);
717
718 return cmd;
719}
720
721static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300722 void (*cb)(struct pending_cmd *cmd, void *data),
723 void *data)
Johan Hedberg03811012010-12-08 00:21:06 +0200724{
725 struct list_head *p, *n;
726
727 list_for_each_safe(p, n, &hdev->mgmt_pending) {
728 struct pending_cmd *cmd;
729
730 cmd = list_entry(p, struct pending_cmd, list);
731
732 if (opcode > 0 && cmd->opcode != opcode)
733 continue;
734
735 cb(cmd, data);
736 }
737}
738
739static struct pending_cmd *mgmt_pending_find(u16 opcode, struct hci_dev *hdev)
740{
741 struct pending_cmd *cmd;
742
743 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
744 if (cmd->opcode == opcode)
745 return cmd;
746 }
747
748 return NULL;
749}
750
751static void mgmt_pending_remove(struct pending_cmd *cmd)
752{
753 list_del(&cmd->list);
754 mgmt_pending_free(cmd);
755}
756
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200757static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +0200758{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200759 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +0200760
Johan Hedbergaee9b2182012-02-18 15:07:59 +0200761 return cmd_complete(sk, hdev->id, opcode, 0, &settings,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300762 sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +0200763}
764
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200765static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300766 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200767{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300768 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200769 struct pending_cmd *cmd;
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200770 int err;
Johan Hedberg03811012010-12-08 00:21:06 +0200771
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200772 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200773
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300774 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200775
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100776 if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) {
777 cancel_delayed_work(&hdev->power_off);
778
779 if (cp->val) {
780 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
781 mgmt_powered(hdev, 1);
782 goto failed;
783 }
784 }
785
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200786 if (!!cp->val == hdev_is_powered(hdev)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200787 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200788 goto failed;
789 }
790
791 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200792 err = cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300793 MGMT_STATUS_BUSY);
Johan Hedberg03811012010-12-08 00:21:06 +0200794 goto failed;
795 }
796
797 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
798 if (!cmd) {
799 err = -ENOMEM;
800 goto failed;
801 }
802
803 if (cp->val)
Gustavo F. Padovan7f971042011-12-18 12:40:32 -0200804 schedule_work(&hdev->power_on);
Johan Hedberg03811012010-12-08 00:21:06 +0200805 else
Gustavo F. Padovan80b7ab32011-12-17 14:52:27 -0200806 schedule_work(&hdev->power_off.work);
Johan Hedberg03811012010-12-08 00:21:06 +0200807
808 err = 0;
809
810failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300811 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200812 return err;
813}
814
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300815static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, u16 data_len,
816 struct sock *skip_sk)
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200817{
818 struct sk_buff *skb;
819 struct mgmt_hdr *hdr;
820
821 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_ATOMIC);
822 if (!skb)
823 return -ENOMEM;
824
825 hdr = (void *) skb_put(skb, sizeof(*hdr));
826 hdr->opcode = cpu_to_le16(event);
827 if (hdev)
828 hdr->index = cpu_to_le16(hdev->id);
829 else
830 hdr->index = cpu_to_le16(MGMT_INDEX_NONE);
831 hdr->len = cpu_to_le16(data_len);
832
833 if (data)
834 memcpy(skb_put(skb, data_len), data, data_len);
835
Marcel Holtmann97e0bde2012-02-22 13:49:28 +0100836 /* Time stamp */
837 __net_timestamp(skb);
838
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200839 hci_send_to_control(skb, skip_sk);
840 kfree_skb(skb);
841
842 return 0;
843}
844
845static int new_settings(struct hci_dev *hdev, struct sock *skip)
846{
847 __le32 ev;
848
849 ev = cpu_to_le32(get_current_settings(hdev));
850
851 return mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), skip);
852}
853
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200854static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300855 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200856{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300857 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200858 struct pending_cmd *cmd;
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200859 u16 timeout;
Johan Hedberg03811012010-12-08 00:21:06 +0200860 u8 scan;
861 int err;
862
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200863 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200864
Marcel Holtmann24c54a92012-02-22 18:06:34 +0100865 timeout = get_unaligned_le16(&cp->timeout);
866 if (!cp->val && timeout > 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200867 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300868 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200869
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300870 hci_dev_lock(hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200871
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200872 if (!hdev_is_powered(hdev) && timeout > 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200873 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300874 MGMT_STATUS_NOT_POWERED);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200875 goto failed;
876 }
877
878 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
879 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200880 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300881 MGMT_STATUS_BUSY);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200882 goto failed;
883 }
884
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200885 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200886 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300887 MGMT_STATUS_REJECTED);
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200888 goto failed;
889 }
890
891 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200892 bool changed = false;
893
894 if (!!cp->val != test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
895 change_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
896 changed = true;
897 }
898
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200899 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200900 if (err < 0)
901 goto failed;
902
903 if (changed)
904 err = new_settings(hdev, sk);
905
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200906 goto failed;
907 }
908
909 if (!!cp->val == test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
Marcel Holtmann955638e2012-02-22 18:21:00 +0100910 if (hdev->discov_timeout > 0) {
911 cancel_delayed_work(&hdev->discov_off);
912 hdev->discov_timeout = 0;
913 }
914
915 if (cp->val && timeout > 0) {
916 hdev->discov_timeout = timeout;
917 queue_delayed_work(hdev->workqueue, &hdev->discov_off,
918 msecs_to_jiffies(hdev->discov_timeout * 1000));
919 }
920
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200921 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200922 goto failed;
923 }
924
925 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
926 if (!cmd) {
927 err = -ENOMEM;
928 goto failed;
929 }
930
931 scan = SCAN_PAGE;
932
933 if (cp->val)
934 scan |= SCAN_INQUIRY;
935 else
936 cancel_delayed_work(&hdev->discov_off);
937
938 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
939 if (err < 0)
940 mgmt_pending_remove(cmd);
941
Johan Hedberg03811012010-12-08 00:21:06 +0200942 if (cp->val)
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200943 hdev->discov_timeout = timeout;
Johan Hedberg03811012010-12-08 00:21:06 +0200944
945failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300946 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200947 return err;
948}
949
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200950static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300951 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200952{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300953 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200954 struct pending_cmd *cmd;
955 u8 scan;
956 int err;
957
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200958 BT_DBG("request for %s", hdev->name);
Johan Hedberge41d8b42010-12-13 21:07:03 +0200959
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300960 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200961
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200962 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200963 bool changed = false;
964
965 if (!!cp->val != test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
966 changed = true;
967
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +0200968 if (cp->val) {
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200969 set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +0200970 } else {
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200971 clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
972 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
973 }
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200974
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200975 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200976 if (err < 0)
977 goto failed;
978
979 if (changed)
980 err = new_settings(hdev, sk);
981
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200982 goto failed;
983 }
984
985 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
986 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200987 err = cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300988 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200989 goto failed;
990 }
991
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200992 if (!!cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200993 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200994 goto failed;
995 }
996
997 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
998 if (!cmd) {
999 err = -ENOMEM;
1000 goto failed;
1001 }
1002
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001003 if (cp->val) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001004 scan = SCAN_PAGE;
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001005 } else {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001006 scan = 0;
1007
Johan Hedbergdf2c6c52012-02-21 19:15:49 +02001008 if (test_bit(HCI_ISCAN, &hdev->flags) &&
1009 hdev->discov_timeout > 0)
1010 cancel_delayed_work(&hdev->discov_off);
1011 }
1012
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001013 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1014 if (err < 0)
1015 mgmt_pending_remove(cmd);
1016
1017failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001018 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001019 return err;
1020}
1021
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001022static int set_pairable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001023 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001024{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001025 struct mgmt_mode *cp = data;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001026 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001027
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001028 BT_DBG("request for %s", hdev->name);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001029
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001030 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001031
1032 if (cp->val)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001033 set_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001034 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001035 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001036
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001037 err = send_settings_rsp(sk, MGMT_OP_SET_PAIRABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001038 if (err < 0)
1039 goto failed;
1040
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001041 err = new_settings(hdev, sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001042
1043failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001044 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001045 return err;
1046}
Johan Hedberg72a734e2010-12-30 00:38:22 +02001047
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001048static int set_link_security(struct sock *sk, struct hci_dev *hdev, void *data,
1049 u16 len)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001050{
1051 struct mgmt_mode *cp = data;
1052 struct pending_cmd *cmd;
Johan Hedberg816a11d2012-02-26 13:04:52 +02001053 u8 val;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001054 int err;
1055
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001056 BT_DBG("request for %s", hdev->name);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001057
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001058 hci_dev_lock(hdev);
1059
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001060 if (!hdev_is_powered(hdev)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001061 bool changed = false;
1062
1063 if (!!cp->val != test_bit(HCI_LINK_SECURITY,
1064 &hdev->dev_flags)) {
1065 change_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
1066 changed = true;
1067 }
1068
1069 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1070 if (err < 0)
1071 goto failed;
1072
1073 if (changed)
1074 err = new_settings(hdev, sk);
1075
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001076 goto failed;
1077 }
1078
1079 if (mgmt_pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001080 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001081 MGMT_STATUS_BUSY);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001082 goto failed;
1083 }
1084
1085 val = !!cp->val;
1086
1087 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1088 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1089 goto failed;
1090 }
1091
1092 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1093 if (!cmd) {
1094 err = -ENOMEM;
1095 goto failed;
1096 }
1097
1098 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1099 if (err < 0) {
1100 mgmt_pending_remove(cmd);
1101 goto failed;
1102 }
1103
1104failed:
1105 hci_dev_unlock(hdev);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001106 return err;
1107}
1108
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001109static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001110{
1111 struct mgmt_mode *cp = data;
1112 struct pending_cmd *cmd;
Johan Hedberg816a11d2012-02-26 13:04:52 +02001113 u8 val;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001114 int err;
1115
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001116 BT_DBG("request for %s", hdev->name);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001117
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001118 hci_dev_lock(hdev);
1119
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001120 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001121 err = cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001122 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001123 goto failed;
1124 }
1125
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001126 val = !!cp->val;
1127
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001128 if (!hdev_is_powered(hdev)) {
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001129 bool changed = false;
1130
1131 if (val != test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) {
1132 change_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
1133 changed = true;
1134 }
1135
1136 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1137 if (err < 0)
1138 goto failed;
1139
1140 if (changed)
1141 err = new_settings(hdev, sk);
1142
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001143 goto failed;
1144 }
1145
1146 if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev)) {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001147 err = cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1148 MGMT_STATUS_BUSY);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001149 goto failed;
1150 }
1151
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001152 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) == val) {
1153 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1154 goto failed;
1155 }
1156
1157 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1158 if (!cmd) {
1159 err = -ENOMEM;
1160 goto failed;
1161 }
1162
1163 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, sizeof(val), &val);
1164 if (err < 0) {
1165 mgmt_pending_remove(cmd);
1166 goto failed;
1167 }
1168
1169failed:
1170 hci_dev_unlock(hdev);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001171 return err;
1172}
1173
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001174static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001175{
1176 struct mgmt_mode *cp = data;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001177
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001178 BT_DBG("request for %s", hdev->name);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001179
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001180 if (!enable_hs)
1181 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001182 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001183
1184 if (cp->val)
1185 set_bit(HCI_HS_ENABLED, &hdev->dev_flags);
1186 else
1187 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
1188
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001189 return send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001190}
1191
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001192static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001193{
1194 struct mgmt_mode *cp = data;
1195 struct hci_cp_write_le_host_supported hci_cp;
1196 struct pending_cmd *cmd;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001197 int err;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001198 u8 val, enabled;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001199
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001200 BT_DBG("request for %s", hdev->name);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001201
Johan Hedberg1de028c2012-02-29 19:55:35 -08001202 hci_dev_lock(hdev);
1203
Johan Hedberg06199cf2012-02-22 16:37:11 +02001204 if (!enable_le || !(hdev->features[4] & LMP_LE)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001205 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001206 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001207 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001208 }
1209
1210 val = !!cp->val;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001211 enabled = !!(hdev->host_features[0] & LMP_HOST_LE);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001212
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001213 if (!hdev_is_powered(hdev) || val == enabled) {
Johan Hedberg06199cf2012-02-22 16:37:11 +02001214 bool changed = false;
1215
1216 if (val != test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
1217 change_bit(HCI_LE_ENABLED, &hdev->dev_flags);
1218 changed = true;
1219 }
1220
1221 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1222 if (err < 0)
Johan Hedberg1de028c2012-02-29 19:55:35 -08001223 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001224
1225 if (changed)
1226 err = new_settings(hdev, sk);
1227
Johan Hedberg1de028c2012-02-29 19:55:35 -08001228 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001229 }
1230
1231 if (mgmt_pending_find(MGMT_OP_SET_LE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001232 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001233 MGMT_STATUS_BUSY);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001234 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001235 }
1236
1237 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
1238 if (!cmd) {
1239 err = -ENOMEM;
Johan Hedberg1de028c2012-02-29 19:55:35 -08001240 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001241 }
1242
1243 memset(&hci_cp, 0, sizeof(hci_cp));
1244
1245 if (val) {
1246 hci_cp.le = val;
1247 hci_cp.simul = !!(hdev->features[6] & LMP_SIMUL_LE_BR);
1248 }
1249
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001250 err = hci_send_cmd(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp),
1251 &hci_cp);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001252 if (err < 0) {
1253 mgmt_pending_remove(cmd);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001254 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001255 }
1256
Johan Hedberg1de028c2012-02-29 19:55:35 -08001257unlock:
1258 hci_dev_unlock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001259 return err;
1260}
1261
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001262static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001263{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001264 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001265 struct pending_cmd *cmd;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001266 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001267 int err;
1268
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001269 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001270
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001271 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001272
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001273 if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001274 err = cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001275 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001276 goto failed;
1277 }
1278
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001279 uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC);
1280 if (!uuid) {
1281 err = -ENOMEM;
1282 goto failed;
1283 }
1284
1285 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001286 uuid->svc_hint = cp->svc_hint;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001287
1288 list_add(&uuid->list, &hdev->uuids);
1289
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001290 err = update_class(hdev);
1291 if (err < 0)
1292 goto failed;
1293
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001294 err = update_eir(hdev);
1295 if (err < 0)
1296 goto failed;
1297
Johan Hedberg90e70452012-02-23 23:09:40 +02001298 if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001299 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001300 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001301 goto failed;
1302 }
1303
1304 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len);
1305 if (!cmd) {
1306 err = -ENOMEM;
1307 goto failed;
1308 }
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001309
1310failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001311 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001312 return err;
1313}
1314
Johan Hedberg24b78d02012-02-23 23:24:30 +02001315static bool enable_service_cache(struct hci_dev *hdev)
1316{
1317 if (!hdev_is_powered(hdev))
1318 return false;
1319
1320 if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Marcel Holtmann17b02e62012-03-01 14:32:37 -08001321 schedule_delayed_work(&hdev->service_cache, CACHE_TIMEOUT);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001322 return true;
1323 }
1324
1325 return false;
1326}
1327
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001328static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
1329 u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001330{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001331 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001332 struct pending_cmd *cmd;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001333 struct list_head *p, *n;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001334 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 +02001335 int err, found;
1336
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001337 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001338
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001339 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001340
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001341 if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001342 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001343 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001344 goto unlock;
1345 }
1346
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001347 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
1348 err = hci_uuids_clear(hdev);
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001349
Johan Hedberg24b78d02012-02-23 23:24:30 +02001350 if (enable_service_cache(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001351 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001352 0, hdev->dev_class, 3);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001353 goto unlock;
1354 }
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001355
Johan Hedberg9246a862012-02-23 21:33:16 +02001356 goto update_class;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001357 }
1358
1359 found = 0;
1360
1361 list_for_each_safe(p, n, &hdev->uuids) {
1362 struct bt_uuid *match = list_entry(p, struct bt_uuid, list);
1363
1364 if (memcmp(match->uuid, cp->uuid, 16) != 0)
1365 continue;
1366
1367 list_del(&match->list);
1368 found++;
1369 }
1370
1371 if (found == 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001372 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001373 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001374 goto unlock;
1375 }
1376
Johan Hedberg9246a862012-02-23 21:33:16 +02001377update_class:
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001378 err = update_class(hdev);
1379 if (err < 0)
1380 goto unlock;
1381
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001382 err = update_eir(hdev);
1383 if (err < 0)
1384 goto unlock;
1385
Johan Hedberg90e70452012-02-23 23:09:40 +02001386 if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001387 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001388 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001389 goto unlock;
1390 }
1391
1392 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
1393 if (!cmd) {
1394 err = -ENOMEM;
1395 goto unlock;
1396 }
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001397
1398unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001399 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001400 return err;
1401}
1402
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001403static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001404 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001405{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001406 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001407 struct pending_cmd *cmd;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001408 int err;
1409
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001410 BT_DBG("request for %s", hdev->name);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001411
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001412 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001413
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001414 if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001415 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001416 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001417 goto unlock;
1418 }
1419
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001420 hdev->major_class = cp->major;
1421 hdev->minor_class = cp->minor;
1422
Johan Hedberg932f5ff2012-02-22 22:11:32 +02001423 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001424 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001425 hdev->dev_class, 3);
Johan Hedberg932f5ff2012-02-22 22:11:32 +02001426 goto unlock;
1427 }
1428
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001429 if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02001430 hci_dev_unlock(hdev);
1431 cancel_delayed_work_sync(&hdev->service_cache);
1432 hci_dev_lock(hdev);
Johan Hedberg14c0b602011-12-15 00:47:37 +02001433 update_eir(hdev);
Johan Hedberg7d785252011-12-15 00:47:39 +02001434 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02001435
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001436 err = update_class(hdev);
Johan Hedberg90e70452012-02-23 23:09:40 +02001437 if (err < 0)
1438 goto unlock;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001439
Johan Hedberg90e70452012-02-23 23:09:40 +02001440 if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001441 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001442 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001443 goto unlock;
1444 }
1445
1446 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
1447 if (!cmd) {
1448 err = -ENOMEM;
1449 goto unlock;
1450 }
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001451
Johan Hedbergb5235a62012-02-21 14:32:24 +02001452unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001453 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001454 return err;
1455}
1456
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001457static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
1458 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001459{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001460 struct mgmt_cp_load_link_keys *cp = data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001461 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001462 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001463
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001464 key_count = get_unaligned_le16(&cp->key_count);
1465
Johan Hedberg86742e12011-11-07 23:13:38 +02001466 expected_len = sizeof(*cp) + key_count *
1467 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001468 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001469 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001470 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001471 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001472 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001473 }
1474
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001475 BT_DBG("%s debug_keys %u key_count %u", hdev->name, cp->debug_keys,
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001476 key_count);
1477
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001478 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001479
1480 hci_link_keys_clear(hdev);
1481
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001482 set_bit(HCI_LINK_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001483
1484 if (cp->debug_keys)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001485 set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001486 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001487 clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001488
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001489 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001490 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001491
Johan Hedbergd753fdc2012-02-17 14:06:34 +02001492 hci_add_link_key(hdev, NULL, 0, &key->addr.bdaddr, key->val,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001493 key->type, key->pin_len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001494 }
1495
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001496 cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02001497
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001498 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001499
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001500 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001501}
1502
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001503static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001504 u8 addr_type, struct sock *skip_sk)
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001505{
1506 struct mgmt_ev_device_unpaired ev;
1507
1508 bacpy(&ev.addr.bdaddr, bdaddr);
1509 ev.addr.type = addr_type;
1510
1511 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001512 skip_sk);
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001513}
1514
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001515static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001516 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001517{
Johan Hedberg124f6e32012-02-09 13:50:12 +02001518 struct mgmt_cp_unpair_device *cp = data;
1519 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001520 struct hci_cp_disconnect dc;
1521 struct pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001522 struct hci_conn *conn;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001523 int err;
1524
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001525 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001526
Johan Hedberga8a1d192011-11-10 15:54:38 +02001527 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02001528 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1529 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001530
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001531 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001532 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001533 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001534 goto unlock;
1535 }
1536
Johan Hedberg124f6e32012-02-09 13:50:12 +02001537 if (cp->addr.type == MGMT_ADDR_BREDR)
1538 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
1539 else
1540 err = hci_remove_ltk(hdev, &cp->addr.bdaddr);
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03001541
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001542 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001543 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001544 MGMT_STATUS_NOT_PAIRED, &rp, sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001545 goto unlock;
1546 }
1547
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001548 if (cp->disconnect) {
1549 if (cp->addr.type == MGMT_ADDR_BREDR)
1550 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
1551 &cp->addr.bdaddr);
1552 else
1553 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
1554 &cp->addr.bdaddr);
1555 } else {
1556 conn = NULL;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001557 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001558
Johan Hedberga8a1d192011-11-10 15:54:38 +02001559 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001560 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001561 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001562 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001563 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001564 }
1565
Johan Hedberg124f6e32012-02-09 13:50:12 +02001566 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001567 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02001568 if (!cmd) {
1569 err = -ENOMEM;
1570 goto unlock;
1571 }
1572
1573 put_unaligned_le16(conn->handle, &dc.handle);
1574 dc.reason = 0x13; /* Remote User Terminated Connection */
1575 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1576 if (err < 0)
1577 mgmt_pending_remove(cmd);
1578
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001579unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001580 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001581 return err;
1582}
1583
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001584static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001585 u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02001586{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001587 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001588 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03001589 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001590 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001591 int err;
1592
1593 BT_DBG("");
1594
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001595 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001596
1597 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001598 err = cmd_status(sk, hdev->id, MGMT_OP_DISCONNECT,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001599 MGMT_STATUS_NOT_POWERED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001600 goto failed;
1601 }
1602
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001603 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001604 err = cmd_status(sk, hdev->id, MGMT_OP_DISCONNECT,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001605 MGMT_STATUS_BUSY);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001606 goto failed;
1607 }
1608
Johan Hedberg88c3df12012-02-09 14:27:38 +02001609 if (cp->addr.type == MGMT_ADDR_BREDR)
1610 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
1611 else
1612 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03001613
Johan Hedberg8962ee72011-01-20 12:40:27 +02001614 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001615 err = cmd_status(sk, hdev->id, MGMT_OP_DISCONNECT,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001616 MGMT_STATUS_NOT_CONNECTED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001617 goto failed;
1618 }
1619
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001620 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001621 if (!cmd) {
1622 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001623 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001624 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001625
1626 put_unaligned_le16(conn->handle, &dc.handle);
1627 dc.reason = 0x13; /* Remote User Terminated Connection */
1628
1629 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1630 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001631 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001632
1633failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001634 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001635 return err;
1636}
1637
Johan Hedberg48264f02011-11-09 13:58:58 +02001638static u8 link_to_mgmt(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02001639{
1640 switch (link_type) {
1641 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02001642 switch (addr_type) {
1643 case ADDR_LE_DEV_PUBLIC:
1644 return MGMT_ADDR_LE_PUBLIC;
1645 case ADDR_LE_DEV_RANDOM:
1646 return MGMT_ADDR_LE_RANDOM;
1647 default:
1648 return MGMT_ADDR_INVALID;
1649 }
Johan Hedberg4c659c32011-11-07 23:13:39 +02001650 case ACL_LINK:
1651 return MGMT_ADDR_BREDR;
1652 default:
1653 return MGMT_ADDR_INVALID;
1654 }
1655}
1656
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001657static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data,
1658 u16 data_len)
Johan Hedberg2784eb42011-01-21 13:56:35 +02001659{
Johan Hedberg2784eb42011-01-21 13:56:35 +02001660 struct mgmt_rp_get_connections *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001661 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02001662 size_t rp_len;
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001663 int err;
1664 u16 i;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001665
1666 BT_DBG("");
1667
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001668 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001669
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001670 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001671 err = cmd_status(sk, hdev->id, MGMT_OP_GET_CONNECTIONS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001672 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001673 goto unlock;
1674 }
1675
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001676 i = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02001677 list_for_each_entry(c, &hdev->conn_hash.list, list) {
1678 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001679 i++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001680 }
1681
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001682 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberga38528f2011-01-22 06:46:43 +02001683 rp = kmalloc(rp_len, GFP_ATOMIC);
1684 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02001685 err = -ENOMEM;
1686 goto unlock;
1687 }
1688
Johan Hedberg2784eb42011-01-21 13:56:35 +02001689 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001690 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02001691 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
1692 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001693 bacpy(&rp->addr[i].bdaddr, &c->dst);
Johan Hedberg48264f02011-11-09 13:58:58 +02001694 rp->addr[i].type = link_to_mgmt(c->type, c->dst_type);
Johan Hedberg4c659c32011-11-07 23:13:39 +02001695 if (rp->addr[i].type == MGMT_ADDR_INVALID)
1696 continue;
1697 i++;
1698 }
1699
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001700 put_unaligned_le16(i, &rp->conn_count);
1701
Johan Hedberg4c659c32011-11-07 23:13:39 +02001702 /* Recalculate length in case of filtered SCO connections, etc */
1703 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02001704
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001705 err = cmd_complete(sk, hdev->id, MGMT_OP_GET_CONNECTIONS, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001706 rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001707
Johan Hedberga38528f2011-01-22 06:46:43 +02001708 kfree(rp);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001709
1710unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001711 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001712 return err;
1713}
1714
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001715static int send_pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001716 struct mgmt_cp_pin_code_neg_reply *cp)
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001717{
1718 struct pending_cmd *cmd;
1719 int err;
1720
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001721 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001722 sizeof(*cp));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001723 if (!cmd)
1724 return -ENOMEM;
1725
Johan Hedbergd8457692012-02-17 14:24:57 +02001726 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001727 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001728 if (err < 0)
1729 mgmt_pending_remove(cmd);
1730
1731 return err;
1732}
1733
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001734static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001735 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001736{
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001737 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001738 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001739 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03001740 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001741 int err;
1742
1743 BT_DBG("");
1744
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001745 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001746
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001747 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001748 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001749 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001750 goto failed;
1751 }
1752
Johan Hedbergd8457692012-02-17 14:24:57 +02001753 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001754 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001755 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001756 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001757 goto failed;
1758 }
1759
1760 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02001761 struct mgmt_cp_pin_code_neg_reply ncp;
1762
1763 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001764
1765 BT_ERR("PIN code is not 16 bytes long");
1766
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001767 err = send_pin_code_neg_reply(sk, hdev, &ncp);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001768 if (err >= 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001769 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001770 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001771
1772 goto failed;
1773 }
1774
Gustavo F. Padovan00abfe42012-03-01 00:37:10 -03001775 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001776 if (!cmd) {
1777 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001778 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001779 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02001780
Johan Hedbergd8457692012-02-17 14:24:57 +02001781 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001782 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02001783 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02001784
1785 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
1786 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001787 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001788
1789failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001790 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001791 return err;
1792}
1793
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001794static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001795 void *data, u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001796{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001797 struct mgmt_cp_pin_code_neg_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001798 int err;
1799
1800 BT_DBG("");
1801
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001802 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001803
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001804 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001805 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001806 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001807 goto failed;
1808 }
1809
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001810 err = send_pin_code_neg_reply(sk, hdev, cp);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001811
1812failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001813 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001814 return err;
1815}
1816
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001817static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,
1818 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001819{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001820 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001821
1822 BT_DBG("");
1823
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001824 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001825
1826 hdev->io_capability = cp->io_capability;
1827
1828 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Szymon Jancb8534e02011-03-01 16:55:34 +01001829 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001830
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001831 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001832
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001833 return cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, 0, NULL,
1834 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001835}
1836
Johan Hedberge9a416b2011-02-19 12:05:56 -03001837static inline struct pending_cmd *find_pairing(struct hci_conn *conn)
1838{
1839 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001840 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001841
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001842 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03001843 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
1844 continue;
1845
Johan Hedberge9a416b2011-02-19 12:05:56 -03001846 if (cmd->user_data != conn)
1847 continue;
1848
1849 return cmd;
1850 }
1851
1852 return NULL;
1853}
1854
1855static void pairing_complete(struct pending_cmd *cmd, u8 status)
1856{
1857 struct mgmt_rp_pair_device rp;
1858 struct hci_conn *conn = cmd->user_data;
1859
Johan Hedbergba4e5642011-11-11 00:07:34 +02001860 bacpy(&rp.addr.bdaddr, &conn->dst);
1861 rp.addr.type = link_to_mgmt(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001862
Johan Hedbergaee9b2182012-02-18 15:07:59 +02001863 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001864 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001865
1866 /* So we don't get further callbacks for this connection */
1867 conn->connect_cfm_cb = NULL;
1868 conn->security_cfm_cb = NULL;
1869 conn->disconn_cfm_cb = NULL;
1870
1871 hci_conn_put(conn);
1872
Johan Hedberga664b5b2011-02-19 12:06:02 -03001873 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001874}
1875
1876static void pairing_complete_cb(struct hci_conn *conn, u8 status)
1877{
1878 struct pending_cmd *cmd;
1879
1880 BT_DBG("status %u", status);
1881
Johan Hedberg56e5cb82011-11-08 20:40:16 +02001882 cmd = find_pairing(conn);
1883 if (!cmd)
1884 BT_DBG("Unable to find a pending command");
1885 else
Johan Hedberge2113262012-02-18 15:20:03 +02001886 pairing_complete(cmd, mgmt_status(status));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001887}
1888
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001889static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001890 u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001891{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001892 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02001893 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001894 struct pending_cmd *cmd;
1895 u8 sec_level, auth_type;
1896 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001897 int err;
1898
1899 BT_DBG("");
1900
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001901 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001902
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001903 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001904 err = cmd_status(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001905 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001906 goto unlock;
1907 }
1908
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001909 sec_level = BT_SECURITY_MEDIUM;
1910 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001911 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001912 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03001913 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001914
Johan Hedbergba4e5642011-11-11 00:07:34 +02001915 if (cp->addr.type == MGMT_ADDR_BREDR)
1916 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr, sec_level,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001917 auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001918 else
Johan Hedbergba4e5642011-11-11 00:07:34 +02001919 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr, sec_level,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001920 auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001921
Johan Hedberg1425acb2011-11-11 00:07:35 +02001922 memset(&rp, 0, sizeof(rp));
1923 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1924 rp.addr.type = cp->addr.type;
1925
Ville Tervo30e76272011-02-22 16:10:53 -03001926 if (IS_ERR(conn)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001927 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001928 MGMT_STATUS_CONNECT_FAILED, &rp,
1929 sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001930 goto unlock;
1931 }
1932
1933 if (conn->connect_cfm_cb) {
1934 hci_conn_put(conn);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001935 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001936 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001937 goto unlock;
1938 }
1939
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001940 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001941 if (!cmd) {
1942 err = -ENOMEM;
1943 hci_conn_put(conn);
1944 goto unlock;
1945 }
1946
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001947 /* For LE, just connecting isn't a proof that the pairing finished */
Johan Hedbergba4e5642011-11-11 00:07:34 +02001948 if (cp->addr.type == MGMT_ADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001949 conn->connect_cfm_cb = pairing_complete_cb;
1950
Johan Hedberge9a416b2011-02-19 12:05:56 -03001951 conn->security_cfm_cb = pairing_complete_cb;
1952 conn->disconn_cfm_cb = pairing_complete_cb;
1953 conn->io_capability = cp->io_cap;
1954 cmd->user_data = conn;
1955
1956 if (conn->state == BT_CONNECTED &&
1957 hci_conn_security(conn, sec_level, auth_type))
1958 pairing_complete(cmd, 0);
1959
1960 err = 0;
1961
1962unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001963 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001964 return err;
1965}
1966
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001967static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
1968 u16 len)
Johan Hedberg28424702012-02-02 04:02:29 +02001969{
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02001970 struct mgmt_addr_info *addr = data;
Johan Hedberg28424702012-02-02 04:02:29 +02001971 struct pending_cmd *cmd;
1972 struct hci_conn *conn;
1973 int err;
1974
1975 BT_DBG("");
1976
Johan Hedberg28424702012-02-02 04:02:29 +02001977 hci_dev_lock(hdev);
1978
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001979 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001980 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001981 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001982 goto unlock;
1983 }
1984
Johan Hedberg28424702012-02-02 04:02:29 +02001985 cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
1986 if (!cmd) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001987 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001988 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02001989 goto unlock;
1990 }
1991
1992 conn = cmd->user_data;
1993
1994 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001995 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001996 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02001997 goto unlock;
1998 }
1999
2000 pairing_complete(cmd, MGMT_STATUS_CANCELLED);
2001
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002002 err = cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002003 addr, sizeof(*addr));
Johan Hedberg28424702012-02-02 04:02:29 +02002004unlock:
2005 hci_dev_unlock(hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02002006 return err;
2007}
2008
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002009static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002010 bdaddr_t *bdaddr, u8 type, u16 mgmt_op,
2011 u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03002012{
Johan Hedberga5c29682011-02-19 12:05:57 -03002013 struct pending_cmd *cmd;
Brian Gix0df4c182011-11-16 13:53:13 -08002014 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03002015 int err;
2016
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002017 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02002018
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002019 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002020 err = cmd_status(sk, hdev->id, mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002021 MGMT_STATUS_NOT_POWERED);
Brian Gix0df4c182011-11-16 13:53:13 -08002022 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002023 }
2024
Johan Hedberg272d90d2012-02-09 15:26:12 +02002025 if (type == MGMT_ADDR_BREDR)
2026 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, bdaddr);
2027 else
Brian Gix47c15e22011-11-16 13:53:14 -08002028 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, bdaddr);
Brian Gix47c15e22011-11-16 13:53:14 -08002029
Johan Hedberg272d90d2012-02-09 15:26:12 +02002030 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002031 err = cmd_status(sk, hdev->id, mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002032 MGMT_STATUS_NOT_CONNECTED);
Johan Hedberg272d90d2012-02-09 15:26:12 +02002033 goto done;
2034 }
2035
2036 if (type == MGMT_ADDR_LE_PUBLIC || type == MGMT_ADDR_LE_RANDOM) {
Brian Gix47c15e22011-11-16 13:53:14 -08002037 /* Continue with pairing via SMP */
Brian Gix5fe57d92011-12-21 16:12:13 -08002038 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix47c15e22011-11-16 13:53:14 -08002039
Brian Gix5fe57d92011-12-21 16:12:13 -08002040 if (!err)
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002041 err = cmd_status(sk, hdev->id, mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002042 MGMT_STATUS_SUCCESS);
Brian Gix5fe57d92011-12-21 16:12:13 -08002043 else
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002044 err = cmd_status(sk, hdev->id, mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002045 MGMT_STATUS_FAILED);
Brian Gix5fe57d92011-12-21 16:12:13 -08002046
Brian Gix47c15e22011-11-16 13:53:14 -08002047 goto done;
2048 }
2049
Brian Gix0df4c182011-11-16 13:53:13 -08002050 cmd = mgmt_pending_add(sk, mgmt_op, hdev, bdaddr, sizeof(*bdaddr));
Johan Hedberga5c29682011-02-19 12:05:57 -03002051 if (!cmd) {
2052 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08002053 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002054 }
2055
Brian Gix0df4c182011-11-16 13:53:13 -08002056 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08002057 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
2058 struct hci_cp_user_passkey_reply cp;
2059
2060 bacpy(&cp.bdaddr, bdaddr);
2061 cp.passkey = passkey;
2062 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
2063 } else
2064 err = hci_send_cmd(hdev, hci_op, sizeof(*bdaddr), bdaddr);
2065
Johan Hedberga664b5b2011-02-19 12:06:02 -03002066 if (err < 0)
2067 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002068
Brian Gix0df4c182011-11-16 13:53:13 -08002069done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002070 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002071 return err;
2072}
2073
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002074static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2075 u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002076{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002077 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002078
2079 BT_DBG("");
2080
2081 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002082 return cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002083 MGMT_STATUS_INVALID_PARAMS);
Brian Gix0df4c182011-11-16 13:53:13 -08002084
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002085 return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002086 MGMT_OP_USER_CONFIRM_REPLY,
2087 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002088}
2089
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002090static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002091 void *data, u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002092{
Johan Hedbergc9c26592011-12-15 00:47:41 +02002093 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002094
2095 BT_DBG("");
2096
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002097 return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002098 MGMT_OP_USER_CONFIRM_NEG_REPLY,
2099 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002100}
2101
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002102static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2103 u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002104{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002105 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002106
2107 BT_DBG("");
2108
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002109 return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002110 MGMT_OP_USER_PASSKEY_REPLY,
2111 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08002112}
2113
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002114static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002115 void *data, u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002116{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002117 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002118
2119 BT_DBG("");
2120
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002121 return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002122 MGMT_OP_USER_PASSKEY_NEG_REPLY,
2123 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08002124}
2125
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002126static int update_name(struct hci_dev *hdev, const char *name)
2127{
2128 struct hci_cp_write_local_name cp;
2129
2130 memcpy(cp.name, name, sizeof(cp.name));
2131
2132 return hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(cp), &cp);
2133}
2134
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002135static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002136 u16 len)
Johan Hedbergb312b1612011-03-16 14:29:37 +02002137{
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002138 struct mgmt_cp_set_local_name *cp = data;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002139 struct pending_cmd *cmd;
2140 int err;
2141
2142 BT_DBG("");
2143
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002144 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002145
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002146 memcpy(hdev->short_name, cp->short_name, sizeof(hdev->short_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002147
Johan Hedbergb5235a62012-02-21 14:32:24 +02002148 if (!hdev_is_powered(hdev)) {
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002149 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002150
2151 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002152 data, len);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002153 if (err < 0)
2154 goto failed;
2155
2156 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data, len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002157 sk);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002158
Johan Hedbergb5235a62012-02-21 14:32:24 +02002159 goto failed;
2160 }
2161
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002162 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002163 if (!cmd) {
2164 err = -ENOMEM;
2165 goto failed;
2166 }
2167
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002168 err = update_name(hdev, cp->name);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002169 if (err < 0)
2170 mgmt_pending_remove(cmd);
2171
2172failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002173 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002174 return err;
2175}
2176
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002177static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002178 void *data, u16 data_len)
Szymon Jancc35938b2011-03-22 13:12:21 +01002179{
Szymon Jancc35938b2011-03-22 13:12:21 +01002180 struct pending_cmd *cmd;
2181 int err;
2182
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002183 BT_DBG("%s", hdev->name);
Szymon Jancc35938b2011-03-22 13:12:21 +01002184
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002185 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002186
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002187 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002188 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002189 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002190 goto unlock;
2191 }
2192
2193 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002194 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002195 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002196 goto unlock;
2197 }
2198
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002199 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002200 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002201 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01002202 goto unlock;
2203 }
2204
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002205 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01002206 if (!cmd) {
2207 err = -ENOMEM;
2208 goto unlock;
2209 }
2210
2211 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
2212 if (err < 0)
2213 mgmt_pending_remove(cmd);
2214
2215unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002216 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002217 return err;
2218}
2219
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002220static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002221 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002222{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002223 struct mgmt_cp_add_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002224 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002225 int err;
2226
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002227 BT_DBG("%s ", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01002228
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002229 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002230
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002231 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002232 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002233 MGMT_STATUS_NOT_POWERED, &cp->addr,
2234 sizeof(cp->addr));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002235 goto unlock;
2236 }
2237
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002238 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, cp->hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002239 cp->randomizer);
Szymon Janc2763eda2011-03-22 13:12:22 +01002240 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002241 status = MGMT_STATUS_FAILED;
Szymon Janc2763eda2011-03-22 13:12:22 +01002242 else
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002243 status = 0;
2244
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002245 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002246 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002247
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002248unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002249 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002250 return err;
2251}
2252
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002253static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002254 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002255{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002256 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002257 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002258 int err;
2259
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002260 BT_DBG("%s", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01002261
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002262 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002263
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002264 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002265 err = cmd_complete(sk, hdev->id,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002266 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2267 MGMT_STATUS_NOT_POWERED, &cp->addr,
2268 sizeof(cp->addr));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002269 goto unlock;
2270 }
2271
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002272 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr);
Szymon Janc2763eda2011-03-22 13:12:22 +01002273 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002274 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01002275 else
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002276 status = 0;
2277
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002278 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002279 status, &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002280
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002281unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002282 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002283 return err;
2284}
2285
Andre Guedes5e0452c2012-02-17 20:39:38 -03002286int mgmt_interleaved_discovery(struct hci_dev *hdev)
2287{
2288 int err;
2289
2290 BT_DBG("%s", hdev->name);
2291
2292 hci_dev_lock(hdev);
2293
2294 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR_LE);
2295 if (err < 0)
2296 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2297
2298 hci_dev_unlock(hdev);
2299
2300 return err;
2301}
2302
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002303static int start_discovery(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002304 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002305{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002306 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002307 struct pending_cmd *cmd;
Johan Hedberg14a53662011-04-27 10:29:56 -04002308 int err;
2309
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002310 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04002311
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002312 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002313
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002314 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002315 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002316 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02002317 goto failed;
2318 }
2319
Johan Hedbergff9ef572012-01-04 14:23:45 +02002320 if (hdev->discovery.state != DISCOVERY_STOPPED) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002321 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002322 MGMT_STATUS_BUSY);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002323 goto failed;
2324 }
2325
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002326 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002327 if (!cmd) {
2328 err = -ENOMEM;
2329 goto failed;
2330 }
2331
Andre Guedes4aab14e2012-02-17 20:39:36 -03002332 hdev->discovery.type = cp->type;
2333
2334 switch (hdev->discovery.type) {
Andre Guedesf39799f2012-02-17 20:39:35 -03002335 case DISCOV_TYPE_BREDR:
Andre Guedes8b901292012-02-23 18:09:27 -03002336 if (lmp_bredr_capable(hdev))
2337 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
2338 else
2339 err = -ENOTSUPP;
Andre Guedesf39799f2012-02-17 20:39:35 -03002340 break;
2341
2342 case DISCOV_TYPE_LE:
Andre Guedes8b901292012-02-23 18:09:27 -03002343 if (lmp_host_le_capable(hdev))
2344 err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002345 LE_SCAN_WIN, LE_SCAN_TIMEOUT_LE_ONLY);
Andre Guedes8b901292012-02-23 18:09:27 -03002346 else
2347 err = -ENOTSUPP;
Andre Guedesf39799f2012-02-17 20:39:35 -03002348 break;
2349
Andre Guedes5e0452c2012-02-17 20:39:38 -03002350 case DISCOV_TYPE_INTERLEAVED:
Andre Guedes426c1892012-02-24 11:41:04 -03002351 if (lmp_host_le_capable(hdev) && lmp_bredr_capable(hdev))
2352 err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002353 LE_SCAN_WIN,
2354 LE_SCAN_TIMEOUT_BREDR_LE);
Andre Guedes426c1892012-02-24 11:41:04 -03002355 else
2356 err = -ENOTSUPP;
Andre Guedes5e0452c2012-02-17 20:39:38 -03002357 break;
2358
Andre Guedesf39799f2012-02-17 20:39:35 -03002359 default:
Andre Guedes3fd24152012-02-03 17:48:01 -03002360 err = -EINVAL;
Andre Guedesf39799f2012-02-17 20:39:35 -03002361 }
Andre Guedes3fd24152012-02-03 17:48:01 -03002362
Johan Hedberg14a53662011-04-27 10:29:56 -04002363 if (err < 0)
2364 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002365 else
2366 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002367
2368failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002369 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002370 return err;
2371}
2372
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002373static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002374 u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002375{
Johan Hedbergd9306502012-02-20 23:25:18 +02002376 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002377 struct pending_cmd *cmd;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002378 struct hci_cp_remote_name_req_cancel cp;
2379 struct inquiry_entry *e;
Johan Hedberg14a53662011-04-27 10:29:56 -04002380 int err;
2381
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002382 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04002383
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002384 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002385
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002386 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002387 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002388 MGMT_STATUS_REJECTED, &mgmt_cp->type,
2389 sizeof(mgmt_cp->type));
Johan Hedbergd9306502012-02-20 23:25:18 +02002390 goto unlock;
2391 }
2392
2393 if (hdev->discovery.type != mgmt_cp->type) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002394 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002395 MGMT_STATUS_INVALID_PARAMS, &mgmt_cp->type,
2396 sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002397 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02002398 }
2399
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002400 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002401 if (!cmd) {
2402 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002403 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04002404 }
2405
Andre Guedes343f9352012-02-17 20:39:37 -03002406 if (hdev->discovery.state == DISCOVERY_FINDING) {
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002407 err = hci_cancel_inquiry(hdev);
2408 if (err < 0)
2409 mgmt_pending_remove(cmd);
2410 else
2411 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
2412 goto unlock;
2413 }
2414
2415 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY, NAME_PENDING);
2416 if (!e) {
2417 mgmt_pending_remove(cmd);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002418 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002419 &mgmt_cp->type, sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002420 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2421 goto unlock;
2422 }
2423
2424 bacpy(&cp.bdaddr, &e->data.bdaddr);
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002425 err = hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ_CANCEL, sizeof(cp),
2426 &cp);
Johan Hedberg14a53662011-04-27 10:29:56 -04002427 if (err < 0)
2428 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002429 else
2430 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002431
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002432unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002433 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002434 return err;
2435}
2436
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002437static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002438 u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02002439{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002440 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002441 struct inquiry_entry *e;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002442 int err;
2443
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002444 BT_DBG("%s", hdev->name);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002445
Johan Hedberg561aafb2012-01-04 13:31:59 +02002446 hci_dev_lock(hdev);
2447
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002448 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002449 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002450 MGMT_STATUS_FAILED);
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002451 goto failed;
2452 }
2453
Johan Hedberga198e7b2012-02-17 14:27:06 +02002454 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002455 if (!e) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002456 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002457 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002458 goto failed;
2459 }
2460
2461 if (cp->name_known) {
2462 e->name_state = NAME_KNOWN;
2463 list_del(&e->list);
2464 } else {
2465 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e202012-01-09 00:53:02 +02002466 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002467 }
2468
2469 err = 0;
2470
2471failed:
2472 hci_dev_unlock(hdev);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002473 return err;
2474}
2475
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002476static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002477 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002478{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002479 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002480 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03002481 int err;
2482
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002483 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03002484
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002485 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002486
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002487 err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002488 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002489 status = MGMT_STATUS_FAILED;
Antti Julku7fbec222011-06-15 12:01:15 +03002490 else
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002491 status = 0;
2492
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002493 err = cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002494 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03002495
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002496 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002497
2498 return err;
2499}
2500
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002501static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002502 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002503{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002504 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002505 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03002506 int err;
2507
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002508 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03002509
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002510 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002511
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002512 err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002513 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002514 status = MGMT_STATUS_INVALID_PARAMS;
Antti Julku7fbec222011-06-15 12:01:15 +03002515 else
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002516 status = 0;
2517
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002518 err = cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002519 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03002520
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002521 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002522
2523 return err;
2524}
2525
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002526static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002527 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03002528{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002529 struct mgmt_mode *cp = data;
Antti Julkuf6422ec2011-06-22 13:11:56 +03002530 struct hci_cp_write_page_scan_activity acp;
2531 u8 type;
2532 int err;
2533
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002534 BT_DBG("%s", hdev->name);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002535
Johan Hedberg5400c042012-02-21 16:40:33 +02002536 if (!hdev_is_powered(hdev))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002537 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002538 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5400c042012-02-21 16:40:33 +02002539
2540 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002541 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002542 MGMT_STATUS_REJECTED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002543
2544 hci_dev_lock(hdev);
2545
Johan Hedbergf7c68692011-12-15 00:47:36 +02002546 if (cp->val) {
Antti Julkuf6422ec2011-06-22 13:11:56 +03002547 type = PAGE_SCAN_TYPE_INTERLACED;
Andrei Emeltchenko76ec9de2012-03-12 12:13:11 +02002548
2549 /* 22.5 msec page scan interval */
2550 acp.interval = __constant_cpu_to_le16(0x0024);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002551 } else {
2552 type = PAGE_SCAN_TYPE_STANDARD; /* default */
Andrei Emeltchenko76ec9de2012-03-12 12:13:11 +02002553
2554 /* default 1.28 sec page scan */
2555 acp.interval = __constant_cpu_to_le16(0x0800);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002556 }
2557
Andrei Emeltchenko76ec9de2012-03-12 12:13:11 +02002558 /* default 11.25 msec page scan window */
2559 acp.window = __constant_cpu_to_le16(0x0012);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002560
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002561 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY, sizeof(acp),
2562 &acp);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002563 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002564 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002565 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002566 goto done;
2567 }
2568
2569 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
2570 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002571 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002572 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002573 goto done;
2574 }
2575
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002576 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002577 NULL, 0);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002578done:
2579 hci_dev_unlock(hdev);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002580 return err;
2581}
2582
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002583static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002584 void *cp_data, u16 len)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002585{
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002586 struct mgmt_cp_load_long_term_keys *cp = cp_data;
2587 u16 key_count, expected_len;
2588 int i;
2589
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002590 key_count = get_unaligned_le16(&cp->key_count);
2591
2592 expected_len = sizeof(*cp) + key_count *
2593 sizeof(struct mgmt_ltk_info);
2594 if (expected_len != len) {
2595 BT_ERR("load_keys: expected %u bytes, got %u bytes",
2596 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002597 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002598 EINVAL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002599 }
2600
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002601 BT_DBG("%s key_count %u", hdev->name, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002602
2603 hci_dev_lock(hdev);
2604
2605 hci_smp_ltks_clear(hdev);
2606
2607 for (i = 0; i < key_count; i++) {
2608 struct mgmt_ltk_info *key = &cp->keys[i];
2609 u8 type;
2610
2611 if (key->master)
2612 type = HCI_SMP_LTK;
2613 else
2614 type = HCI_SMP_LTK_SLAVE;
2615
2616 hci_add_ltk(hdev, &key->addr.bdaddr, key->addr.type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002617 type, 0, key->authenticated, key->val,
2618 key->enc_size, key->ediv, key->rand);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002619 }
2620
2621 hci_dev_unlock(hdev);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002622
2623 return 0;
2624}
2625
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002626struct mgmt_handler {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002627 int (*func) (struct sock *sk, struct hci_dev *hdev, void *data,
2628 u16 data_len);
Johan Hedbergbe22b542012-03-01 22:24:41 +02002629 bool var_len;
2630 size_t data_len;
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002631} mgmt_handlers[] = {
2632 { NULL }, /* 0x0000 (no command) */
Johan Hedbergbe22b542012-03-01 22:24:41 +02002633 { read_version, false, MGMT_READ_VERSION_SIZE },
2634 { read_commands, false, MGMT_READ_COMMANDS_SIZE },
2635 { read_index_list, false, MGMT_READ_INDEX_LIST_SIZE },
2636 { read_controller_info, false, MGMT_READ_INFO_SIZE },
2637 { set_powered, false, MGMT_SETTING_SIZE },
2638 { set_discoverable, false, MGMT_SET_DISCOVERABLE_SIZE },
2639 { set_connectable, false, MGMT_SETTING_SIZE },
2640 { set_fast_connectable, false, MGMT_SETTING_SIZE },
2641 { set_pairable, false, MGMT_SETTING_SIZE },
2642 { set_link_security, false, MGMT_SETTING_SIZE },
2643 { set_ssp, false, MGMT_SETTING_SIZE },
2644 { set_hs, false, MGMT_SETTING_SIZE },
2645 { set_le, false, MGMT_SETTING_SIZE },
2646 { set_dev_class, false, MGMT_SET_DEV_CLASS_SIZE },
2647 { set_local_name, false, MGMT_SET_LOCAL_NAME_SIZE },
2648 { add_uuid, false, MGMT_ADD_UUID_SIZE },
2649 { remove_uuid, false, MGMT_REMOVE_UUID_SIZE },
2650 { load_link_keys, true, MGMT_LOAD_LINK_KEYS_SIZE },
2651 { load_long_term_keys, true, MGMT_LOAD_LONG_TERM_KEYS_SIZE },
2652 { disconnect, false, MGMT_DISCONNECT_SIZE },
2653 { get_connections, false, MGMT_GET_CONNECTIONS_SIZE },
2654 { pin_code_reply, false, MGMT_PIN_CODE_REPLY_SIZE },
2655 { pin_code_neg_reply, false, MGMT_PIN_CODE_NEG_REPLY_SIZE },
2656 { set_io_capability, false, MGMT_SET_IO_CAPABILITY_SIZE },
2657 { pair_device, false, MGMT_PAIR_DEVICE_SIZE },
2658 { cancel_pair_device, false, MGMT_CANCEL_PAIR_DEVICE_SIZE },
2659 { unpair_device, false, MGMT_UNPAIR_DEVICE_SIZE },
2660 { user_confirm_reply, false, MGMT_USER_CONFIRM_REPLY_SIZE },
2661 { user_confirm_neg_reply, false, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
2662 { user_passkey_reply, false, MGMT_USER_PASSKEY_REPLY_SIZE },
2663 { user_passkey_neg_reply, false, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
2664 { read_local_oob_data, false, MGMT_READ_LOCAL_OOB_DATA_SIZE },
2665 { add_remote_oob_data, false, MGMT_ADD_REMOTE_OOB_DATA_SIZE },
2666 { remove_remote_oob_data, false, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
2667 { start_discovery, false, MGMT_START_DISCOVERY_SIZE },
2668 { stop_discovery, false, MGMT_STOP_DISCOVERY_SIZE },
2669 { confirm_name, false, MGMT_CONFIRM_NAME_SIZE },
2670 { block_device, false, MGMT_BLOCK_DEVICE_SIZE },
2671 { unblock_device, false, MGMT_UNBLOCK_DEVICE_SIZE },
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002672};
2673
2674
Johan Hedberg03811012010-12-08 00:21:06 +02002675int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
2676{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002677 void *buf;
2678 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02002679 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002680 u16 opcode, index, len;
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002681 struct hci_dev *hdev = NULL;
Johan Hedbergbe22b542012-03-01 22:24:41 +02002682 struct mgmt_handler *handler;
Johan Hedberg03811012010-12-08 00:21:06 +02002683 int err;
2684
2685 BT_DBG("got %zu bytes", msglen);
2686
2687 if (msglen < sizeof(*hdr))
2688 return -EINVAL;
2689
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03002690 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02002691 if (!buf)
2692 return -ENOMEM;
2693
2694 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
2695 err = -EFAULT;
2696 goto done;
2697 }
2698
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002699 hdr = buf;
Johan Hedberg03811012010-12-08 00:21:06 +02002700 opcode = get_unaligned_le16(&hdr->opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002701 index = get_unaligned_le16(&hdr->index);
Johan Hedberg03811012010-12-08 00:21:06 +02002702 len = get_unaligned_le16(&hdr->len);
2703
2704 if (len != msglen - sizeof(*hdr)) {
2705 err = -EINVAL;
2706 goto done;
2707 }
2708
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002709 if (index != MGMT_INDEX_NONE) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002710 hdev = hci_dev_get(index);
2711 if (!hdev) {
2712 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002713 MGMT_STATUS_INVALID_INDEX);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002714 goto done;
2715 }
2716 }
2717
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002718 if (opcode >= ARRAY_SIZE(mgmt_handlers) ||
2719 mgmt_handlers[opcode].func == NULL) {
Johan Hedberg03811012010-12-08 00:21:06 +02002720 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02002721 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002722 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002723 goto done;
Johan Hedberg03811012010-12-08 00:21:06 +02002724 }
2725
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002726 if ((hdev && opcode < MGMT_OP_READ_INFO) ||
2727 (!hdev && opcode >= MGMT_OP_READ_INFO)) {
2728 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002729 MGMT_STATUS_INVALID_INDEX);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002730 goto done;
2731 }
2732
Johan Hedbergbe22b542012-03-01 22:24:41 +02002733 handler = &mgmt_handlers[opcode];
2734
2735 if ((handler->var_len && len < handler->data_len) ||
2736 (!handler->var_len && len != handler->data_len)) {
2737 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002738 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergbe22b542012-03-01 22:24:41 +02002739 goto done;
2740 }
2741
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002742 if (hdev)
2743 mgmt_init_hdev(sk, hdev);
2744
2745 cp = buf + sizeof(*hdr);
2746
Johan Hedbergbe22b542012-03-01 22:24:41 +02002747 err = handler->func(sk, hdev, cp, len);
Johan Hedberge41d8b42010-12-13 21:07:03 +02002748 if (err < 0)
2749 goto done;
2750
Johan Hedberg03811012010-12-08 00:21:06 +02002751 err = msglen;
2752
2753done:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002754 if (hdev)
2755 hci_dev_put(hdev);
2756
Johan Hedberg03811012010-12-08 00:21:06 +02002757 kfree(buf);
2758 return err;
2759}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002760
Johan Hedbergb24752f2011-11-03 14:40:33 +02002761static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
2762{
2763 u8 *status = data;
2764
2765 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
2766 mgmt_pending_remove(cmd);
2767}
2768
Johan Hedberg744cf192011-11-08 20:40:14 +02002769int mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002770{
Johan Hedberg744cf192011-11-08 20:40:14 +02002771 return mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002772}
2773
Johan Hedberg744cf192011-11-08 20:40:14 +02002774int mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002775{
Johan Hedberg5f159032012-03-02 03:13:19 +02002776 u8 status = MGMT_STATUS_INVALID_INDEX;
Johan Hedbergb24752f2011-11-03 14:40:33 +02002777
Johan Hedberg744cf192011-11-08 20:40:14 +02002778 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002779
Johan Hedberg744cf192011-11-08 20:40:14 +02002780 return mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002781}
2782
Johan Hedberg73f22f62010-12-29 16:00:25 +02002783struct cmd_lookup {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002784 struct sock *sk;
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002785 struct hci_dev *hdev;
Johan Hedberg90e70452012-02-23 23:09:40 +02002786 u8 mgmt_status;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002787};
2788
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002789static void settings_rsp(struct pending_cmd *cmd, void *data)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002790{
Johan Hedberg73f22f62010-12-29 16:00:25 +02002791 struct cmd_lookup *match = data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002792
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002793 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002794
2795 list_del(&cmd->list);
2796
2797 if (match->sk == NULL) {
2798 match->sk = cmd->sk;
2799 sock_hold(match->sk);
2800 }
2801
2802 mgmt_pending_free(cmd);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002803}
Johan Hedberg5add6af2010-12-16 10:00:37 +02002804
Johan Hedberg744cf192011-11-08 20:40:14 +02002805int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg5add6af2010-12-16 10:00:37 +02002806{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002807 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002808 int err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002809
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002810 if (!test_bit(HCI_MGMT, &hdev->dev_flags))
2811 return 0;
2812
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002813 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
Johan Hedberg5add6af2010-12-16 10:00:37 +02002814
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002815 if (powered) {
2816 u8 scan = 0;
2817
2818 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
2819 scan |= SCAN_PAGE;
2820 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
2821 scan |= SCAN_INQUIRY;
2822
2823 if (scan)
2824 hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
Johan Hedberg504c8dc2012-02-23 13:30:41 +02002825
2826 update_class(hdev);
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002827 update_name(hdev, hdev->dev_name);
Johan Hedberg504c8dc2012-02-23 13:30:41 +02002828 update_eir(hdev);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002829 } else {
Johan Hedbergd4f68522012-03-02 03:07:07 +02002830 u8 status = MGMT_STATUS_NOT_POWERED;
Johan Hedberg744cf192011-11-08 20:40:14 +02002831 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002832 }
2833
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02002834 err = new_settings(hdev, match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002835
2836 if (match.sk)
2837 sock_put(match.sk);
2838
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002839 return err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002840}
Johan Hedberg73f22f62010-12-29 16:00:25 +02002841
Johan Hedberg744cf192011-11-08 20:40:14 +02002842int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg73f22f62010-12-29 16:00:25 +02002843{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002844 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002845 bool changed = false;
2846 int err = 0;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002847
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002848 if (discoverable) {
2849 if (!test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
2850 changed = true;
2851 } else {
2852 if (test_and_clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
2853 changed = true;
2854 }
Johan Hedberg73f22f62010-12-29 16:00:25 +02002855
Johan Hedberged9b5f22012-02-21 20:47:06 +02002856 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002857 &match);
Johan Hedberged9b5f22012-02-21 20:47:06 +02002858
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02002859 if (changed)
2860 err = new_settings(hdev, match.sk);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002861
Johan Hedberg73f22f62010-12-29 16:00:25 +02002862 if (match.sk)
2863 sock_put(match.sk);
2864
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002865 return err;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002866}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002867
Johan Hedberg744cf192011-11-08 20:40:14 +02002868int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002869{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002870 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002871 bool changed = false;
2872 int err = 0;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002873
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002874 if (connectable) {
2875 if (!test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags))
2876 changed = true;
2877 } else {
2878 if (test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags))
2879 changed = true;
2880 }
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002881
Johan Hedberged9b5f22012-02-21 20:47:06 +02002882 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002883 &match);
Johan Hedberged9b5f22012-02-21 20:47:06 +02002884
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02002885 if (changed)
2886 err = new_settings(hdev, match.sk);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002887
2888 if (match.sk)
2889 sock_put(match.sk);
2890
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002891 return err;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002892}
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002893
Johan Hedberg744cf192011-11-08 20:40:14 +02002894int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002895{
Johan Hedbergca69b792011-11-11 18:10:00 +02002896 u8 mgmt_err = mgmt_status(status);
2897
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002898 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02002899 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002900 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002901
2902 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02002903 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002904 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002905
2906 return 0;
2907}
2908
Vishal Agarwal745c0ce2012-04-13 17:43:22 +05302909int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key, bool persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002910{
Johan Hedberg86742e12011-11-07 23:13:38 +02002911 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002912
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002913 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002914
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002915 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02002916 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
2917 ev.key.addr.type = MGMT_ADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002918 ev.key.type = key->type;
2919 memcpy(ev.key.val, key->val, 16);
2920 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002921
Johan Hedberg744cf192011-11-08 20:40:14 +02002922 return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002923}
Johan Hedbergf7520542011-01-20 12:34:39 +02002924
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002925int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
2926{
2927 struct mgmt_ev_new_long_term_key ev;
2928
2929 memset(&ev, 0, sizeof(ev));
2930
2931 ev.store_hint = persistent;
2932 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
2933 ev.key.addr.type = key->bdaddr_type;
2934 ev.key.authenticated = key->authenticated;
2935 ev.key.enc_size = key->enc_size;
2936 ev.key.ediv = key->ediv;
2937
2938 if (key->type == HCI_SMP_LTK)
2939 ev.key.master = 1;
2940
2941 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
2942 memcpy(ev.key.val, key->val, sizeof(key->val));
2943
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002944 return mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev),
2945 NULL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002946}
2947
Johan Hedbergafc747a2012-01-15 18:11:07 +02002948int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002949 u8 addr_type, u32 flags, u8 *name, u8 name_len,
2950 u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02002951{
Johan Hedbergb644ba32012-01-17 21:48:47 +02002952 char buf[512];
2953 struct mgmt_ev_device_connected *ev = (void *) buf;
2954 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02002955
Johan Hedbergb644ba32012-01-17 21:48:47 +02002956 bacpy(&ev->addr.bdaddr, bdaddr);
2957 ev->addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02002958
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02002959 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02002960
Johan Hedbergb644ba32012-01-17 21:48:47 +02002961 if (name_len > 0)
2962 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002963 name, name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02002964
2965 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
Brian Gix53156382012-03-09 14:07:03 -08002966 eir_len = eir_append_data(ev->eir, eir_len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002967 EIR_CLASS_OF_DEV, dev_class, 3);
Johan Hedbergb644ba32012-01-17 21:48:47 +02002968
2969 put_unaligned_le16(eir_len, &ev->eir_len);
2970
2971 return mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002972 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02002973}
2974
Johan Hedberg8962ee72011-01-20 12:40:27 +02002975static void disconnect_rsp(struct pending_cmd *cmd, void *data)
2976{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01002977 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002978 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02002979 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002980
Johan Hedberg88c3df12012-02-09 14:27:38 +02002981 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2982 rp.addr.type = cp->addr.type;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002983
Johan Hedbergaee9b2182012-02-18 15:07:59 +02002984 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002985 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002986
2987 *sk = cmd->sk;
2988 sock_hold(*sk);
2989
Johan Hedberga664b5b2011-02-19 12:06:02 -03002990 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002991}
2992
Johan Hedberg124f6e32012-02-09 13:50:12 +02002993static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02002994{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002995 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02002996 struct mgmt_cp_unpair_device *cp = cmd->param;
2997 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002998
2999 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02003000 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3001 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02003002
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003003 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
3004
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003005 cmd_complete(cmd->sk, cmd->index, cmd->opcode, 0, &rp, sizeof(rp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02003006
3007 mgmt_pending_remove(cmd);
3008}
3009
Johan Hedbergafc747a2012-01-15 18:11:07 +02003010int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003011 u8 link_type, u8 addr_type)
Johan Hedbergf7520542011-01-20 12:34:39 +02003012{
Johan Hedberg4c659c32011-11-07 23:13:39 +02003013 struct mgmt_addr_info ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003014 struct sock *sk = NULL;
3015 int err;
3016
Johan Hedberg744cf192011-11-08 20:40:14 +02003017 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02003018
Johan Hedbergf7520542011-01-20 12:34:39 +02003019 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02003020 ev.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02003021
Johan Hedbergafc747a2012-01-15 18:11:07 +02003022 err = mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003023 sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003024
3025 if (sk)
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003026 sock_put(sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003027
Johan Hedberg124f6e32012-02-09 13:50:12 +02003028 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003029 hdev);
Johan Hedberga8a1d192011-11-10 15:54:38 +02003030
Johan Hedberg8962ee72011-01-20 12:40:27 +02003031 return err;
3032}
3033
Johan Hedberg88c3df12012-02-09 14:27:38 +02003034int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003035 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02003036{
Johan Hedberg88c3df12012-02-09 14:27:38 +02003037 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003038 struct pending_cmd *cmd;
3039 int err;
3040
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003041 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003042 if (!cmd)
3043 return -ENOENT;
3044
Johan Hedberg88c3df12012-02-09 14:27:38 +02003045 bacpy(&rp.addr.bdaddr, bdaddr);
3046 rp.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02003047
Johan Hedberg88c3df12012-02-09 14:27:38 +02003048 err = cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003049 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003050
Johan Hedberga664b5b2011-02-19 12:06:02 -03003051 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003052
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003053 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
3054 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003055 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02003056}
Johan Hedberg17d5c042011-01-22 06:09:08 +02003057
Johan Hedberg48264f02011-11-09 13:58:58 +02003058int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003059 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02003060{
3061 struct mgmt_ev_connect_failed ev;
3062
Johan Hedberg4c659c32011-11-07 23:13:39 +02003063 bacpy(&ev.addr.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02003064 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003065 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003066
Johan Hedberg744cf192011-11-08 20:40:14 +02003067 return mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003068}
Johan Hedberg980e1a52011-01-22 06:10:07 +02003069
Johan Hedberg744cf192011-11-08 20:40:14 +02003070int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003071{
3072 struct mgmt_ev_pin_code_request ev;
3073
Johan Hedbergd8457692012-02-17 14:24:57 +02003074 bacpy(&ev.addr.bdaddr, bdaddr);
3075 ev.addr.type = MGMT_ADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02003076 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003077
Johan Hedberg744cf192011-11-08 20:40:14 +02003078 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003079 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003080}
3081
Johan Hedberg744cf192011-11-08 20:40:14 +02003082int mgmt_pin_code_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_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_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}
3103
Johan Hedberg744cf192011-11-08 20:40:14 +02003104int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003105 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003106{
3107 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003108 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003109 int err;
3110
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003111 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003112 if (!cmd)
3113 return -ENOENT;
3114
Johan Hedbergd8457692012-02-17 14:24:57 +02003115 bacpy(&rp.addr.bdaddr, bdaddr);
3116 rp.addr.type = MGMT_ADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003117
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003118 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003119 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003120
Johan Hedberga664b5b2011-02-19 12:06:02 -03003121 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003122
3123 return err;
3124}
Johan Hedberga5c29682011-02-19 12:05:57 -03003125
Johan Hedberg744cf192011-11-08 20:40:14 +02003126int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003127 u8 link_type, u8 addr_type, __le32 value,
3128 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03003129{
3130 struct mgmt_ev_user_confirm_request ev;
3131
Johan Hedberg744cf192011-11-08 20:40:14 +02003132 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03003133
Johan Hedberg272d90d2012-02-09 15:26:12 +02003134 bacpy(&ev.addr.bdaddr, bdaddr);
3135 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07003136 ev.confirm_hint = confirm_hint;
Andrei Emeltchenko78e8098e2012-03-09 13:00:50 +02003137 ev.value = value;
Johan Hedberga5c29682011-02-19 12:05:57 -03003138
Johan Hedberg744cf192011-11-08 20:40:14 +02003139 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003140 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03003141}
3142
Johan Hedberg272d90d2012-02-09 15:26:12 +02003143int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
3144 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08003145{
3146 struct mgmt_ev_user_passkey_request ev;
3147
3148 BT_DBG("%s", hdev->name);
3149
Johan Hedberg272d90d2012-02-09 15:26:12 +02003150 bacpy(&ev.addr.bdaddr, bdaddr);
3151 ev.addr.type = link_to_mgmt(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08003152
3153 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003154 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08003155}
3156
Brian Gix0df4c182011-11-16 13:53:13 -08003157static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003158 u8 link_type, u8 addr_type, u8 status,
3159 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03003160{
3161 struct pending_cmd *cmd;
3162 struct mgmt_rp_user_confirm_reply rp;
3163 int err;
3164
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003165 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03003166 if (!cmd)
3167 return -ENOENT;
3168
Johan Hedberg272d90d2012-02-09 15:26:12 +02003169 bacpy(&rp.addr.bdaddr, bdaddr);
3170 rp.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003171 err = cmd_complete(cmd->sk, hdev->id, opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003172 &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03003173
Johan Hedberga664b5b2011-02-19 12:06:02 -03003174 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03003175
3176 return err;
3177}
3178
Johan Hedberg744cf192011-11-08 20:40:14 +02003179int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003180 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003181{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003182 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003183 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003184}
3185
Johan Hedberg272d90d2012-02-09 15:26:12 +02003186int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003187 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003188{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003189 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003190 status, MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003191}
Johan Hedberg2a611692011-02-19 12:06:00 -03003192
Brian Gix604086b2011-11-23 08:28:33 -08003193int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003194 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003195{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003196 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003197 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003198}
3199
Johan Hedberg272d90d2012-02-09 15:26:12 +02003200int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003201 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003202{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003203 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003204 status, MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003205}
3206
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003207int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003208 u8 addr_type, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03003209{
3210 struct mgmt_ev_auth_failed ev;
3211
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003212 bacpy(&ev.addr.bdaddr, bdaddr);
3213 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003214 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03003215
Johan Hedberg744cf192011-11-08 20:40:14 +02003216 return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03003217}
Johan Hedbergb312b1612011-03-16 14:29:37 +02003218
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003219int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
3220{
3221 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg47990ea2012-02-22 11:58:37 +02003222 bool changed = false;
3223 int err = 0;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003224
3225 if (status) {
3226 u8 mgmt_err = mgmt_status(status);
3227 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003228 cmd_status_rsp, &mgmt_err);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003229 return 0;
3230 }
3231
Johan Hedberg47990ea2012-02-22 11:58:37 +02003232 if (test_bit(HCI_AUTH, &hdev->flags)) {
3233 if (!test_and_set_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
3234 changed = true;
3235 } else {
3236 if (test_and_clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
3237 changed = true;
3238 }
3239
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003240 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003241 &match);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003242
Johan Hedberg47990ea2012-02-22 11:58:37 +02003243 if (changed)
3244 err = new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003245
3246 if (match.sk)
3247 sock_put(match.sk);
3248
3249 return err;
3250}
3251
Johan Hedbergcacaf522012-02-21 00:52:42 +02003252static int clear_eir(struct hci_dev *hdev)
3253{
3254 struct hci_cp_write_eir cp;
3255
3256 if (!(hdev->features[6] & LMP_EXT_INQ))
3257 return 0;
3258
Johan Hedbergc80da272012-02-22 15:38:48 +02003259 memset(hdev->eir, 0, sizeof(hdev->eir));
3260
Johan Hedbergcacaf522012-02-21 00:52:42 +02003261 memset(&cp, 0, sizeof(cp));
3262
3263 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
3264}
3265
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003266int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003267{
3268 struct cmd_lookup match = { NULL, hdev };
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003269 bool changed = false;
3270 int err = 0;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003271
3272 if (status) {
3273 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003274
3275 if (enable && test_and_clear_bit(HCI_SSP_ENABLED,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003276 &hdev->dev_flags))
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003277 err = new_settings(hdev, NULL);
3278
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003279 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
3280 &mgmt_err);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003281
3282 return err;
3283 }
3284
3285 if (enable) {
3286 if (!test_and_set_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3287 changed = true;
3288 } else {
3289 if (test_and_clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3290 changed = true;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003291 }
3292
3293 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
3294
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003295 if (changed)
3296 err = new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003297
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02003298 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003299 sock_put(match.sk);
3300
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02003301 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3302 update_eir(hdev);
3303 else
3304 clear_eir(hdev);
Johan Hedbergcacaf522012-02-21 00:52:42 +02003305
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003306 return err;
3307}
3308
Johan Hedberg90e70452012-02-23 23:09:40 +02003309static void class_rsp(struct pending_cmd *cmd, void *data)
3310{
3311 struct cmd_lookup *match = data;
3312
3313 cmd_complete(cmd->sk, cmd->index, cmd->opcode, match->mgmt_status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003314 match->hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02003315
3316 list_del(&cmd->list);
3317
3318 if (match->sk == NULL) {
3319 match->sk = cmd->sk;
3320 sock_hold(match->sk);
3321 }
3322
3323 mgmt_pending_free(cmd);
3324}
3325
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003326int mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003327 u8 status)
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003328{
Johan Hedberg90e70452012-02-23 23:09:40 +02003329 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
3330 int err = 0;
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003331
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02003332 clear_bit(HCI_PENDING_CLASS, &hdev->dev_flags);
3333
Johan Hedberg90e70452012-02-23 23:09:40 +02003334 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, class_rsp, &match);
3335 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, class_rsp, &match);
3336 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, class_rsp, &match);
3337
3338 if (!status)
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003339 err = mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class,
3340 3, NULL);
Johan Hedberg90e70452012-02-23 23:09:40 +02003341
3342 if (match.sk)
3343 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003344
3345 return err;
3346}
3347
Johan Hedberg744cf192011-11-08 20:40:14 +02003348int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02003349{
3350 struct pending_cmd *cmd;
3351 struct mgmt_cp_set_local_name ev;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003352 bool changed = false;
3353 int err = 0;
3354
3355 if (memcmp(name, hdev->dev_name, sizeof(hdev->dev_name)) != 0) {
3356 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
3357 changed = true;
3358 }
Johan Hedbergb312b1612011-03-16 14:29:37 +02003359
3360 memset(&ev, 0, sizeof(ev));
3361 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003362 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003363
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003364 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003365 if (!cmd)
3366 goto send_event;
3367
Johan Hedberg7bdaae42012-02-22 21:39:58 +02003368 /* Always assume that either the short or the complete name has
3369 * changed if there was a pending mgmt command */
3370 changed = true;
3371
Johan Hedbergb312b1612011-03-16 14:29:37 +02003372 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02003373 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003374 mgmt_status(status));
Johan Hedbergb312b1612011-03-16 14:29:37 +02003375 goto failed;
3376 }
3377
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003378 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0, &ev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003379 sizeof(ev));
Johan Hedbergb312b1612011-03-16 14:29:37 +02003380 if (err < 0)
3381 goto failed;
3382
3383send_event:
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003384 if (changed)
3385 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003386 sizeof(ev), cmd ? cmd->sk : NULL);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003387
Johan Hedbergf51d5b22012-02-22 18:17:32 +02003388 update_eir(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003389
3390failed:
3391 if (cmd)
3392 mgmt_pending_remove(cmd);
3393 return err;
3394}
Szymon Jancc35938b2011-03-22 13:12:21 +01003395
Johan Hedberg744cf192011-11-08 20:40:14 +02003396int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003397 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01003398{
3399 struct pending_cmd *cmd;
3400 int err;
3401
Johan Hedberg744cf192011-11-08 20:40:14 +02003402 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01003403
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003404 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003405 if (!cmd)
3406 return -ENOENT;
3407
3408 if (status) {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003409 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3410 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01003411 } else {
3412 struct mgmt_rp_read_local_oob_data rp;
3413
3414 memcpy(rp.hash, hash, sizeof(rp.hash));
3415 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
3416
Johan Hedberg744cf192011-11-08 20:40:14 +02003417 err = cmd_complete(cmd->sk, hdev->id,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003418 MGMT_OP_READ_LOCAL_OOB_DATA, 0, &rp,
3419 sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01003420 }
3421
3422 mgmt_pending_remove(cmd);
3423
3424 return err;
3425}
Johan Hedberge17acd42011-03-30 23:57:16 +03003426
Johan Hedberg06199cf2012-02-22 16:37:11 +02003427int mgmt_le_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
3428{
3429 struct cmd_lookup match = { NULL, hdev };
3430 bool changed = false;
3431 int err = 0;
3432
3433 if (status) {
3434 u8 mgmt_err = mgmt_status(status);
3435
3436 if (enable && test_and_clear_bit(HCI_LE_ENABLED,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003437 &hdev->dev_flags))
3438 err = new_settings(hdev, NULL);
Johan Hedberg06199cf2012-02-22 16:37:11 +02003439
3440 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003441 cmd_status_rsp, &mgmt_err);
Johan Hedberg06199cf2012-02-22 16:37:11 +02003442
3443 return err;
3444 }
3445
3446 if (enable) {
3447 if (!test_and_set_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3448 changed = true;
3449 } else {
3450 if (test_and_clear_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3451 changed = true;
3452 }
3453
3454 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
3455
3456 if (changed)
3457 err = new_settings(hdev, match.sk);
3458
3459 if (match.sk)
3460 sock_put(match.sk);
3461
3462 return err;
3463}
3464
Johan Hedberg48264f02011-11-09 13:58:58 +02003465int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003466 u8 addr_type, u8 *dev_class, s8 rssi, u8 cfm_name, u8
3467 ssp, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03003468{
Johan Hedberge319d2e2012-01-15 19:51:59 +02003469 char buf[512];
3470 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02003471 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03003472
Johan Hedberg1dc06092012-01-15 21:01:23 +02003473 /* Leave 5 bytes for a potential CoD field */
3474 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Andre Guedes7d262f82012-01-10 18:20:49 -03003475 return -EINVAL;
3476
Johan Hedberg1dc06092012-01-15 21:01:23 +02003477 memset(buf, 0, sizeof(buf));
3478
Johan Hedberge319d2e2012-01-15 19:51:59 +02003479 bacpy(&ev->addr.bdaddr, bdaddr);
3480 ev->addr.type = link_to_mgmt(link_type, addr_type);
3481 ev->rssi = rssi;
Johan Hedberg9a395a82012-02-23 00:00:32 +02003482 if (cfm_name)
3483 ev->flags[0] |= MGMT_DEV_FOUND_CONFIRM_NAME;
Johan Hedberg388fc8f2012-02-23 00:38:59 +02003484 if (!ssp)
3485 ev->flags[0] |= MGMT_DEV_FOUND_LEGACY_PAIRING;
Johan Hedberge17acd42011-03-30 23:57:16 +03003486
Johan Hedberg1dc06092012-01-15 21:01:23 +02003487 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02003488 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03003489
Johan Hedberg1dc06092012-01-15 21:01:23 +02003490 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
3491 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003492 dev_class, 3);
Johan Hedberg1dc06092012-01-15 21:01:23 +02003493
3494 put_unaligned_le16(eir_len, &ev->eir_len);
3495
3496 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03003497
Johan Hedberge319d2e2012-01-15 19:51:59 +02003498 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03003499}
Johan Hedberga88a9652011-03-30 13:18:12 +03003500
Johan Hedbergb644ba32012-01-17 21:48:47 +02003501int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003502 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03003503{
Johan Hedbergb644ba32012-01-17 21:48:47 +02003504 struct mgmt_ev_device_found *ev;
3505 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
3506 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03003507
Johan Hedbergb644ba32012-01-17 21:48:47 +02003508 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03003509
Johan Hedbergb644ba32012-01-17 21:48:47 +02003510 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03003511
Johan Hedbergb644ba32012-01-17 21:48:47 +02003512 bacpy(&ev->addr.bdaddr, bdaddr);
3513 ev->addr.type = link_to_mgmt(link_type, addr_type);
3514 ev->rssi = rssi;
3515
3516 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003517 name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003518
3519 put_unaligned_le16(eir_len, &ev->eir_len);
3520
Johan Hedberg053c7e02012-02-04 00:06:00 +02003521 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003522 sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03003523}
Johan Hedberg314b2382011-04-27 10:29:57 -04003524
Andre Guedes7a135102011-11-09 17:14:25 -03003525int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
Johan Hedberg164a6e72011-11-01 17:06:44 +02003526{
3527 struct pending_cmd *cmd;
Johan Hedbergf808e162012-02-19 12:52:07 +02003528 u8 type;
Johan Hedberg164a6e72011-11-01 17:06:44 +02003529 int err;
3530
Andre Guedes203159d2012-02-13 15:41:01 -03003531 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3532
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003533 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003534 if (!cmd)
3535 return -ENOENT;
3536
Johan Hedbergf808e162012-02-19 12:52:07 +02003537 type = hdev->discovery.type;
3538
3539 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003540 &type, sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02003541 mgmt_pending_remove(cmd);
3542
3543 return err;
3544}
3545
Andre Guedese6d465c2011-11-09 17:14:26 -03003546int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
3547{
3548 struct pending_cmd *cmd;
3549 int err;
3550
3551 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
3552 if (!cmd)
3553 return -ENOENT;
3554
Johan Hedbergd9306502012-02-20 23:25:18 +02003555 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003556 &hdev->discovery.type, sizeof(hdev->discovery.type));
Johan Hedberg03811012010-12-08 00:21:06 +02003557 mgmt_pending_remove(cmd);
3558
3559 return err;
3560}
Johan Hedberg314b2382011-04-27 10:29:57 -04003561
Johan Hedberg744cf192011-11-08 20:40:14 +02003562int mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04003563{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02003564 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02003565 struct pending_cmd *cmd;
3566
Andre Guedes343fb142011-11-22 17:14:19 -03003567 BT_DBG("%s discovering %u", hdev->name, discovering);
3568
Johan Hedberg164a6e72011-11-01 17:06:44 +02003569 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003570 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003571 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003572 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003573
3574 if (cmd != NULL) {
Johan Hedbergf808e162012-02-19 12:52:07 +02003575 u8 type = hdev->discovery.type;
3576
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003577 cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0, &type,
3578 sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02003579 mgmt_pending_remove(cmd);
3580 }
3581
Johan Hedbergf963e8e2012-02-20 23:30:44 +02003582 memset(&ev, 0, sizeof(ev));
3583 ev.type = hdev->discovery.type;
3584 ev.discovering = discovering;
3585
3586 return mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04003587}
Antti Julku5e762442011-08-25 16:48:02 +03003588
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003589int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003590{
3591 struct pending_cmd *cmd;
3592 struct mgmt_ev_device_blocked ev;
3593
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003594 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003595
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003596 bacpy(&ev.addr.bdaddr, bdaddr);
3597 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003598
Johan Hedberg744cf192011-11-08 20:40:14 +02003599 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003600 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003601}
3602
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003603int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003604{
3605 struct pending_cmd *cmd;
3606 struct mgmt_ev_device_unblocked ev;
3607
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003608 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003609
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003610 bacpy(&ev.addr.bdaddr, bdaddr);
3611 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003612
Johan Hedberg744cf192011-11-08 20:40:14 +02003613 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003614 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003615}
Marcel Holtmannd7b7e792012-02-20 21:47:49 +01003616
3617module_param(enable_hs, bool, 0644);
3618MODULE_PARM_DESC(enable_hs, "Enable High Speed support");
3619
3620module_param(enable_le, bool, 0644);
3621MODULE_PARM_DESC(enable_le, "Enable Low Energy support");