blob: 7bd7d57a8775756e3beb0f0cff60932bf53e2524 [file] [log] [blame]
Johan Hedberg03811012010-12-08 00:21:06 +02001/*
2 BlueZ - Bluetooth protocol stack for Linux
Johan Hedbergea585ab2012-02-17 14:50:39 +02003
Johan Hedberg03811012010-12-08 00:21:06 +02004 Copyright (C) 2010 Nokia Corporation
Johan Hedbergea585ab2012-02-17 14:50:39 +02005 Copyright (C) 2011-2012 Intel Corporation
Johan Hedberg03811012010-12-08 00:21:06 +02006
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License version 2 as
9 published by the Free Software Foundation;
10
11 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
12 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
13 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
14 IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
15 CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
16 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19
20 ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
21 COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
22 SOFTWARE IS DISCLAIMED.
23*/
24
25/* Bluetooth HCI Management interface */
26
Johan Hedbergca69b792011-11-11 18:10:00 +020027#include <linux/kernel.h>
Szymon Janc72359752011-02-17 14:16:32 +010028#include <linux/uaccess.h>
Paul Gortmaker3a9a2312011-05-27 09:12:25 -040029#include <linux/module.h>
Johan Hedberg03811012010-12-08 00:21:06 +020030#include <asm/unaligned.h>
31
32#include <net/bluetooth/bluetooth.h>
33#include <net/bluetooth/hci_core.h>
34#include <net/bluetooth/mgmt.h>
Brian Gix5fe57d92011-12-21 16:12:13 -080035#include <net/bluetooth/smp.h>
Johan Hedberg03811012010-12-08 00:21:06 +020036
Marcel Holtmannd7b7e792012-02-20 21:47:49 +010037bool enable_hs;
38bool enable_le;
39
Johan Hedberg2da9c552012-02-17 14:39:28 +020040#define MGMT_VERSION 1
41#define MGMT_REVISION 0
Johan Hedberg02d98122010-12-13 21:07:04 +020042
Johan Hedberge70bb2e2012-02-13 16:59:33 +020043static const u16 mgmt_commands[] = {
44 MGMT_OP_READ_INDEX_LIST,
45 MGMT_OP_READ_INFO,
46 MGMT_OP_SET_POWERED,
47 MGMT_OP_SET_DISCOVERABLE,
48 MGMT_OP_SET_CONNECTABLE,
49 MGMT_OP_SET_FAST_CONNECTABLE,
50 MGMT_OP_SET_PAIRABLE,
51 MGMT_OP_SET_LINK_SECURITY,
52 MGMT_OP_SET_SSP,
53 MGMT_OP_SET_HS,
54 MGMT_OP_SET_LE,
55 MGMT_OP_SET_DEV_CLASS,
56 MGMT_OP_SET_LOCAL_NAME,
57 MGMT_OP_ADD_UUID,
58 MGMT_OP_REMOVE_UUID,
59 MGMT_OP_LOAD_LINK_KEYS,
60 MGMT_OP_LOAD_LONG_TERM_KEYS,
61 MGMT_OP_DISCONNECT,
62 MGMT_OP_GET_CONNECTIONS,
63 MGMT_OP_PIN_CODE_REPLY,
64 MGMT_OP_PIN_CODE_NEG_REPLY,
65 MGMT_OP_SET_IO_CAPABILITY,
66 MGMT_OP_PAIR_DEVICE,
67 MGMT_OP_CANCEL_PAIR_DEVICE,
68 MGMT_OP_UNPAIR_DEVICE,
69 MGMT_OP_USER_CONFIRM_REPLY,
70 MGMT_OP_USER_CONFIRM_NEG_REPLY,
71 MGMT_OP_USER_PASSKEY_REPLY,
72 MGMT_OP_USER_PASSKEY_NEG_REPLY,
73 MGMT_OP_READ_LOCAL_OOB_DATA,
74 MGMT_OP_ADD_REMOTE_OOB_DATA,
75 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
76 MGMT_OP_START_DISCOVERY,
77 MGMT_OP_STOP_DISCOVERY,
78 MGMT_OP_CONFIRM_NAME,
79 MGMT_OP_BLOCK_DEVICE,
80 MGMT_OP_UNBLOCK_DEVICE,
81};
82
83static const u16 mgmt_events[] = {
84 MGMT_EV_CONTROLLER_ERROR,
85 MGMT_EV_INDEX_ADDED,
86 MGMT_EV_INDEX_REMOVED,
87 MGMT_EV_NEW_SETTINGS,
88 MGMT_EV_CLASS_OF_DEV_CHANGED,
89 MGMT_EV_LOCAL_NAME_CHANGED,
90 MGMT_EV_NEW_LINK_KEY,
91 MGMT_EV_NEW_LONG_TERM_KEY,
92 MGMT_EV_DEVICE_CONNECTED,
93 MGMT_EV_DEVICE_DISCONNECTED,
94 MGMT_EV_CONNECT_FAILED,
95 MGMT_EV_PIN_CODE_REQUEST,
96 MGMT_EV_USER_CONFIRM_REQUEST,
97 MGMT_EV_USER_PASSKEY_REQUEST,
98 MGMT_EV_AUTH_FAILED,
99 MGMT_EV_DEVICE_FOUND,
100 MGMT_EV_DISCOVERING,
101 MGMT_EV_DEVICE_BLOCKED,
102 MGMT_EV_DEVICE_UNBLOCKED,
103 MGMT_EV_DEVICE_UNPAIRED,
104};
105
Andre Guedes3fd24152012-02-03 17:48:01 -0300106/*
107 * These LE scan and inquiry parameters were chosen according to LE General
108 * Discovery Procedure specification.
109 */
110#define LE_SCAN_TYPE 0x01
111#define LE_SCAN_WIN 0x12
112#define LE_SCAN_INT 0x12
113#define LE_SCAN_TIMEOUT_LE_ONLY 10240 /* TGAP(gen_disc_scan_min) */
Andre Guedes5e0452c2012-02-17 20:39:38 -0300114#define LE_SCAN_TIMEOUT_BREDR_LE 5120 /* TGAP(100)/2 */
Andre Guedes3fd24152012-02-03 17:48:01 -0300115
Andre Guedese8777522012-02-03 17:48:02 -0300116#define INQUIRY_LEN_BREDR 0x08 /* TGAP(100) */
Andre Guedes5e0452c2012-02-17 20:39:38 -0300117#define INQUIRY_LEN_BREDR_LE 0x04 /* TGAP(100)/2 */
Andre Guedes2519a1f2011-11-07 11:45:24 -0300118
Johan Hedberg7d785252011-12-15 00:47:39 +0200119#define SERVICE_CACHE_TIMEOUT (5 * 1000)
120
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200121#define hdev_is_powered(hdev) (test_bit(HCI_UP, &hdev->flags) && \
122 !test_bit(HCI_AUTO_OFF, &hdev->dev_flags))
123
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200124struct pending_cmd {
125 struct list_head list;
Johan Hedbergfc2f4b12011-11-09 13:58:56 +0200126 u16 opcode;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200127 int index;
Szymon Jancc68fb7f2011-03-22 13:12:19 +0100128 void *param;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200129 struct sock *sk;
Johan Hedberge9a416b2011-02-19 12:05:56 -0300130 void *user_data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200131};
132
Johan Hedbergca69b792011-11-11 18:10:00 +0200133/* HCI to MGMT error code conversion table */
134static u8 mgmt_status_table[] = {
135 MGMT_STATUS_SUCCESS,
136 MGMT_STATUS_UNKNOWN_COMMAND, /* Unknown Command */
137 MGMT_STATUS_NOT_CONNECTED, /* No Connection */
138 MGMT_STATUS_FAILED, /* Hardware Failure */
139 MGMT_STATUS_CONNECT_FAILED, /* Page Timeout */
140 MGMT_STATUS_AUTH_FAILED, /* Authentication Failed */
141 MGMT_STATUS_NOT_PAIRED, /* PIN or Key Missing */
142 MGMT_STATUS_NO_RESOURCES, /* Memory Full */
143 MGMT_STATUS_TIMEOUT, /* Connection Timeout */
144 MGMT_STATUS_NO_RESOURCES, /* Max Number of Connections */
145 MGMT_STATUS_NO_RESOURCES, /* Max Number of SCO Connections */
146 MGMT_STATUS_ALREADY_CONNECTED, /* ACL Connection Exists */
147 MGMT_STATUS_BUSY, /* Command Disallowed */
148 MGMT_STATUS_NO_RESOURCES, /* Rejected Limited Resources */
149 MGMT_STATUS_REJECTED, /* Rejected Security */
150 MGMT_STATUS_REJECTED, /* Rejected Personal */
151 MGMT_STATUS_TIMEOUT, /* Host Timeout */
152 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Feature */
153 MGMT_STATUS_INVALID_PARAMS, /* Invalid Parameters */
154 MGMT_STATUS_DISCONNECTED, /* OE User Ended Connection */
155 MGMT_STATUS_NO_RESOURCES, /* OE Low Resources */
156 MGMT_STATUS_DISCONNECTED, /* OE Power Off */
157 MGMT_STATUS_DISCONNECTED, /* Connection Terminated */
158 MGMT_STATUS_BUSY, /* Repeated Attempts */
159 MGMT_STATUS_REJECTED, /* Pairing Not Allowed */
160 MGMT_STATUS_FAILED, /* Unknown LMP PDU */
161 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Remote Feature */
162 MGMT_STATUS_REJECTED, /* SCO Offset Rejected */
163 MGMT_STATUS_REJECTED, /* SCO Interval Rejected */
164 MGMT_STATUS_REJECTED, /* Air Mode Rejected */
165 MGMT_STATUS_INVALID_PARAMS, /* Invalid LMP Parameters */
166 MGMT_STATUS_FAILED, /* Unspecified Error */
167 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported LMP Parameter Value */
168 MGMT_STATUS_FAILED, /* Role Change Not Allowed */
169 MGMT_STATUS_TIMEOUT, /* LMP Response Timeout */
170 MGMT_STATUS_FAILED, /* LMP Error Transaction Collision */
171 MGMT_STATUS_FAILED, /* LMP PDU Not Allowed */
172 MGMT_STATUS_REJECTED, /* Encryption Mode Not Accepted */
173 MGMT_STATUS_FAILED, /* Unit Link Key Used */
174 MGMT_STATUS_NOT_SUPPORTED, /* QoS Not Supported */
175 MGMT_STATUS_TIMEOUT, /* Instant Passed */
176 MGMT_STATUS_NOT_SUPPORTED, /* Pairing Not Supported */
177 MGMT_STATUS_FAILED, /* Transaction Collision */
178 MGMT_STATUS_INVALID_PARAMS, /* Unacceptable Parameter */
179 MGMT_STATUS_REJECTED, /* QoS Rejected */
180 MGMT_STATUS_NOT_SUPPORTED, /* Classification Not Supported */
181 MGMT_STATUS_REJECTED, /* Insufficient Security */
182 MGMT_STATUS_INVALID_PARAMS, /* Parameter Out Of Range */
183 MGMT_STATUS_BUSY, /* Role Switch Pending */
184 MGMT_STATUS_FAILED, /* Slot Violation */
185 MGMT_STATUS_FAILED, /* Role Switch Failed */
186 MGMT_STATUS_INVALID_PARAMS, /* EIR Too Large */
187 MGMT_STATUS_NOT_SUPPORTED, /* Simple Pairing Not Supported */
188 MGMT_STATUS_BUSY, /* Host Busy Pairing */
189 MGMT_STATUS_REJECTED, /* Rejected, No Suitable Channel */
190 MGMT_STATUS_BUSY, /* Controller Busy */
191 MGMT_STATUS_INVALID_PARAMS, /* Unsuitable Connection Interval */
192 MGMT_STATUS_TIMEOUT, /* Directed Advertising Timeout */
193 MGMT_STATUS_AUTH_FAILED, /* Terminated Due to MIC Failure */
194 MGMT_STATUS_CONNECT_FAILED, /* Connection Establishment Failed */
195 MGMT_STATUS_CONNECT_FAILED, /* MAC Connection Failed */
196};
197
198static u8 mgmt_status(u8 hci_status)
199{
200 if (hci_status < ARRAY_SIZE(mgmt_status_table))
201 return mgmt_status_table[hci_status];
202
203 return MGMT_STATUS_FAILED;
204}
205
Szymon Janc4e51eae2011-02-25 19:05:48 +0100206static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200207{
208 struct sk_buff *skb;
209 struct mgmt_hdr *hdr;
210 struct mgmt_ev_cmd_status *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300211 int err;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200212
Szymon Janc34eb5252011-02-28 14:10:08 +0100213 BT_DBG("sock %p, index %u, cmd %u, status %u", sk, index, cmd, status);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200214
215 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_ATOMIC);
216 if (!skb)
217 return -ENOMEM;
218
219 hdr = (void *) skb_put(skb, sizeof(*hdr));
220
221 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_STATUS);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100222 hdr->index = cpu_to_le16(index);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200223 hdr->len = cpu_to_le16(sizeof(*ev));
224
225 ev = (void *) skb_put(skb, sizeof(*ev));
226 ev->status = status;
227 put_unaligned_le16(cmd, &ev->opcode);
228
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300229 err = sock_queue_rcv_skb(sk, skb);
230 if (err < 0)
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200231 kfree_skb(skb);
232
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300233 return err;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200234}
235
Johan Hedbergaee9b2182012-02-18 15:07:59 +0200236static int cmd_complete(struct sock *sk, u16 index, u16 cmd, u8 status,
237 void *rp, size_t rp_len)
Johan Hedberg02d98122010-12-13 21:07:04 +0200238{
239 struct sk_buff *skb;
240 struct mgmt_hdr *hdr;
241 struct mgmt_ev_cmd_complete *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300242 int err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200243
244 BT_DBG("sock %p", sk);
245
Johan Hedberga38528f2011-01-22 06:46:43 +0200246 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + rp_len, GFP_ATOMIC);
Johan Hedberg02d98122010-12-13 21:07:04 +0200247 if (!skb)
248 return -ENOMEM;
249
250 hdr = (void *) skb_put(skb, sizeof(*hdr));
Johan Hedberga38528f2011-01-22 06:46:43 +0200251
Johan Hedberg02d98122010-12-13 21:07:04 +0200252 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100253 hdr->index = cpu_to_le16(index);
Johan Hedberga38528f2011-01-22 06:46:43 +0200254 hdr->len = cpu_to_le16(sizeof(*ev) + rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200255
Johan Hedberga38528f2011-01-22 06:46:43 +0200256 ev = (void *) skb_put(skb, sizeof(*ev) + rp_len);
257 put_unaligned_le16(cmd, &ev->opcode);
Johan Hedbergaee9b2182012-02-18 15:07:59 +0200258 ev->status = status;
Szymon Janc8020c162011-02-28 14:09:50 +0100259
260 if (rp)
261 memcpy(ev->data, rp, rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200262
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300263 err = sock_queue_rcv_skb(sk, skb);
264 if (err < 0)
Johan Hedberg02d98122010-12-13 21:07:04 +0200265 kfree_skb(skb);
266
Marcel Holtmanne5f0e152012-02-22 11:59:01 +0100267 return err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200268}
269
Johan Hedberg0f4e68c2012-02-28 17:18:30 +0200270static int read_version(struct sock *sk, struct hci_dev *hdev,
271 void *data, 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,
Szymon Janc4e51eae2011-02-25 19:05:48 +0100281 sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200282}
283
Johan Hedberg0f4e68c2012-02-28 17:18:30 +0200284static int read_commands(struct sock *sk, struct hci_dev *hdev,
285 void *data, 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,
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200312 rp_size);
313 kfree(rp);
314
315 return err;
316}
317
Johan Hedberg0f4e68c2012-02-28 17:18:30 +0200318static int read_index_list(struct sock *sk, struct hci_dev *hdev,
319 void *data, 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,
Szymon Janc4e51eae2011-02-25 19:05:48 +0100358 rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200359
Johan Hedberga38528f2011-01-22 06:46:43 +0200360 kfree(rp);
361
362 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200363}
364
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200365static u32 get_supported_settings(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +0200366{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200367 u32 settings = 0;
Johan Hedberg03811012010-12-08 00:21:06 +0200368
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200369 settings |= MGMT_SETTING_POWERED;
370 settings |= MGMT_SETTING_CONNECTABLE;
371 settings |= MGMT_SETTING_FAST_CONNECTABLE;
372 settings |= MGMT_SETTING_DISCOVERABLE;
373 settings |= MGMT_SETTING_PAIRABLE;
Johan Hedberg03811012010-12-08 00:21:06 +0200374
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200375 if (hdev->features[6] & LMP_SIMPLE_PAIR)
376 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200377
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200378 if (!(hdev->features[4] & LMP_NO_BREDR)) {
379 settings |= MGMT_SETTING_BREDR;
380 settings |= MGMT_SETTING_LINK_SECURITY;
381 }
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200382
Marcel Holtmannd7b7e792012-02-20 21:47:49 +0100383 if (enable_hs)
384 settings |= MGMT_SETTING_HS;
385
386 if (enable_le) {
387 if (hdev->features[4] & LMP_LE)
388 settings |= MGMT_SETTING_LE;
389 }
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200390
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200391 return settings;
392}
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200393
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200394static u32 get_current_settings(struct hci_dev *hdev)
395{
396 u32 settings = 0;
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200397
Johan Hedbergf1f0eb02012-02-21 17:15:41 +0200398 if (hdev_is_powered(hdev))
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100399 settings |= MGMT_SETTING_POWERED;
400
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200401 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200402 settings |= MGMT_SETTING_CONNECTABLE;
403
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200404 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200405 settings |= MGMT_SETTING_DISCOVERABLE;
406
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200407 if (test_bit(HCI_PAIRABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200408 settings |= MGMT_SETTING_PAIRABLE;
409
410 if (!(hdev->features[4] & LMP_NO_BREDR))
411 settings |= MGMT_SETTING_BREDR;
412
Johan Hedberg06199cf2012-02-22 16:37:11 +0200413 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200414 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200415
Johan Hedberg47990ea2012-02-22 11:58:37 +0200416 if (test_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200417 settings |= MGMT_SETTING_LINK_SECURITY;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200418
Johan Hedberg84bde9d2012-01-25 14:21:06 +0200419 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200420 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200421
Johan Hedberg6d80dfd2012-02-20 23:50:38 +0200422 if (test_bit(HCI_HS_ENABLED, &hdev->dev_flags))
423 settings |= MGMT_SETTING_HS;
424
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200425 return settings;
Johan Hedbergc542a062011-01-26 13:11:03 +0200426}
427
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300428#define PNP_INFO_SVCLASS_ID 0x1200
429
430static u8 bluetooth_base_uuid[] = {
431 0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80,
432 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
433};
434
435static u16 get_uuid16(u8 *uuid128)
436{
437 u32 val;
438 int i;
439
440 for (i = 0; i < 12; i++) {
441 if (bluetooth_base_uuid[i] != uuid128[i])
442 return 0;
443 }
444
445 memcpy(&val, &uuid128[12], 4);
446
447 val = le32_to_cpu(val);
448 if (val > 0xffff)
449 return 0;
450
451 return (u16) val;
452}
453
454static void create_eir(struct hci_dev *hdev, u8 *data)
455{
456 u8 *ptr = data;
457 u16 eir_len = 0;
458 u16 uuid16_list[HCI_MAX_EIR_LENGTH / sizeof(u16)];
459 int i, truncated = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200460 struct bt_uuid *uuid;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300461 size_t name_len;
462
463 name_len = strlen(hdev->dev_name);
464
465 if (name_len > 0) {
466 /* EIR Data type */
467 if (name_len > 48) {
468 name_len = 48;
469 ptr[1] = EIR_NAME_SHORT;
470 } else
471 ptr[1] = EIR_NAME_COMPLETE;
472
473 /* EIR Data length */
474 ptr[0] = name_len + 1;
475
476 memcpy(ptr + 2, hdev->dev_name, name_len);
477
478 eir_len += (name_len + 2);
479 ptr += (name_len + 2);
480 }
481
482 memset(uuid16_list, 0, sizeof(uuid16_list));
483
484 /* Group all UUID16 types */
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200485 list_for_each_entry(uuid, &hdev->uuids, list) {
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300486 u16 uuid16;
487
488 uuid16 = get_uuid16(uuid->uuid);
489 if (uuid16 == 0)
490 return;
491
492 if (uuid16 < 0x1100)
493 continue;
494
495 if (uuid16 == PNP_INFO_SVCLASS_ID)
496 continue;
497
498 /* Stop if not enough space to put next UUID */
499 if (eir_len + 2 + sizeof(u16) > HCI_MAX_EIR_LENGTH) {
500 truncated = 1;
501 break;
502 }
503
504 /* Check for duplicates */
505 for (i = 0; uuid16_list[i] != 0; i++)
506 if (uuid16_list[i] == uuid16)
507 break;
508
509 if (uuid16_list[i] == 0) {
510 uuid16_list[i] = uuid16;
511 eir_len += sizeof(u16);
512 }
513 }
514
515 if (uuid16_list[0] != 0) {
516 u8 *length = ptr;
517
518 /* EIR Data type */
519 ptr[1] = truncated ? EIR_UUID16_SOME : EIR_UUID16_ALL;
520
521 ptr += 2;
522 eir_len += 2;
523
524 for (i = 0; uuid16_list[i] != 0; i++) {
525 *ptr++ = (uuid16_list[i] & 0x00ff);
526 *ptr++ = (uuid16_list[i] & 0xff00) >> 8;
527 }
528
529 /* EIR Data length */
530 *length = (i * sizeof(u16)) + 1;
531 }
532}
533
534static int update_eir(struct hci_dev *hdev)
535{
536 struct hci_cp_write_eir cp;
537
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200538 if (!hdev_is_powered(hdev))
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200539 return 0;
540
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300541 if (!(hdev->features[6] & LMP_EXT_INQ))
542 return 0;
543
Johan Hedberg84bde9d2012-01-25 14:21:06 +0200544 if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300545 return 0;
546
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200547 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300548 return 0;
549
550 memset(&cp, 0, sizeof(cp));
551
552 create_eir(hdev, cp.data);
553
554 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
555 return 0;
556
557 memcpy(hdev->eir, cp.data, sizeof(cp.data));
558
559 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
560}
561
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200562static u8 get_service_classes(struct hci_dev *hdev)
563{
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300564 struct bt_uuid *uuid;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200565 u8 val = 0;
566
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300567 list_for_each_entry(uuid, &hdev->uuids, list)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200568 val |= uuid->svc_hint;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200569
570 return val;
571}
572
573static int update_class(struct hci_dev *hdev)
574{
575 u8 cod[3];
Johan Hedbergc95f0ba2012-02-23 22:54:38 +0200576 int err;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200577
578 BT_DBG("%s", hdev->name);
579
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200580 if (!hdev_is_powered(hdev))
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200581 return 0;
582
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200583 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200584 return 0;
585
586 cod[0] = hdev->minor_class;
587 cod[1] = hdev->major_class;
588 cod[2] = get_service_classes(hdev);
589
590 if (memcmp(cod, hdev->dev_class, 3) == 0)
591 return 0;
592
Johan Hedbergc95f0ba2012-02-23 22:54:38 +0200593 err = hci_send_cmd(hdev, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
594 if (err == 0)
595 set_bit(HCI_PENDING_CLASS, &hdev->dev_flags);
596
597 return err;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200598}
599
Johan Hedberg7d785252011-12-15 00:47:39 +0200600static void service_cache_off(struct work_struct *work)
601{
602 struct hci_dev *hdev = container_of(work, struct hci_dev,
603 service_cache.work);
604
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200605 if (!test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200606 return;
607
608 hci_dev_lock(hdev);
609
610 update_eir(hdev);
611 update_class(hdev);
612
613 hci_dev_unlock(hdev);
614}
615
Johan Hedberg6a919082012-02-28 06:17:26 +0200616static void mgmt_init_hdev(struct sock *sk, struct hci_dev *hdev)
Johan Hedberg7d785252011-12-15 00:47:39 +0200617{
Johan Hedberg6a919082012-02-28 06:17:26 +0200618 if (!test_and_clear_bit(HCI_PI_MGMT_INIT, &hci_pi(sk)->flags))
619 return;
620
Johan Hedberg0cbf4ed62012-02-21 17:25:22 +0200621 if (!test_and_set_bit(HCI_MGMT, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +0200622 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
623
Johan Hedberg0cbf4ed62012-02-21 17:25:22 +0200624 /* Non-mgmt controlled devices get this bit set
625 * implicitly so that pairing works for them, however
626 * for mgmt we require user-space to explicitly enable
627 * it
628 */
629 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
630 }
Johan Hedberg7d785252011-12-15 00:47:39 +0200631}
632
Johan Hedberg0f4e68c2012-02-28 17:18:30 +0200633static int read_controller_info(struct sock *sk, struct hci_dev *hdev,
634 void *data, u16 data_len)
Johan Hedberg03811012010-12-08 00:21:06 +0200635{
636 struct mgmt_rp_read_info rp;
Johan Hedberg03811012010-12-08 00:21:06 +0200637
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200638 BT_DBG("sock %p %s", sk, hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200639
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300640 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200641
Johan Hedberg03811012010-12-08 00:21:06 +0200642 memset(&rp, 0, sizeof(rp));
643
Johan Hedberg03811012010-12-08 00:21:06 +0200644 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200645
646 rp.version = hdev->hci_ver;
647
Johan Hedberg03811012010-12-08 00:21:06 +0200648 put_unaligned_le16(hdev->manufacturer, &rp.manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200649
650 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
651 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
652
653 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedberg03811012010-12-08 00:21:06 +0200654
655 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
Johan Hedberg27fcc362012-02-22 21:46:22 +0200656 memcpy(rp.short_name, hdev->short_name, sizeof(hdev->short_name));
Johan Hedberg03811012010-12-08 00:21:06 +0200657
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300658 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200659
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200660 return cmd_complete(sk, hdev->id, MGMT_OP_READ_INFO, 0, &rp,
661 sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +0200662}
663
664static void mgmt_pending_free(struct pending_cmd *cmd)
665{
666 sock_put(cmd->sk);
667 kfree(cmd->param);
668 kfree(cmd);
669}
670
671static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
672 struct hci_dev *hdev,
673 void *data, u16 len)
674{
675 struct pending_cmd *cmd;
676
677 cmd = kmalloc(sizeof(*cmd), GFP_ATOMIC);
678 if (!cmd)
679 return NULL;
680
681 cmd->opcode = opcode;
682 cmd->index = hdev->id;
683
684 cmd->param = kmalloc(len, GFP_ATOMIC);
685 if (!cmd->param) {
686 kfree(cmd);
687 return NULL;
688 }
689
690 if (data)
691 memcpy(cmd->param, data, len);
692
693 cmd->sk = sk;
694 sock_hold(sk);
695
696 list_add(&cmd->list, &hdev->mgmt_pending);
697
698 return cmd;
699}
700
701static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
702 void (*cb)(struct pending_cmd *cmd, void *data),
703 void *data)
704{
705 struct list_head *p, *n;
706
707 list_for_each_safe(p, n, &hdev->mgmt_pending) {
708 struct pending_cmd *cmd;
709
710 cmd = list_entry(p, struct pending_cmd, list);
711
712 if (opcode > 0 && cmd->opcode != opcode)
713 continue;
714
715 cb(cmd, data);
716 }
717}
718
719static struct pending_cmd *mgmt_pending_find(u16 opcode, struct hci_dev *hdev)
720{
721 struct pending_cmd *cmd;
722
723 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
724 if (cmd->opcode == opcode)
725 return cmd;
726 }
727
728 return NULL;
729}
730
731static void mgmt_pending_remove(struct pending_cmd *cmd)
732{
733 list_del(&cmd->list);
734 mgmt_pending_free(cmd);
735}
736
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200737static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +0200738{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200739 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +0200740
Johan Hedbergaee9b2182012-02-18 15:07:59 +0200741 return cmd_complete(sk, hdev->id, opcode, 0, &settings,
742 sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +0200743}
744
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200745static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data,
746 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200747{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300748 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200749 struct pending_cmd *cmd;
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200750 int err;
Johan Hedberg03811012010-12-08 00:21:06 +0200751
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200752 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200753
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300754 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200755
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100756 if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) {
757 cancel_delayed_work(&hdev->power_off);
758
759 if (cp->val) {
760 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
761 mgmt_powered(hdev, 1);
762 goto failed;
763 }
764 }
765
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200766 if (!!cp->val == hdev_is_powered(hdev)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200767 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200768 goto failed;
769 }
770
771 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200772 err = cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
Johan Hedbergca69b792011-11-11 18:10:00 +0200773 MGMT_STATUS_BUSY);
Johan Hedberg03811012010-12-08 00:21:06 +0200774 goto failed;
775 }
776
777 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
778 if (!cmd) {
779 err = -ENOMEM;
780 goto failed;
781 }
782
783 if (cp->val)
Gustavo F. Padovan7f971042011-12-18 12:40:32 -0200784 schedule_work(&hdev->power_on);
Johan Hedberg03811012010-12-08 00:21:06 +0200785 else
Gustavo F. Padovan80b7ab32011-12-17 14:52:27 -0200786 schedule_work(&hdev->power_off.work);
Johan Hedberg03811012010-12-08 00:21:06 +0200787
788 err = 0;
789
790failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300791 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200792 return err;
793}
794
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200795static int mgmt_event(u16 event, struct hci_dev *hdev, void *data,
796 u16 data_len, struct sock *skip_sk)
797{
798 struct sk_buff *skb;
799 struct mgmt_hdr *hdr;
800
801 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_ATOMIC);
802 if (!skb)
803 return -ENOMEM;
804
805 hdr = (void *) skb_put(skb, sizeof(*hdr));
806 hdr->opcode = cpu_to_le16(event);
807 if (hdev)
808 hdr->index = cpu_to_le16(hdev->id);
809 else
810 hdr->index = cpu_to_le16(MGMT_INDEX_NONE);
811 hdr->len = cpu_to_le16(data_len);
812
813 if (data)
814 memcpy(skb_put(skb, data_len), data, data_len);
815
Marcel Holtmann97e0bde2012-02-22 13:49:28 +0100816 /* Time stamp */
817 __net_timestamp(skb);
818
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200819 hci_send_to_control(skb, skip_sk);
820 kfree_skb(skb);
821
822 return 0;
823}
824
825static int new_settings(struct hci_dev *hdev, struct sock *skip)
826{
827 __le32 ev;
828
829 ev = cpu_to_le32(get_current_settings(hdev));
830
831 return mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), skip);
832}
833
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200834static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
835 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200836{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300837 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200838 struct pending_cmd *cmd;
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200839 u16 timeout;
Johan Hedberg03811012010-12-08 00:21:06 +0200840 u8 scan;
841 int err;
842
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200843 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200844
Marcel Holtmann24c54a92012-02-22 18:06:34 +0100845 timeout = get_unaligned_le16(&cp->timeout);
846 if (!cp->val && timeout > 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200847 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +0200848 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200849
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300850 hci_dev_lock(hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200851
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200852 if (!hdev_is_powered(hdev) && timeout > 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200853 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +0200854 MGMT_STATUS_NOT_POWERED);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200855 goto failed;
856 }
857
858 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
859 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200860 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +0200861 MGMT_STATUS_BUSY);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200862 goto failed;
863 }
864
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200865 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200866 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200867 MGMT_STATUS_REJECTED);
868 goto failed;
869 }
870
871 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200872 bool changed = false;
873
874 if (!!cp->val != test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
875 change_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
876 changed = true;
877 }
878
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200879 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200880 if (err < 0)
881 goto failed;
882
883 if (changed)
884 err = new_settings(hdev, sk);
885
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200886 goto failed;
887 }
888
889 if (!!cp->val == test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
Marcel Holtmann955638e2012-02-22 18:21:00 +0100890 if (hdev->discov_timeout > 0) {
891 cancel_delayed_work(&hdev->discov_off);
892 hdev->discov_timeout = 0;
893 }
894
895 if (cp->val && timeout > 0) {
896 hdev->discov_timeout = timeout;
897 queue_delayed_work(hdev->workqueue, &hdev->discov_off,
898 msecs_to_jiffies(hdev->discov_timeout * 1000));
899 }
900
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200901 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200902 goto failed;
903 }
904
905 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
906 if (!cmd) {
907 err = -ENOMEM;
908 goto failed;
909 }
910
911 scan = SCAN_PAGE;
912
913 if (cp->val)
914 scan |= SCAN_INQUIRY;
915 else
916 cancel_delayed_work(&hdev->discov_off);
917
918 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
919 if (err < 0)
920 mgmt_pending_remove(cmd);
921
Johan Hedberg03811012010-12-08 00:21:06 +0200922 if (cp->val)
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200923 hdev->discov_timeout = timeout;
Johan Hedberg03811012010-12-08 00:21:06 +0200924
925failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300926 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200927 return err;
928}
929
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200930static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
931 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200932{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300933 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200934 struct pending_cmd *cmd;
935 u8 scan;
936 int err;
937
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200938 BT_DBG("request for %s", hdev->name);
Johan Hedberge41d8b42010-12-13 21:07:03 +0200939
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300940 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200941
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200942 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200943 bool changed = false;
944
945 if (!!cp->val != test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
946 changed = true;
947
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +0200948 if (cp->val) {
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200949 set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +0200950 } else {
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200951 clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
952 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
953 }
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200954
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200955 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200956 if (err < 0)
957 goto failed;
958
959 if (changed)
960 err = new_settings(hdev, sk);
961
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200962 goto failed;
963 }
964
965 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
966 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200967 err = cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +0200968 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200969 goto failed;
970 }
971
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200972 if (!!cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200973 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200974 goto failed;
975 }
976
977 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
978 if (!cmd) {
979 err = -ENOMEM;
980 goto failed;
981 }
982
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +0200983 if (cp->val) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200984 scan = SCAN_PAGE;
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +0200985 } else {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200986 scan = 0;
987
Johan Hedbergdf2c6c52012-02-21 19:15:49 +0200988 if (test_bit(HCI_ISCAN, &hdev->flags) &&
989 hdev->discov_timeout > 0)
990 cancel_delayed_work(&hdev->discov_off);
991 }
992
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200993 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
994 if (err < 0)
995 mgmt_pending_remove(cmd);
996
997failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300998 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200999 return err;
1000}
1001
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001002static int set_pairable(struct sock *sk, struct hci_dev *hdev, void *data,
1003 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001004{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001005 struct mgmt_mode *cp = data;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001006 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001007
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001008 BT_DBG("request for %s", hdev->name);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001009
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001010 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001011
1012 if (cp->val)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001013 set_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001014 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001015 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001016
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001017 err = send_settings_rsp(sk, MGMT_OP_SET_PAIRABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001018 if (err < 0)
1019 goto failed;
1020
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001021 err = new_settings(hdev, sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001022
1023failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001024 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001025 return err;
1026}
Johan Hedberg72a734e2010-12-30 00:38:22 +02001027
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001028static int set_link_security(struct sock *sk, struct hci_dev *hdev,
1029 void *data, u16 len)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001030{
1031 struct mgmt_mode *cp = data;
1032 struct pending_cmd *cmd;
Johan Hedberg816a11d2012-02-26 13:04:52 +02001033 u8 val;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001034 int err;
1035
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001036 BT_DBG("request for %s", hdev->name);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001037
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001038 hci_dev_lock(hdev);
1039
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001040 if (!hdev_is_powered(hdev)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001041 bool changed = false;
1042
1043 if (!!cp->val != test_bit(HCI_LINK_SECURITY,
1044 &hdev->dev_flags)) {
1045 change_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
1046 changed = true;
1047 }
1048
1049 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1050 if (err < 0)
1051 goto failed;
1052
1053 if (changed)
1054 err = new_settings(hdev, sk);
1055
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001056 goto failed;
1057 }
1058
1059 if (mgmt_pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001060 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001061 MGMT_STATUS_BUSY);
1062 goto failed;
1063 }
1064
1065 val = !!cp->val;
1066
1067 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1068 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1069 goto failed;
1070 }
1071
1072 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1073 if (!cmd) {
1074 err = -ENOMEM;
1075 goto failed;
1076 }
1077
1078 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1079 if (err < 0) {
1080 mgmt_pending_remove(cmd);
1081 goto failed;
1082 }
1083
1084failed:
1085 hci_dev_unlock(hdev);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001086 return err;
1087}
1088
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001089static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001090{
1091 struct mgmt_mode *cp = data;
1092 struct pending_cmd *cmd;
Johan Hedberg816a11d2012-02-26 13:04:52 +02001093 u8 val;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001094 int err;
1095
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001096 BT_DBG("request for %s", hdev->name);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001097
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001098 hci_dev_lock(hdev);
1099
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001100 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001101 err = cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001102 MGMT_STATUS_NOT_SUPPORTED);
1103 goto failed;
1104 }
1105
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001106 val = !!cp->val;
1107
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001108 if (!hdev_is_powered(hdev)) {
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001109 bool changed = false;
1110
1111 if (val != test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) {
1112 change_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
1113 changed = true;
1114 }
1115
1116 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1117 if (err < 0)
1118 goto failed;
1119
1120 if (changed)
1121 err = new_settings(hdev, sk);
1122
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001123 goto failed;
1124 }
1125
1126 if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001127 err = cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1128 MGMT_STATUS_BUSY);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001129 goto failed;
1130 }
1131
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001132 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) == val) {
1133 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1134 goto failed;
1135 }
1136
1137 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1138 if (!cmd) {
1139 err = -ENOMEM;
1140 goto failed;
1141 }
1142
1143 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, sizeof(val), &val);
1144 if (err < 0) {
1145 mgmt_pending_remove(cmd);
1146 goto failed;
1147 }
1148
1149failed:
1150 hci_dev_unlock(hdev);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001151 return err;
1152}
1153
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001154static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001155{
1156 struct mgmt_mode *cp = data;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001157
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001158 BT_DBG("request for %s", hdev->name);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001159
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001160 if (!enable_hs)
1161 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1162 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001163
1164 if (cp->val)
1165 set_bit(HCI_HS_ENABLED, &hdev->dev_flags);
1166 else
1167 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
1168
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001169 return send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001170}
1171
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001172static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001173{
1174 struct mgmt_mode *cp = data;
1175 struct hci_cp_write_le_host_supported hci_cp;
1176 struct pending_cmd *cmd;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001177 int err;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001178 u8 val, enabled;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001179
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001180 BT_DBG("request for %s", hdev->name);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001181
Johan Hedberg1de028c2012-02-29 19:55:35 -08001182 hci_dev_lock(hdev);
1183
Johan Hedberg06199cf2012-02-22 16:37:11 +02001184 if (!enable_le || !(hdev->features[4] & LMP_LE)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001185 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
Johan Hedberg06199cf2012-02-22 16:37:11 +02001186 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001187 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001188 }
1189
1190 val = !!cp->val;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001191 enabled = !!(hdev->host_features[0] & LMP_HOST_LE);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001192
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001193 if (!hdev_is_powered(hdev) || val == enabled) {
Johan Hedberg06199cf2012-02-22 16:37:11 +02001194 bool changed = false;
1195
1196 if (val != test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
1197 change_bit(HCI_LE_ENABLED, &hdev->dev_flags);
1198 changed = true;
1199 }
1200
1201 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1202 if (err < 0)
Johan Hedberg1de028c2012-02-29 19:55:35 -08001203 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001204
1205 if (changed)
1206 err = new_settings(hdev, sk);
1207
Johan Hedberg1de028c2012-02-29 19:55:35 -08001208 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001209 }
1210
1211 if (mgmt_pending_find(MGMT_OP_SET_LE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001212 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1213 MGMT_STATUS_BUSY);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001214 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001215 }
1216
1217 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
1218 if (!cmd) {
1219 err = -ENOMEM;
Johan Hedberg1de028c2012-02-29 19:55:35 -08001220 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001221 }
1222
1223 memset(&hci_cp, 0, sizeof(hci_cp));
1224
1225 if (val) {
1226 hci_cp.le = val;
1227 hci_cp.simul = !!(hdev->features[6] & LMP_SIMUL_LE_BR);
1228 }
1229
1230 err = hci_send_cmd(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED,
1231 sizeof(hci_cp), &hci_cp);
1232 if (err < 0) {
1233 mgmt_pending_remove(cmd);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001234 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001235 }
1236
Johan Hedberg1de028c2012-02-29 19:55:35 -08001237unlock:
1238 hci_dev_unlock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001239 return err;
1240}
1241
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001242static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001243{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001244 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001245 struct pending_cmd *cmd;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001246 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001247 int err;
1248
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001249 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001250
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001251 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001252
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001253 if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001254 err = cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID,
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001255 MGMT_STATUS_BUSY);
1256 goto failed;
1257 }
1258
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001259 uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC);
1260 if (!uuid) {
1261 err = -ENOMEM;
1262 goto failed;
1263 }
1264
1265 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001266 uuid->svc_hint = cp->svc_hint;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001267
1268 list_add(&uuid->list, &hdev->uuids);
1269
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001270 err = update_class(hdev);
1271 if (err < 0)
1272 goto failed;
1273
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001274 err = update_eir(hdev);
1275 if (err < 0)
1276 goto failed;
1277
Johan Hedberg90e70452012-02-23 23:09:40 +02001278 if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001279 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0,
Johan Hedberg90e70452012-02-23 23:09:40 +02001280 hdev->dev_class, 3);
1281 goto failed;
1282 }
1283
1284 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len);
1285 if (!cmd) {
1286 err = -ENOMEM;
1287 goto failed;
1288 }
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001289
1290failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001291 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001292 return err;
1293}
1294
Johan Hedberg24b78d02012-02-23 23:24:30 +02001295static bool enable_service_cache(struct hci_dev *hdev)
1296{
1297 if (!hdev_is_powered(hdev))
1298 return false;
1299
1300 if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
1301 schedule_delayed_work(&hdev->service_cache,
1302 msecs_to_jiffies(SERVICE_CACHE_TIMEOUT));
1303 return true;
1304 }
1305
1306 return false;
1307}
1308
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001309static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
1310 u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001311{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001312 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001313 struct pending_cmd *cmd;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001314 struct list_head *p, *n;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001315 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 +02001316 int err, found;
1317
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001318 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001319
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001320 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001321
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001322 if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001323 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001324 MGMT_STATUS_BUSY);
1325 goto unlock;
1326 }
1327
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001328 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
1329 err = hci_uuids_clear(hdev);
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001330
Johan Hedberg24b78d02012-02-23 23:24:30 +02001331 if (enable_service_cache(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001332 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID,
1333 0, hdev->dev_class, 3);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001334 goto unlock;
1335 }
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001336
Johan Hedberg9246a862012-02-23 21:33:16 +02001337 goto update_class;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001338 }
1339
1340 found = 0;
1341
1342 list_for_each_safe(p, n, &hdev->uuids) {
1343 struct bt_uuid *match = list_entry(p, struct bt_uuid, list);
1344
1345 if (memcmp(match->uuid, cp->uuid, 16) != 0)
1346 continue;
1347
1348 list_del(&match->list);
1349 found++;
1350 }
1351
1352 if (found == 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001353 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Johan Hedbergca69b792011-11-11 18:10:00 +02001354 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001355 goto unlock;
1356 }
1357
Johan Hedberg9246a862012-02-23 21:33:16 +02001358update_class:
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001359 err = update_class(hdev);
1360 if (err < 0)
1361 goto unlock;
1362
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001363 err = update_eir(hdev);
1364 if (err < 0)
1365 goto unlock;
1366
Johan Hedberg90e70452012-02-23 23:09:40 +02001367 if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001368 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0,
Johan Hedberg9997a532012-02-23 15:57:46 +02001369 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001370 goto unlock;
1371 }
1372
1373 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
1374 if (!cmd) {
1375 err = -ENOMEM;
1376 goto unlock;
1377 }
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001378
1379unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001380 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001381 return err;
1382}
1383
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001384static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
1385 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001386{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001387 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001388 struct pending_cmd *cmd;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001389 int err;
1390
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001391 BT_DBG("request for %s", hdev->name);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001392
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001393 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001394
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001395 if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001396 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001397 MGMT_STATUS_BUSY);
1398 goto unlock;
1399 }
1400
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001401 hdev->major_class = cp->major;
1402 hdev->minor_class = cp->minor;
1403
Johan Hedberg932f5ff2012-02-22 22:11:32 +02001404 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001405 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Johan Hedberg932f5ff2012-02-22 22:11:32 +02001406 hdev->dev_class, 3);
1407 goto unlock;
1408 }
1409
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001410 if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02001411 hci_dev_unlock(hdev);
1412 cancel_delayed_work_sync(&hdev->service_cache);
1413 hci_dev_lock(hdev);
Johan Hedberg14c0b602011-12-15 00:47:37 +02001414 update_eir(hdev);
Johan Hedberg7d785252011-12-15 00:47:39 +02001415 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02001416
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001417 err = update_class(hdev);
Johan Hedberg90e70452012-02-23 23:09:40 +02001418 if (err < 0)
1419 goto unlock;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001420
Johan Hedberg90e70452012-02-23 23:09:40 +02001421 if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001422 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Johan Hedberg8ec37032012-02-22 22:02:50 +02001423 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001424 goto unlock;
1425 }
1426
1427 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
1428 if (!cmd) {
1429 err = -ENOMEM;
1430 goto unlock;
1431 }
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001432
Johan Hedbergb5235a62012-02-21 14:32:24 +02001433unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001434 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001435 return err;
1436}
1437
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001438static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
1439 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001440{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001441 struct mgmt_cp_load_link_keys *cp = data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001442 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001443 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001444
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001445 key_count = get_unaligned_le16(&cp->key_count);
1446
Johan Hedberg86742e12011-11-07 23:13:38 +02001447 expected_len = sizeof(*cp) + key_count *
1448 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001449 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001450 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001451 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001452 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
Johan Hedbergca69b792011-11-11 18:10:00 +02001453 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001454 }
1455
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001456 BT_DBG("%s debug_keys %u key_count %u", hdev->name, cp->debug_keys,
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001457 key_count);
1458
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001459 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001460
1461 hci_link_keys_clear(hdev);
1462
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001463 set_bit(HCI_LINK_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001464
1465 if (cp->debug_keys)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001466 set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001467 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001468 clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001469
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001470 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001471 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001472
Johan Hedbergd753fdc2012-02-17 14:06:34 +02001473 hci_add_link_key(hdev, NULL, 0, &key->addr.bdaddr, key->val,
1474 key->type, key->pin_len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001475 }
1476
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001477 cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02001478
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001479 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001480
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001481 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001482}
1483
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001484static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
1485 u8 addr_type, struct sock *skip_sk)
1486{
1487 struct mgmt_ev_device_unpaired ev;
1488
1489 bacpy(&ev.addr.bdaddr, bdaddr);
1490 ev.addr.type = addr_type;
1491
1492 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
1493 skip_sk);
1494}
1495
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001496static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
1497 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001498{
Johan Hedberg124f6e32012-02-09 13:50:12 +02001499 struct mgmt_cp_unpair_device *cp = data;
1500 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001501 struct hci_cp_disconnect dc;
1502 struct pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001503 struct hci_conn *conn;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001504 int err;
1505
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001506 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001507
Johan Hedberga8a1d192011-11-10 15:54:38 +02001508 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02001509 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1510 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001511
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001512 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001513 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001514 MGMT_STATUS_NOT_POWERED,
1515 &rp, sizeof(rp));
1516 goto unlock;
1517 }
1518
Johan Hedberg124f6e32012-02-09 13:50:12 +02001519 if (cp->addr.type == MGMT_ADDR_BREDR)
1520 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
1521 else
1522 err = hci_remove_ltk(hdev, &cp->addr.bdaddr);
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03001523
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001524 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001525 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001526 MGMT_STATUS_NOT_PAIRED,
1527 &rp, sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001528 goto unlock;
1529 }
1530
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001531 if (cp->disconnect) {
1532 if (cp->addr.type == MGMT_ADDR_BREDR)
1533 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
1534 &cp->addr.bdaddr);
1535 else
1536 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
1537 &cp->addr.bdaddr);
1538 } else {
1539 conn = NULL;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001540 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001541
Johan Hedberga8a1d192011-11-10 15:54:38 +02001542 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001543 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0,
Johan Hedbergaee9b2182012-02-18 15:07:59 +02001544 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001545 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001546 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001547 }
1548
Johan Hedberg124f6e32012-02-09 13:50:12 +02001549 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
1550 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02001551 if (!cmd) {
1552 err = -ENOMEM;
1553 goto unlock;
1554 }
1555
1556 put_unaligned_le16(conn->handle, &dc.handle);
1557 dc.reason = 0x13; /* Remote User Terminated Connection */
1558 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1559 if (err < 0)
1560 mgmt_pending_remove(cmd);
1561
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001562unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001563 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001564 return err;
1565}
1566
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001567static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
1568 u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02001569{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001570 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001571 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03001572 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001573 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001574 int err;
1575
1576 BT_DBG("");
1577
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001578 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001579
1580 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001581 err = cmd_status(sk, hdev->id, MGMT_OP_DISCONNECT,
Johan Hedbergca69b792011-11-11 18:10:00 +02001582 MGMT_STATUS_NOT_POWERED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001583 goto failed;
1584 }
1585
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001586 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001587 err = cmd_status(sk, hdev->id, MGMT_OP_DISCONNECT,
Johan Hedbergca69b792011-11-11 18:10:00 +02001588 MGMT_STATUS_BUSY);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001589 goto failed;
1590 }
1591
Johan Hedberg88c3df12012-02-09 14:27:38 +02001592 if (cp->addr.type == MGMT_ADDR_BREDR)
1593 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
1594 else
1595 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03001596
Johan Hedberg8962ee72011-01-20 12:40:27 +02001597 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001598 err = cmd_status(sk, hdev->id, MGMT_OP_DISCONNECT,
Johan Hedbergca69b792011-11-11 18:10:00 +02001599 MGMT_STATUS_NOT_CONNECTED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001600 goto failed;
1601 }
1602
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001603 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001604 if (!cmd) {
1605 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001606 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001607 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001608
1609 put_unaligned_le16(conn->handle, &dc.handle);
1610 dc.reason = 0x13; /* Remote User Terminated Connection */
1611
1612 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1613 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001614 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001615
1616failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001617 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001618 return err;
1619}
1620
Johan Hedberg48264f02011-11-09 13:58:58 +02001621static u8 link_to_mgmt(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02001622{
1623 switch (link_type) {
1624 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02001625 switch (addr_type) {
1626 case ADDR_LE_DEV_PUBLIC:
1627 return MGMT_ADDR_LE_PUBLIC;
1628 case ADDR_LE_DEV_RANDOM:
1629 return MGMT_ADDR_LE_RANDOM;
1630 default:
1631 return MGMT_ADDR_INVALID;
1632 }
Johan Hedberg4c659c32011-11-07 23:13:39 +02001633 case ACL_LINK:
1634 return MGMT_ADDR_BREDR;
1635 default:
1636 return MGMT_ADDR_INVALID;
1637 }
1638}
1639
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02001640static int get_connections(struct sock *sk, struct hci_dev *hdev,
1641 void *data, u16 data_len)
Johan Hedberg2784eb42011-01-21 13:56:35 +02001642{
Johan Hedberg2784eb42011-01-21 13:56:35 +02001643 struct mgmt_rp_get_connections *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001644 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02001645 size_t rp_len;
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001646 int err;
1647 u16 i;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001648
1649 BT_DBG("");
1650
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001651 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001652
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001653 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001654 err = cmd_status(sk, hdev->id, MGMT_OP_GET_CONNECTIONS,
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001655 MGMT_STATUS_NOT_POWERED);
1656 goto unlock;
1657 }
1658
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001659 i = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02001660 list_for_each_entry(c, &hdev->conn_hash.list, list) {
1661 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001662 i++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001663 }
1664
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001665 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberga38528f2011-01-22 06:46:43 +02001666 rp = kmalloc(rp_len, GFP_ATOMIC);
1667 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02001668 err = -ENOMEM;
1669 goto unlock;
1670 }
1671
Johan Hedberg2784eb42011-01-21 13:56:35 +02001672 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001673 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02001674 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
1675 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001676 bacpy(&rp->addr[i].bdaddr, &c->dst);
Johan Hedberg48264f02011-11-09 13:58:58 +02001677 rp->addr[i].type = link_to_mgmt(c->type, c->dst_type);
Johan Hedberg4c659c32011-11-07 23:13:39 +02001678 if (rp->addr[i].type == MGMT_ADDR_INVALID)
1679 continue;
1680 i++;
1681 }
1682
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001683 put_unaligned_le16(i, &rp->conn_count);
1684
Johan Hedberg4c659c32011-11-07 23:13:39 +02001685 /* Recalculate length in case of filtered SCO connections, etc */
1686 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02001687
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001688 err = cmd_complete(sk, hdev->id, MGMT_OP_GET_CONNECTIONS, 0, rp,
1689 rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001690
Johan Hedberga38528f2011-01-22 06:46:43 +02001691 kfree(rp);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001692
1693unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001694 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001695 return err;
1696}
1697
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001698static int send_pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
1699 struct mgmt_cp_pin_code_neg_reply *cp)
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001700{
1701 struct pending_cmd *cmd;
1702 int err;
1703
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001704 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001705 sizeof(*cp));
1706 if (!cmd)
1707 return -ENOMEM;
1708
Johan Hedbergd8457692012-02-17 14:24:57 +02001709 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
1710 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001711 if (err < 0)
1712 mgmt_pending_remove(cmd);
1713
1714 return err;
1715}
1716
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001717static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data,
1718 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001719{
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001720 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001721 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001722 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03001723 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001724 int err;
1725
1726 BT_DBG("");
1727
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001728 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001729
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001730 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001731 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001732 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001733 goto failed;
1734 }
1735
Johan Hedbergd8457692012-02-17 14:24:57 +02001736 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001737 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001738 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001739 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001740 goto failed;
1741 }
1742
1743 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02001744 struct mgmt_cp_pin_code_neg_reply ncp;
1745
1746 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001747
1748 BT_ERR("PIN code is not 16 bytes long");
1749
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001750 err = send_pin_code_neg_reply(sk, hdev, &ncp);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001751 if (err >= 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001752 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001753 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001754
1755 goto failed;
1756 }
1757
Gustavo F. Padovan00abfe42012-03-01 00:37:10 -03001758 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001759 if (!cmd) {
1760 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001761 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001762 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02001763
Johan Hedbergd8457692012-02-17 14:24:57 +02001764 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001765 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02001766 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02001767
1768 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
1769 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001770 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001771
1772failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001773 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001774 return err;
1775}
1776
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001777static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
1778 void *data, u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001779{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001780 struct mgmt_cp_pin_code_neg_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001781 int err;
1782
1783 BT_DBG("");
1784
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001785 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001786
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001787 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001788 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001789 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001790 goto failed;
1791 }
1792
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001793 err = send_pin_code_neg_reply(sk, hdev, cp);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001794
1795failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001796 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001797 return err;
1798}
1799
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001800static int set_io_capability(struct sock *sk, struct hci_dev *hdev,
1801 void *data, u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001802{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001803 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001804
1805 BT_DBG("");
1806
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001807 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001808
1809 hdev->io_capability = cp->io_capability;
1810
1811 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Szymon Jancb8534e02011-03-01 16:55:34 +01001812 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001813
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001814 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001815
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001816 return cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, 0,
1817 NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001818}
1819
Johan Hedberge9a416b2011-02-19 12:05:56 -03001820static inline struct pending_cmd *find_pairing(struct hci_conn *conn)
1821{
1822 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001823 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001824
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001825 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03001826 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
1827 continue;
1828
Johan Hedberge9a416b2011-02-19 12:05:56 -03001829 if (cmd->user_data != conn)
1830 continue;
1831
1832 return cmd;
1833 }
1834
1835 return NULL;
1836}
1837
1838static void pairing_complete(struct pending_cmd *cmd, u8 status)
1839{
1840 struct mgmt_rp_pair_device rp;
1841 struct hci_conn *conn = cmd->user_data;
1842
Johan Hedbergba4e5642011-11-11 00:07:34 +02001843 bacpy(&rp.addr.bdaddr, &conn->dst);
1844 rp.addr.type = link_to_mgmt(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001845
Johan Hedbergaee9b2182012-02-18 15:07:59 +02001846 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, status,
1847 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001848
1849 /* So we don't get further callbacks for this connection */
1850 conn->connect_cfm_cb = NULL;
1851 conn->security_cfm_cb = NULL;
1852 conn->disconn_cfm_cb = NULL;
1853
1854 hci_conn_put(conn);
1855
Johan Hedberga664b5b2011-02-19 12:06:02 -03001856 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001857}
1858
1859static void pairing_complete_cb(struct hci_conn *conn, u8 status)
1860{
1861 struct pending_cmd *cmd;
1862
1863 BT_DBG("status %u", status);
1864
Johan Hedberg56e5cb82011-11-08 20:40:16 +02001865 cmd = find_pairing(conn);
1866 if (!cmd)
1867 BT_DBG("Unable to find a pending command");
1868 else
Johan Hedberge2113262012-02-18 15:20:03 +02001869 pairing_complete(cmd, mgmt_status(status));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001870}
1871
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001872static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
1873 u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001874{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001875 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02001876 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001877 struct pending_cmd *cmd;
1878 u8 sec_level, auth_type;
1879 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001880 int err;
1881
1882 BT_DBG("");
1883
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001884 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001885
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001886 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001887 err = cmd_status(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001888 MGMT_STATUS_NOT_POWERED);
1889 goto unlock;
1890 }
1891
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001892 sec_level = BT_SECURITY_MEDIUM;
1893 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001894 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001895 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03001896 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001897
Johan Hedbergba4e5642011-11-11 00:07:34 +02001898 if (cp->addr.type == MGMT_ADDR_BREDR)
1899 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr, sec_level,
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001900 auth_type);
1901 else
Johan Hedbergba4e5642011-11-11 00:07:34 +02001902 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr, sec_level,
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001903 auth_type);
1904
Johan Hedberg1425acb2011-11-11 00:07:35 +02001905 memset(&rp, 0, sizeof(rp));
1906 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1907 rp.addr.type = cp->addr.type;
1908
Ville Tervo30e76272011-02-22 16:10:53 -03001909 if (IS_ERR(conn)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001910 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Johan Hedberge2113262012-02-18 15:20:03 +02001911 MGMT_STATUS_CONNECT_FAILED,
1912 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001913 goto unlock;
1914 }
1915
1916 if (conn->connect_cfm_cb) {
1917 hci_conn_put(conn);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001918 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Johan Hedberge2113262012-02-18 15:20:03 +02001919 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001920 goto unlock;
1921 }
1922
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001923 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001924 if (!cmd) {
1925 err = -ENOMEM;
1926 hci_conn_put(conn);
1927 goto unlock;
1928 }
1929
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001930 /* For LE, just connecting isn't a proof that the pairing finished */
Johan Hedbergba4e5642011-11-11 00:07:34 +02001931 if (cp->addr.type == MGMT_ADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001932 conn->connect_cfm_cb = pairing_complete_cb;
1933
Johan Hedberge9a416b2011-02-19 12:05:56 -03001934 conn->security_cfm_cb = pairing_complete_cb;
1935 conn->disconn_cfm_cb = pairing_complete_cb;
1936 conn->io_capability = cp->io_cap;
1937 cmd->user_data = conn;
1938
1939 if (conn->state == BT_CONNECTED &&
1940 hci_conn_security(conn, sec_level, auth_type))
1941 pairing_complete(cmd, 0);
1942
1943 err = 0;
1944
1945unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001946 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001947 return err;
1948}
1949
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001950static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev,
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02001951 void *data, u16 len)
Johan Hedberg28424702012-02-02 04:02:29 +02001952{
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02001953 struct mgmt_addr_info *addr = data;
Johan Hedberg28424702012-02-02 04:02:29 +02001954 struct pending_cmd *cmd;
1955 struct hci_conn *conn;
1956 int err;
1957
1958 BT_DBG("");
1959
Johan Hedberg28424702012-02-02 04:02:29 +02001960 hci_dev_lock(hdev);
1961
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001962 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001963 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001964 MGMT_STATUS_NOT_POWERED);
1965 goto unlock;
1966 }
1967
Johan Hedberg28424702012-02-02 04:02:29 +02001968 cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
1969 if (!cmd) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001970 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Johan Hedberg28424702012-02-02 04:02:29 +02001971 MGMT_STATUS_INVALID_PARAMS);
1972 goto unlock;
1973 }
1974
1975 conn = cmd->user_data;
1976
1977 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001978 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Johan Hedberg28424702012-02-02 04:02:29 +02001979 MGMT_STATUS_INVALID_PARAMS);
1980 goto unlock;
1981 }
1982
1983 pairing_complete(cmd, MGMT_STATUS_CANCELLED);
1984
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001985 err = cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0,
1986 addr, sizeof(*addr));
Johan Hedberg28424702012-02-02 04:02:29 +02001987unlock:
1988 hci_dev_unlock(hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02001989 return err;
1990}
1991
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001992static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
1993 bdaddr_t *bdaddr, u8 type, u16 mgmt_op,
1994 u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03001995{
Johan Hedberga5c29682011-02-19 12:05:57 -03001996 struct pending_cmd *cmd;
Brian Gix0df4c182011-11-16 13:53:13 -08001997 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03001998 int err;
1999
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002000 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02002001
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002002 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002003 err = cmd_status(sk, hdev->id, mgmt_op,
2004 MGMT_STATUS_NOT_POWERED);
Brian Gix0df4c182011-11-16 13:53:13 -08002005 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002006 }
2007
Johan Hedberg272d90d2012-02-09 15:26:12 +02002008 if (type == MGMT_ADDR_BREDR)
2009 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, bdaddr);
2010 else
Brian Gix47c15e22011-11-16 13:53:14 -08002011 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, bdaddr);
Brian Gix47c15e22011-11-16 13:53:14 -08002012
Johan Hedberg272d90d2012-02-09 15:26:12 +02002013 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002014 err = cmd_status(sk, hdev->id, mgmt_op,
Johan Hedberg272d90d2012-02-09 15:26:12 +02002015 MGMT_STATUS_NOT_CONNECTED);
2016 goto done;
2017 }
2018
2019 if (type == MGMT_ADDR_LE_PUBLIC || type == MGMT_ADDR_LE_RANDOM) {
Brian Gix47c15e22011-11-16 13:53:14 -08002020 /* Continue with pairing via SMP */
Brian Gix5fe57d92011-12-21 16:12:13 -08002021 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix47c15e22011-11-16 13:53:14 -08002022
Brian Gix5fe57d92011-12-21 16:12:13 -08002023 if (!err)
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002024 err = cmd_status(sk, hdev->id, mgmt_op,
Brian Gix5fe57d92011-12-21 16:12:13 -08002025 MGMT_STATUS_SUCCESS);
2026 else
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002027 err = cmd_status(sk, hdev->id, mgmt_op,
Brian Gix5fe57d92011-12-21 16:12:13 -08002028 MGMT_STATUS_FAILED);
2029
Brian Gix47c15e22011-11-16 13:53:14 -08002030 goto done;
2031 }
2032
Brian Gix0df4c182011-11-16 13:53:13 -08002033 cmd = mgmt_pending_add(sk, mgmt_op, hdev, bdaddr, sizeof(*bdaddr));
Johan Hedberga5c29682011-02-19 12:05:57 -03002034 if (!cmd) {
2035 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08002036 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002037 }
2038
Brian Gix0df4c182011-11-16 13:53:13 -08002039 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08002040 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
2041 struct hci_cp_user_passkey_reply cp;
2042
2043 bacpy(&cp.bdaddr, bdaddr);
2044 cp.passkey = passkey;
2045 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
2046 } else
2047 err = hci_send_cmd(hdev, hci_op, sizeof(*bdaddr), bdaddr);
2048
Johan Hedberga664b5b2011-02-19 12:06:02 -03002049 if (err < 0)
2050 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002051
Brian Gix0df4c182011-11-16 13:53:13 -08002052done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002053 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002054 return err;
2055}
2056
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002057static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev,
2058 void *data, u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002059{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002060 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002061
2062 BT_DBG("");
2063
2064 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002065 return cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY,
Brian Gix0df4c182011-11-16 13:53:13 -08002066 MGMT_STATUS_INVALID_PARAMS);
2067
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002068 return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
Johan Hedberg272d90d2012-02-09 15:26:12 +02002069 MGMT_OP_USER_CONFIRM_REPLY,
2070 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002071}
2072
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002073static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev,
2074 void *data, u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002075{
Johan Hedbergc9c26592011-12-15 00:47:41 +02002076 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002077
2078 BT_DBG("");
2079
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002080 return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
Johan Hedberg272d90d2012-02-09 15:26:12 +02002081 MGMT_OP_USER_CONFIRM_NEG_REPLY,
2082 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002083}
2084
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002085static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev,
2086 void *data, u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002087{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002088 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002089
2090 BT_DBG("");
2091
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002092 return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
Johan Hedberg272d90d2012-02-09 15:26:12 +02002093 MGMT_OP_USER_PASSKEY_REPLY,
2094 HCI_OP_USER_PASSKEY_REPLY,
2095 cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08002096}
2097
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002098static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
2099 void *data, u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002100{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002101 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002102
2103 BT_DBG("");
2104
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002105 return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
Johan Hedberg272d90d2012-02-09 15:26:12 +02002106 MGMT_OP_USER_PASSKEY_NEG_REPLY,
2107 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08002108}
2109
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002110static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
Johan Hedbergb312b1612011-03-16 14:29:37 +02002111 u16 len)
2112{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002113 struct mgmt_cp_set_local_name *mgmt_cp = data;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002114 struct hci_cp_write_local_name hci_cp;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002115 struct pending_cmd *cmd;
2116 int err;
2117
2118 BT_DBG("");
2119
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002120 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002121
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002122 memcpy(hdev->short_name, mgmt_cp->short_name,
2123 sizeof(hdev->short_name));
2124
Johan Hedbergb5235a62012-02-21 14:32:24 +02002125 if (!hdev_is_powered(hdev)) {
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002126 memcpy(hdev->dev_name, mgmt_cp->name, sizeof(hdev->dev_name));
2127
2128 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
2129 data, len);
2130 if (err < 0)
2131 goto failed;
2132
2133 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data, len,
2134 sk);
2135
Johan Hedbergb5235a62012-02-21 14:32:24 +02002136 goto failed;
2137 }
2138
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002139 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002140 if (!cmd) {
2141 err = -ENOMEM;
2142 goto failed;
2143 }
2144
2145 memcpy(hci_cp.name, mgmt_cp->name, sizeof(hci_cp.name));
2146 err = hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(hci_cp),
2147 &hci_cp);
2148 if (err < 0)
2149 mgmt_pending_remove(cmd);
2150
2151failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002152 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002153 return err;
2154}
2155
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002156static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
2157 void *data, u16 data_len)
Szymon Jancc35938b2011-03-22 13:12:21 +01002158{
Szymon Jancc35938b2011-03-22 13:12:21 +01002159 struct pending_cmd *cmd;
2160 int err;
2161
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002162 BT_DBG("%s", hdev->name);
Szymon Jancc35938b2011-03-22 13:12:21 +01002163
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002164 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002165
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002166 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002167 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002168 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002169 goto unlock;
2170 }
2171
2172 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002173 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002174 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002175 goto unlock;
2176 }
2177
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002178 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002179 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002180 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01002181 goto unlock;
2182 }
2183
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002184 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01002185 if (!cmd) {
2186 err = -ENOMEM;
2187 goto unlock;
2188 }
2189
2190 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
2191 if (err < 0)
2192 mgmt_pending_remove(cmd);
2193
2194unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002195 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002196 return err;
2197}
2198
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002199static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
2200 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002201{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002202 struct mgmt_cp_add_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002203 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002204 int err;
2205
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002206 BT_DBG("%s ", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01002207
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002208 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002209
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002210 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002211 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA,
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002212 MGMT_STATUS_NOT_POWERED,
2213 &cp->addr, sizeof(cp->addr));
2214 goto unlock;
2215 }
2216
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002217 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, cp->hash,
Szymon Janc2763eda2011-03-22 13:12:22 +01002218 cp->randomizer);
2219 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002220 status = MGMT_STATUS_FAILED;
Szymon Janc2763eda2011-03-22 13:12:22 +01002221 else
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002222 status = 0;
2223
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002224 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA, status,
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002225 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002226
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002227unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002228 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002229 return err;
2230}
2231
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002232static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002233 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002234{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002235 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002236 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002237 int err;
2238
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002239 BT_DBG("%s", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01002240
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002241 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002242
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002243 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002244 err = cmd_complete(sk, hdev->id,
2245 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2246 MGMT_STATUS_NOT_POWERED,
2247 &cp->addr, sizeof(cp->addr));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002248 goto unlock;
2249 }
2250
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002251 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr);
Szymon Janc2763eda2011-03-22 13:12:22 +01002252 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002253 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01002254 else
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002255 status = 0;
2256
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002257 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2258 status, &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002259
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002260unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002261 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002262 return err;
2263}
2264
Andre Guedes5e0452c2012-02-17 20:39:38 -03002265int mgmt_interleaved_discovery(struct hci_dev *hdev)
2266{
2267 int err;
2268
2269 BT_DBG("%s", hdev->name);
2270
2271 hci_dev_lock(hdev);
2272
2273 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR_LE);
2274 if (err < 0)
2275 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2276
2277 hci_dev_unlock(hdev);
2278
2279 return err;
2280}
2281
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002282static int start_discovery(struct sock *sk, struct hci_dev *hdev,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002283 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002284{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002285 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002286 struct pending_cmd *cmd;
Johan Hedberg14a53662011-04-27 10:29:56 -04002287 int err;
2288
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002289 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04002290
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002291 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002292
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002293 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002294 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Johan Hedbergca69b792011-11-11 18:10:00 +02002295 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02002296 goto failed;
2297 }
2298
Johan Hedbergff9ef572012-01-04 14:23:45 +02002299 if (hdev->discovery.state != DISCOVERY_STOPPED) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002300 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2301 MGMT_STATUS_BUSY);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002302 goto failed;
2303 }
2304
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002305 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002306 if (!cmd) {
2307 err = -ENOMEM;
2308 goto failed;
2309 }
2310
Andre Guedes4aab14e2012-02-17 20:39:36 -03002311 hdev->discovery.type = cp->type;
2312
2313 switch (hdev->discovery.type) {
Andre Guedesf39799f2012-02-17 20:39:35 -03002314 case DISCOV_TYPE_BREDR:
Andre Guedes8b901292012-02-23 18:09:27 -03002315 if (lmp_bredr_capable(hdev))
2316 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
2317 else
2318 err = -ENOTSUPP;
Andre Guedesf39799f2012-02-17 20:39:35 -03002319 break;
2320
2321 case DISCOV_TYPE_LE:
Andre Guedes8b901292012-02-23 18:09:27 -03002322 if (lmp_host_le_capable(hdev))
2323 err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT,
Andre Guedes3fd24152012-02-03 17:48:01 -03002324 LE_SCAN_WIN, LE_SCAN_TIMEOUT_LE_ONLY);
Andre Guedes8b901292012-02-23 18:09:27 -03002325 else
2326 err = -ENOTSUPP;
Andre Guedesf39799f2012-02-17 20:39:35 -03002327 break;
2328
Andre Guedes5e0452c2012-02-17 20:39:38 -03002329 case DISCOV_TYPE_INTERLEAVED:
Andre Guedes426c1892012-02-24 11:41:04 -03002330 if (lmp_host_le_capable(hdev) && lmp_bredr_capable(hdev))
2331 err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT,
2332 LE_SCAN_WIN, LE_SCAN_TIMEOUT_BREDR_LE);
2333 else
2334 err = -ENOTSUPP;
Andre Guedes5e0452c2012-02-17 20:39:38 -03002335 break;
2336
Andre Guedesf39799f2012-02-17 20:39:35 -03002337 default:
Andre Guedes3fd24152012-02-03 17:48:01 -03002338 err = -EINVAL;
Andre Guedesf39799f2012-02-17 20:39:35 -03002339 }
Andre Guedes3fd24152012-02-03 17:48:01 -03002340
Johan Hedberg14a53662011-04-27 10:29:56 -04002341 if (err < 0)
2342 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002343 else
2344 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002345
2346failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002347 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002348 return err;
2349}
2350
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002351static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
2352 u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002353{
Johan Hedbergd9306502012-02-20 23:25:18 +02002354 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002355 struct pending_cmd *cmd;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002356 struct hci_cp_remote_name_req_cancel cp;
2357 struct inquiry_entry *e;
Johan Hedberg14a53662011-04-27 10:29:56 -04002358 int err;
2359
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002360 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04002361
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002362 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002363
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002364 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002365 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Johan Hedbergd9306502012-02-20 23:25:18 +02002366 MGMT_STATUS_REJECTED,
2367 &mgmt_cp->type, sizeof(mgmt_cp->type));
2368 goto unlock;
2369 }
2370
2371 if (hdev->discovery.type != mgmt_cp->type) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002372 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Johan Hedbergd9306502012-02-20 23:25:18 +02002373 MGMT_STATUS_INVALID_PARAMS,
2374 &mgmt_cp->type, sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002375 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02002376 }
2377
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002378 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002379 if (!cmd) {
2380 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002381 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04002382 }
2383
Andre Guedes343f9352012-02-17 20:39:37 -03002384 if (hdev->discovery.state == DISCOVERY_FINDING) {
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002385 err = hci_cancel_inquiry(hdev);
2386 if (err < 0)
2387 mgmt_pending_remove(cmd);
2388 else
2389 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
2390 goto unlock;
2391 }
2392
2393 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY, NAME_PENDING);
2394 if (!e) {
2395 mgmt_pending_remove(cmd);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002396 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY, 0,
Johan Hedbergd9306502012-02-20 23:25:18 +02002397 &mgmt_cp->type, sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002398 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2399 goto unlock;
2400 }
2401
2402 bacpy(&cp.bdaddr, &e->data.bdaddr);
2403 err = hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ_CANCEL,
2404 sizeof(cp), &cp);
Johan Hedberg14a53662011-04-27 10:29:56 -04002405 if (err < 0)
2406 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002407 else
2408 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002409
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002410unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002411 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002412 return err;
2413}
2414
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002415static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
2416 u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02002417{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002418 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002419 struct inquiry_entry *e;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002420 int err;
2421
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002422 BT_DBG("%s", hdev->name);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002423
Johan Hedberg561aafb2012-01-04 13:31:59 +02002424 hci_dev_lock(hdev);
2425
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002426 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002427 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002428 MGMT_STATUS_FAILED);
2429 goto failed;
2430 }
2431
Johan Hedberga198e7b2012-02-17 14:27:06 +02002432 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002433 if (!e) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002434 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
2435 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002436 goto failed;
2437 }
2438
2439 if (cp->name_known) {
2440 e->name_state = NAME_KNOWN;
2441 list_del(&e->list);
2442 } else {
2443 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e202012-01-09 00:53:02 +02002444 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002445 }
2446
2447 err = 0;
2448
2449failed:
2450 hci_dev_unlock(hdev);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002451 return err;
2452}
2453
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002454static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
2455 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002456{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002457 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002458 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03002459 int err;
2460
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002461 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03002462
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002463 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002464
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002465 err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002466 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002467 status = MGMT_STATUS_FAILED;
Antti Julku7fbec222011-06-15 12:01:15 +03002468 else
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002469 status = 0;
2470
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002471 err = cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status,
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002472 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03002473
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002474 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002475
2476 return err;
2477}
2478
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002479static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
2480 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002481{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002482 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002483 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03002484 int err;
2485
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002486 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03002487
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002488 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002489
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002490 err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002491 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002492 status = MGMT_STATUS_INVALID_PARAMS;
Antti Julku7fbec222011-06-15 12:01:15 +03002493 else
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002494 status = 0;
2495
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002496 err = cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status,
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002497 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03002498
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002499 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002500
2501 return err;
2502}
2503
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002504static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
2505 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03002506{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002507 struct mgmt_mode *cp = data;
Antti Julkuf6422ec2011-06-22 13:11:56 +03002508 struct hci_cp_write_page_scan_activity acp;
2509 u8 type;
2510 int err;
2511
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002512 BT_DBG("%s", hdev->name);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002513
Johan Hedberg5400c042012-02-21 16:40:33 +02002514 if (!hdev_is_powered(hdev))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002515 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedberg5400c042012-02-21 16:40:33 +02002516 MGMT_STATUS_NOT_POWERED);
2517
2518 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002519 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
2520 MGMT_STATUS_REJECTED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002521
2522 hci_dev_lock(hdev);
2523
Johan Hedbergf7c68692011-12-15 00:47:36 +02002524 if (cp->val) {
Antti Julkuf6422ec2011-06-22 13:11:56 +03002525 type = PAGE_SCAN_TYPE_INTERLACED;
2526 acp.interval = 0x0024; /* 22.5 msec page scan interval */
2527 } else {
2528 type = PAGE_SCAN_TYPE_STANDARD; /* default */
2529 acp.interval = 0x0800; /* default 1.28 sec page scan */
2530 }
2531
2532 acp.window = 0x0012; /* default 11.25 msec page scan window */
2533
2534 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
2535 sizeof(acp), &acp);
2536 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002537 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
2538 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002539 goto done;
2540 }
2541
2542 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
2543 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002544 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
2545 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002546 goto done;
2547 }
2548
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002549 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE, 0,
Johan Hedbergaee9b2182012-02-18 15:07:59 +02002550 NULL, 0);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002551done:
2552 hci_dev_unlock(hdev);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002553 return err;
2554}
2555
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002556static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002557 void *cp_data, u16 len)
2558{
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002559 struct mgmt_cp_load_long_term_keys *cp = cp_data;
2560 u16 key_count, expected_len;
2561 int i;
2562
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002563 key_count = get_unaligned_le16(&cp->key_count);
2564
2565 expected_len = sizeof(*cp) + key_count *
2566 sizeof(struct mgmt_ltk_info);
2567 if (expected_len != len) {
2568 BT_ERR("load_keys: expected %u bytes, got %u bytes",
2569 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002570 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002571 EINVAL);
2572 }
2573
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002574 BT_DBG("%s key_count %u", hdev->name, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002575
2576 hci_dev_lock(hdev);
2577
2578 hci_smp_ltks_clear(hdev);
2579
2580 for (i = 0; i < key_count; i++) {
2581 struct mgmt_ltk_info *key = &cp->keys[i];
2582 u8 type;
2583
2584 if (key->master)
2585 type = HCI_SMP_LTK;
2586 else
2587 type = HCI_SMP_LTK_SLAVE;
2588
2589 hci_add_ltk(hdev, &key->addr.bdaddr, key->addr.type,
2590 type, 0, key->authenticated, key->val,
2591 key->enc_size, key->ediv, key->rand);
2592 }
2593
2594 hci_dev_unlock(hdev);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002595
2596 return 0;
2597}
2598
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002599struct mgmt_handler {
2600 int (*func) (struct sock *sk, struct hci_dev *hdev,
2601 void *data, u16 data_len);
Johan Hedbergbe22b542012-03-01 22:24:41 +02002602 bool var_len;
2603 size_t data_len;
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002604} mgmt_handlers[] = {
2605 { NULL }, /* 0x0000 (no command) */
Johan Hedbergbe22b542012-03-01 22:24:41 +02002606 { read_version, false, MGMT_READ_VERSION_SIZE },
2607 { read_commands, false, MGMT_READ_COMMANDS_SIZE },
2608 { read_index_list, false, MGMT_READ_INDEX_LIST_SIZE },
2609 { read_controller_info, false, MGMT_READ_INFO_SIZE },
2610 { set_powered, false, MGMT_SETTING_SIZE },
2611 { set_discoverable, false, MGMT_SET_DISCOVERABLE_SIZE },
2612 { set_connectable, false, MGMT_SETTING_SIZE },
2613 { set_fast_connectable, false, MGMT_SETTING_SIZE },
2614 { set_pairable, false, MGMT_SETTING_SIZE },
2615 { set_link_security, false, MGMT_SETTING_SIZE },
2616 { set_ssp, false, MGMT_SETTING_SIZE },
2617 { set_hs, false, MGMT_SETTING_SIZE },
2618 { set_le, false, MGMT_SETTING_SIZE },
2619 { set_dev_class, false, MGMT_SET_DEV_CLASS_SIZE },
2620 { set_local_name, false, MGMT_SET_LOCAL_NAME_SIZE },
2621 { add_uuid, false, MGMT_ADD_UUID_SIZE },
2622 { remove_uuid, false, MGMT_REMOVE_UUID_SIZE },
2623 { load_link_keys, true, MGMT_LOAD_LINK_KEYS_SIZE },
2624 { load_long_term_keys, true, MGMT_LOAD_LONG_TERM_KEYS_SIZE },
2625 { disconnect, false, MGMT_DISCONNECT_SIZE },
2626 { get_connections, false, MGMT_GET_CONNECTIONS_SIZE },
2627 { pin_code_reply, false, MGMT_PIN_CODE_REPLY_SIZE },
2628 { pin_code_neg_reply, false, MGMT_PIN_CODE_NEG_REPLY_SIZE },
2629 { set_io_capability, false, MGMT_SET_IO_CAPABILITY_SIZE },
2630 { pair_device, false, MGMT_PAIR_DEVICE_SIZE },
2631 { cancel_pair_device, false, MGMT_CANCEL_PAIR_DEVICE_SIZE },
2632 { unpair_device, false, MGMT_UNPAIR_DEVICE_SIZE },
2633 { user_confirm_reply, false, MGMT_USER_CONFIRM_REPLY_SIZE },
2634 { user_confirm_neg_reply, false, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
2635 { user_passkey_reply, false, MGMT_USER_PASSKEY_REPLY_SIZE },
2636 { user_passkey_neg_reply, false, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
2637 { read_local_oob_data, false, MGMT_READ_LOCAL_OOB_DATA_SIZE },
2638 { add_remote_oob_data, false, MGMT_ADD_REMOTE_OOB_DATA_SIZE },
2639 { remove_remote_oob_data, false, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
2640 { start_discovery, false, MGMT_START_DISCOVERY_SIZE },
2641 { stop_discovery, false, MGMT_STOP_DISCOVERY_SIZE },
2642 { confirm_name, false, MGMT_CONFIRM_NAME_SIZE },
2643 { block_device, false, MGMT_BLOCK_DEVICE_SIZE },
2644 { unblock_device, false, MGMT_UNBLOCK_DEVICE_SIZE },
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002645};
2646
2647
Johan Hedberg03811012010-12-08 00:21:06 +02002648int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
2649{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002650 void *buf;
2651 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02002652 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002653 u16 opcode, index, len;
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002654 struct hci_dev *hdev = NULL;
Johan Hedbergbe22b542012-03-01 22:24:41 +02002655 struct mgmt_handler *handler;
Johan Hedberg03811012010-12-08 00:21:06 +02002656 int err;
2657
2658 BT_DBG("got %zu bytes", msglen);
2659
2660 if (msglen < sizeof(*hdr))
2661 return -EINVAL;
2662
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03002663 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02002664 if (!buf)
2665 return -ENOMEM;
2666
2667 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
2668 err = -EFAULT;
2669 goto done;
2670 }
2671
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002672 hdr = buf;
Johan Hedberg03811012010-12-08 00:21:06 +02002673 opcode = get_unaligned_le16(&hdr->opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002674 index = get_unaligned_le16(&hdr->index);
Johan Hedberg03811012010-12-08 00:21:06 +02002675 len = get_unaligned_le16(&hdr->len);
2676
2677 if (len != msglen - sizeof(*hdr)) {
2678 err = -EINVAL;
2679 goto done;
2680 }
2681
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002682 if (index != MGMT_INDEX_NONE) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002683 hdev = hci_dev_get(index);
2684 if (!hdev) {
2685 err = cmd_status(sk, index, opcode,
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002686 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002687 goto done;
2688 }
2689 }
2690
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002691 if (opcode >= ARRAY_SIZE(mgmt_handlers) ||
2692 mgmt_handlers[opcode].func == NULL) {
Johan Hedberg03811012010-12-08 00:21:06 +02002693 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02002694 err = cmd_status(sk, index, opcode,
2695 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002696 goto done;
Johan Hedberg03811012010-12-08 00:21:06 +02002697 }
2698
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002699 if ((hdev && opcode < MGMT_OP_READ_INFO) ||
2700 (!hdev && opcode >= MGMT_OP_READ_INFO)) {
2701 err = cmd_status(sk, index, opcode,
2702 MGMT_STATUS_INVALID_PARAMS);
2703 goto done;
2704 }
2705
Johan Hedbergbe22b542012-03-01 22:24:41 +02002706 handler = &mgmt_handlers[opcode];
2707
2708 if ((handler->var_len && len < handler->data_len) ||
2709 (!handler->var_len && len != handler->data_len)) {
2710 err = cmd_status(sk, index, opcode,
2711 MGMT_STATUS_INVALID_PARAMS);
2712 goto done;
2713 }
2714
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002715 if (hdev)
2716 mgmt_init_hdev(sk, hdev);
2717
2718 cp = buf + sizeof(*hdr);
2719
Johan Hedbergbe22b542012-03-01 22:24:41 +02002720 err = handler->func(sk, hdev, cp, len);
Johan Hedberge41d8b42010-12-13 21:07:03 +02002721 if (err < 0)
2722 goto done;
2723
Johan Hedberg03811012010-12-08 00:21:06 +02002724 err = msglen;
2725
2726done:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002727 if (hdev)
2728 hci_dev_put(hdev);
2729
Johan Hedberg03811012010-12-08 00:21:06 +02002730 kfree(buf);
2731 return err;
2732}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002733
Johan Hedbergb24752f2011-11-03 14:40:33 +02002734static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
2735{
2736 u8 *status = data;
2737
2738 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
2739 mgmt_pending_remove(cmd);
2740}
2741
Johan Hedberg744cf192011-11-08 20:40:14 +02002742int mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002743{
Johan Hedberg744cf192011-11-08 20:40:14 +02002744 return mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002745}
2746
Johan Hedberg744cf192011-11-08 20:40:14 +02002747int mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002748{
Johan Hedbergb24752f2011-11-03 14:40:33 +02002749 u8 status = ENODEV;
2750
Johan Hedberg744cf192011-11-08 20:40:14 +02002751 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002752
Johan Hedberg744cf192011-11-08 20:40:14 +02002753 return mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002754}
2755
Johan Hedberg73f22f62010-12-29 16:00:25 +02002756struct cmd_lookup {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002757 struct sock *sk;
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002758 struct hci_dev *hdev;
Johan Hedberg90e70452012-02-23 23:09:40 +02002759 u8 mgmt_status;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002760};
2761
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002762static void settings_rsp(struct pending_cmd *cmd, void *data)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002763{
Johan Hedberg73f22f62010-12-29 16:00:25 +02002764 struct cmd_lookup *match = data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002765
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002766 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002767
2768 list_del(&cmd->list);
2769
2770 if (match->sk == NULL) {
2771 match->sk = cmd->sk;
2772 sock_hold(match->sk);
2773 }
2774
2775 mgmt_pending_free(cmd);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002776}
Johan Hedberg5add6af2010-12-16 10:00:37 +02002777
Johan Hedberg744cf192011-11-08 20:40:14 +02002778int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg5add6af2010-12-16 10:00:37 +02002779{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002780 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002781 int err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002782
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002783 if (!test_bit(HCI_MGMT, &hdev->dev_flags))
2784 return 0;
2785
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002786 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
Johan Hedberg5add6af2010-12-16 10:00:37 +02002787
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002788 if (powered) {
2789 u8 scan = 0;
2790
2791 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
2792 scan |= SCAN_PAGE;
2793 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
2794 scan |= SCAN_INQUIRY;
2795
2796 if (scan)
2797 hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
Johan Hedberg504c8dc2012-02-23 13:30:41 +02002798
2799 update_class(hdev);
2800 update_eir(hdev);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002801 } else {
Johan Hedbergb24752f2011-11-03 14:40:33 +02002802 u8 status = ENETDOWN;
Johan Hedberg744cf192011-11-08 20:40:14 +02002803 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002804 }
2805
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02002806 err = new_settings(hdev, match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002807
2808 if (match.sk)
2809 sock_put(match.sk);
2810
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002811 return err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002812}
Johan Hedberg73f22f62010-12-29 16:00:25 +02002813
Johan Hedberg744cf192011-11-08 20:40:14 +02002814int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg73f22f62010-12-29 16:00:25 +02002815{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002816 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002817 bool changed = false;
2818 int err = 0;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002819
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002820 if (discoverable) {
2821 if (!test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
2822 changed = true;
2823 } else {
2824 if (test_and_clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
2825 changed = true;
2826 }
Johan Hedberg73f22f62010-12-29 16:00:25 +02002827
Johan Hedberged9b5f22012-02-21 20:47:06 +02002828 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp,
2829 &match);
2830
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02002831 if (changed)
2832 err = new_settings(hdev, match.sk);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002833
Johan Hedberg73f22f62010-12-29 16:00:25 +02002834 if (match.sk)
2835 sock_put(match.sk);
2836
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002837 return err;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002838}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002839
Johan Hedberg744cf192011-11-08 20:40:14 +02002840int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002841{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002842 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002843 bool changed = false;
2844 int err = 0;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002845
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002846 if (connectable) {
2847 if (!test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags))
2848 changed = true;
2849 } else {
2850 if (test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags))
2851 changed = true;
2852 }
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002853
Johan Hedberged9b5f22012-02-21 20:47:06 +02002854 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev, settings_rsp,
2855 &match);
2856
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02002857 if (changed)
2858 err = new_settings(hdev, match.sk);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002859
2860 if (match.sk)
2861 sock_put(match.sk);
2862
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002863 return err;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002864}
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002865
Johan Hedberg744cf192011-11-08 20:40:14 +02002866int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002867{
Johan Hedbergca69b792011-11-11 18:10:00 +02002868 u8 mgmt_err = mgmt_status(status);
2869
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002870 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02002871 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Johan Hedbergca69b792011-11-11 18:10:00 +02002872 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002873
2874 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02002875 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Johan Hedbergca69b792011-11-11 18:10:00 +02002876 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002877
2878 return 0;
2879}
2880
Johan Hedberg744cf192011-11-08 20:40:14 +02002881int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
2882 u8 persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002883{
Johan Hedberg86742e12011-11-07 23:13:38 +02002884 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002885
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002886 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002887
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002888 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02002889 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
2890 ev.key.addr.type = MGMT_ADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002891 ev.key.type = key->type;
2892 memcpy(ev.key.val, key->val, 16);
2893 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002894
Johan Hedberg744cf192011-11-08 20:40:14 +02002895 return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002896}
Johan Hedbergf7520542011-01-20 12:34:39 +02002897
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002898int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
2899{
2900 struct mgmt_ev_new_long_term_key ev;
2901
2902 memset(&ev, 0, sizeof(ev));
2903
2904 ev.store_hint = persistent;
2905 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
2906 ev.key.addr.type = key->bdaddr_type;
2907 ev.key.authenticated = key->authenticated;
2908 ev.key.enc_size = key->enc_size;
2909 ev.key.ediv = key->ediv;
2910
2911 if (key->type == HCI_SMP_LTK)
2912 ev.key.master = 1;
2913
2914 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
2915 memcpy(ev.key.val, key->val, sizeof(key->val));
2916
2917 return mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev,
2918 &ev, sizeof(ev), NULL);
2919}
2920
Johan Hedbergafc747a2012-01-15 18:11:07 +02002921int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Johan Hedberg08c79b62012-02-23 22:31:51 +02002922 u8 addr_type, u32 flags, u8 *name,
2923 u8 name_len, u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02002924{
Johan Hedbergb644ba32012-01-17 21:48:47 +02002925 char buf[512];
2926 struct mgmt_ev_device_connected *ev = (void *) buf;
2927 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02002928
Johan Hedbergb644ba32012-01-17 21:48:47 +02002929 bacpy(&ev->addr.bdaddr, bdaddr);
2930 ev->addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02002931
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02002932 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02002933
Johan Hedbergb644ba32012-01-17 21:48:47 +02002934 if (name_len > 0)
2935 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
2936 name, name_len);
2937
2938 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
2939 eir_len = eir_append_data(&ev->eir[eir_len], eir_len,
2940 EIR_CLASS_OF_DEV, dev_class, 3);
2941
2942 put_unaligned_le16(eir_len, &ev->eir_len);
2943
2944 return mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
2945 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02002946}
2947
Johan Hedberg8962ee72011-01-20 12:40:27 +02002948static void disconnect_rsp(struct pending_cmd *cmd, void *data)
2949{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01002950 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002951 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02002952 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002953
Johan Hedberg88c3df12012-02-09 14:27:38 +02002954 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2955 rp.addr.type = cp->addr.type;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002956
Johan Hedbergaee9b2182012-02-18 15:07:59 +02002957 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, 0, &rp,
2958 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002959
2960 *sk = cmd->sk;
2961 sock_hold(*sk);
2962
Johan Hedberga664b5b2011-02-19 12:06:02 -03002963 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002964}
2965
Johan Hedberg124f6e32012-02-09 13:50:12 +02002966static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02002967{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002968 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02002969 struct mgmt_cp_unpair_device *cp = cmd->param;
2970 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002971
2972 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02002973 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2974 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002975
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002976 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
2977
Johan Hedbergaee9b2182012-02-18 15:07:59 +02002978 cmd_complete(cmd->sk, cmd->index, cmd->opcode, 0, &rp, sizeof(rp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02002979
2980 mgmt_pending_remove(cmd);
2981}
2982
Johan Hedbergafc747a2012-01-15 18:11:07 +02002983int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
2984 u8 link_type, u8 addr_type)
Johan Hedbergf7520542011-01-20 12:34:39 +02002985{
Johan Hedberg4c659c32011-11-07 23:13:39 +02002986 struct mgmt_addr_info ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002987 struct sock *sk = NULL;
2988 int err;
2989
Johan Hedberg744cf192011-11-08 20:40:14 +02002990 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02002991
Johan Hedbergf7520542011-01-20 12:34:39 +02002992 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02002993 ev.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02002994
Johan Hedbergafc747a2012-01-15 18:11:07 +02002995 err = mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev),
2996 sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002997
2998 if (sk)
2999 sock_put(sk);
3000
Johan Hedberg124f6e32012-02-09 13:50:12 +02003001 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003002 hdev);
Johan Hedberga8a1d192011-11-10 15:54:38 +02003003
Johan Hedberg8962ee72011-01-20 12:40:27 +02003004 return err;
3005}
3006
Johan Hedberg88c3df12012-02-09 14:27:38 +02003007int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
3008 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02003009{
Johan Hedberg88c3df12012-02-09 14:27:38 +02003010 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003011 struct pending_cmd *cmd;
3012 int err;
3013
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003014 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003015 if (!cmd)
3016 return -ENOENT;
3017
Johan Hedberg88c3df12012-02-09 14:27:38 +02003018 bacpy(&rp.addr.bdaddr, bdaddr);
3019 rp.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02003020
Johan Hedberg88c3df12012-02-09 14:27:38 +02003021 err = cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003022 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003023
Johan Hedberga664b5b2011-02-19 12:06:02 -03003024 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003025
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003026 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
3027 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003028 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02003029}
Johan Hedberg17d5c042011-01-22 06:09:08 +02003030
Johan Hedberg48264f02011-11-09 13:58:58 +02003031int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
3032 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02003033{
3034 struct mgmt_ev_connect_failed ev;
3035
Johan Hedberg4c659c32011-11-07 23:13:39 +02003036 bacpy(&ev.addr.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02003037 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003038 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003039
Johan Hedberg744cf192011-11-08 20:40:14 +02003040 return mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003041}
Johan Hedberg980e1a52011-01-22 06:10:07 +02003042
Johan Hedberg744cf192011-11-08 20:40:14 +02003043int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003044{
3045 struct mgmt_ev_pin_code_request ev;
3046
Johan Hedbergd8457692012-02-17 14:24:57 +02003047 bacpy(&ev.addr.bdaddr, bdaddr);
3048 ev.addr.type = MGMT_ADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02003049 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003050
Johan Hedberg744cf192011-11-08 20:40:14 +02003051 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01003052 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003053}
3054
Johan Hedberg744cf192011-11-08 20:40:14 +02003055int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3056 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003057{
3058 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003059 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003060 int err;
3061
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003062 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003063 if (!cmd)
3064 return -ENOENT;
3065
Johan Hedbergd8457692012-02-17 14:24:57 +02003066 bacpy(&rp.addr.bdaddr, bdaddr);
3067 rp.addr.type = MGMT_ADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003068
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003069 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
3070 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003071
Johan Hedberga664b5b2011-02-19 12:06:02 -03003072 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003073
3074 return err;
3075}
3076
Johan Hedberg744cf192011-11-08 20:40:14 +02003077int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3078 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003079{
3080 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003081 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003082 int err;
3083
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003084 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003085 if (!cmd)
3086 return -ENOENT;
3087
Johan Hedbergd8457692012-02-17 14:24:57 +02003088 bacpy(&rp.addr.bdaddr, bdaddr);
3089 rp.addr.type = MGMT_ADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003090
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003091 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
3092 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003093
Johan Hedberga664b5b2011-02-19 12:06:02 -03003094 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003095
3096 return err;
3097}
Johan Hedberga5c29682011-02-19 12:05:57 -03003098
Johan Hedberg744cf192011-11-08 20:40:14 +02003099int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003100 u8 link_type, u8 addr_type, __le32 value,
3101 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03003102{
3103 struct mgmt_ev_user_confirm_request ev;
3104
Johan Hedberg744cf192011-11-08 20:40:14 +02003105 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03003106
Johan Hedberg272d90d2012-02-09 15:26:12 +02003107 bacpy(&ev.addr.bdaddr, bdaddr);
3108 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07003109 ev.confirm_hint = confirm_hint;
Johan Hedberga5c29682011-02-19 12:05:57 -03003110 put_unaligned_le32(value, &ev.value);
3111
Johan Hedberg744cf192011-11-08 20:40:14 +02003112 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01003113 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03003114}
3115
Johan Hedberg272d90d2012-02-09 15:26:12 +02003116int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
3117 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08003118{
3119 struct mgmt_ev_user_passkey_request ev;
3120
3121 BT_DBG("%s", hdev->name);
3122
Johan Hedberg272d90d2012-02-09 15:26:12 +02003123 bacpy(&ev.addr.bdaddr, bdaddr);
3124 ev.addr.type = link_to_mgmt(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08003125
3126 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
3127 NULL);
3128}
3129
Brian Gix0df4c182011-11-16 13:53:13 -08003130static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003131 u8 link_type, u8 addr_type, u8 status,
3132 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03003133{
3134 struct pending_cmd *cmd;
3135 struct mgmt_rp_user_confirm_reply rp;
3136 int err;
3137
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003138 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03003139 if (!cmd)
3140 return -ENOENT;
3141
Johan Hedberg272d90d2012-02-09 15:26:12 +02003142 bacpy(&rp.addr.bdaddr, bdaddr);
3143 rp.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003144 err = cmd_complete(cmd->sk, hdev->id, opcode, mgmt_status(status),
3145 &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03003146
Johan Hedberga664b5b2011-02-19 12:06:02 -03003147 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03003148
3149 return err;
3150}
3151
Johan Hedberg744cf192011-11-08 20:40:14 +02003152int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003153 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003154{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003155 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3156 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003157}
3158
Johan Hedberg272d90d2012-02-09 15:26:12 +02003159int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3160 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003161{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003162 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3163 status, MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003164}
Johan Hedberg2a611692011-02-19 12:06:00 -03003165
Brian Gix604086b2011-11-23 08:28:33 -08003166int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003167 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003168{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003169 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3170 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003171}
3172
Johan Hedberg272d90d2012-02-09 15:26:12 +02003173int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3174 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003175{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003176 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3177 status, MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003178}
3179
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003180int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
3181 u8 addr_type, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03003182{
3183 struct mgmt_ev_auth_failed ev;
3184
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003185 bacpy(&ev.addr.bdaddr, bdaddr);
3186 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003187 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03003188
Johan Hedberg744cf192011-11-08 20:40:14 +02003189 return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03003190}
Johan Hedbergb312b1612011-03-16 14:29:37 +02003191
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003192int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
3193{
3194 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg47990ea2012-02-22 11:58:37 +02003195 bool changed = false;
3196 int err = 0;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003197
3198 if (status) {
3199 u8 mgmt_err = mgmt_status(status);
3200 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
3201 cmd_status_rsp, &mgmt_err);
3202 return 0;
3203 }
3204
Johan Hedberg47990ea2012-02-22 11:58:37 +02003205 if (test_bit(HCI_AUTH, &hdev->flags)) {
3206 if (!test_and_set_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
3207 changed = true;
3208 } else {
3209 if (test_and_clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
3210 changed = true;
3211 }
3212
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003213 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
3214 &match);
3215
Johan Hedberg47990ea2012-02-22 11:58:37 +02003216 if (changed)
3217 err = new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003218
3219 if (match.sk)
3220 sock_put(match.sk);
3221
3222 return err;
3223}
3224
Johan Hedbergcacaf522012-02-21 00:52:42 +02003225static int clear_eir(struct hci_dev *hdev)
3226{
3227 struct hci_cp_write_eir cp;
3228
3229 if (!(hdev->features[6] & LMP_EXT_INQ))
3230 return 0;
3231
Johan Hedbergc80da272012-02-22 15:38:48 +02003232 memset(hdev->eir, 0, sizeof(hdev->eir));
3233
Johan Hedbergcacaf522012-02-21 00:52:42 +02003234 memset(&cp, 0, sizeof(cp));
3235
3236 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
3237}
3238
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003239int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003240{
3241 struct cmd_lookup match = { NULL, hdev };
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003242 bool changed = false;
3243 int err = 0;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003244
3245 if (status) {
3246 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003247
3248 if (enable && test_and_clear_bit(HCI_SSP_ENABLED,
3249 &hdev->dev_flags))
3250 err = new_settings(hdev, NULL);
3251
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003252 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev,
3253 cmd_status_rsp, &mgmt_err);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003254
3255 return err;
3256 }
3257
3258 if (enable) {
3259 if (!test_and_set_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3260 changed = true;
3261 } else {
3262 if (test_and_clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3263 changed = true;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003264 }
3265
3266 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
3267
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003268 if (changed)
3269 err = new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003270
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02003271 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003272 sock_put(match.sk);
3273
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02003274 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3275 update_eir(hdev);
3276 else
3277 clear_eir(hdev);
Johan Hedbergcacaf522012-02-21 00:52:42 +02003278
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003279 return err;
3280}
3281
Johan Hedberg90e70452012-02-23 23:09:40 +02003282static void class_rsp(struct pending_cmd *cmd, void *data)
3283{
3284 struct cmd_lookup *match = data;
3285
3286 cmd_complete(cmd->sk, cmd->index, cmd->opcode, match->mgmt_status,
3287 match->hdev->dev_class, 3);
3288
3289 list_del(&cmd->list);
3290
3291 if (match->sk == NULL) {
3292 match->sk = cmd->sk;
3293 sock_hold(match->sk);
3294 }
3295
3296 mgmt_pending_free(cmd);
3297}
3298
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003299int mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
3300 u8 status)
3301{
Johan Hedberg90e70452012-02-23 23:09:40 +02003302 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
3303 int err = 0;
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003304
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02003305 clear_bit(HCI_PENDING_CLASS, &hdev->dev_flags);
3306
Johan Hedberg90e70452012-02-23 23:09:40 +02003307 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, class_rsp, &match);
3308 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, class_rsp, &match);
3309 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, class_rsp, &match);
3310
3311 if (!status)
3312 err = mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
3313 dev_class, 3, NULL);
3314
3315 if (match.sk)
3316 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003317
3318 return err;
3319}
3320
Johan Hedberg744cf192011-11-08 20:40:14 +02003321int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02003322{
3323 struct pending_cmd *cmd;
3324 struct mgmt_cp_set_local_name ev;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003325 bool changed = false;
3326 int err = 0;
3327
3328 if (memcmp(name, hdev->dev_name, sizeof(hdev->dev_name)) != 0) {
3329 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
3330 changed = true;
3331 }
Johan Hedbergb312b1612011-03-16 14:29:37 +02003332
3333 memset(&ev, 0, sizeof(ev));
3334 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003335 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003336
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003337 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003338 if (!cmd)
3339 goto send_event;
3340
Johan Hedberg7bdaae42012-02-22 21:39:58 +02003341 /* Always assume that either the short or the complete name has
3342 * changed if there was a pending mgmt command */
3343 changed = true;
3344
Johan Hedbergb312b1612011-03-16 14:29:37 +02003345 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02003346 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
Johan Hedbergca69b792011-11-11 18:10:00 +02003347 mgmt_status(status));
Johan Hedbergb312b1612011-03-16 14:29:37 +02003348 goto failed;
3349 }
3350
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003351 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0, &ev,
Johan Hedbergb312b1612011-03-16 14:29:37 +02003352 sizeof(ev));
3353 if (err < 0)
3354 goto failed;
3355
3356send_event:
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003357 if (changed)
3358 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev,
3359 sizeof(ev), cmd ? cmd->sk : NULL);
3360
Johan Hedbergf51d5b22012-02-22 18:17:32 +02003361 update_eir(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003362
3363failed:
3364 if (cmd)
3365 mgmt_pending_remove(cmd);
3366 return err;
3367}
Szymon Jancc35938b2011-03-22 13:12:21 +01003368
Johan Hedberg744cf192011-11-08 20:40:14 +02003369int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
3370 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01003371{
3372 struct pending_cmd *cmd;
3373 int err;
3374
Johan Hedberg744cf192011-11-08 20:40:14 +02003375 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01003376
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003377 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003378 if (!cmd)
3379 return -ENOENT;
3380
3381 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02003382 err = cmd_status(cmd->sk, hdev->id,
Johan Hedbergca69b792011-11-11 18:10:00 +02003383 MGMT_OP_READ_LOCAL_OOB_DATA,
3384 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01003385 } else {
3386 struct mgmt_rp_read_local_oob_data rp;
3387
3388 memcpy(rp.hash, hash, sizeof(rp.hash));
3389 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
3390
Johan Hedberg744cf192011-11-08 20:40:14 +02003391 err = cmd_complete(cmd->sk, hdev->id,
3392 MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003393 0, &rp, sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01003394 }
3395
3396 mgmt_pending_remove(cmd);
3397
3398 return err;
3399}
Johan Hedberge17acd42011-03-30 23:57:16 +03003400
Johan Hedberg06199cf2012-02-22 16:37:11 +02003401int mgmt_le_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
3402{
3403 struct cmd_lookup match = { NULL, hdev };
3404 bool changed = false;
3405 int err = 0;
3406
3407 if (status) {
3408 u8 mgmt_err = mgmt_status(status);
3409
3410 if (enable && test_and_clear_bit(HCI_LE_ENABLED,
3411 &hdev->dev_flags))
3412 err = new_settings(hdev, NULL);
3413
3414 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev,
3415 cmd_status_rsp, &mgmt_err);
3416
3417 return err;
3418 }
3419
3420 if (enable) {
3421 if (!test_and_set_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3422 changed = true;
3423 } else {
3424 if (test_and_clear_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3425 changed = true;
3426 }
3427
3428 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
3429
3430 if (changed)
3431 err = new_settings(hdev, match.sk);
3432
3433 if (match.sk)
3434 sock_put(match.sk);
3435
3436 return err;
3437}
3438
Johan Hedberg48264f02011-11-09 13:58:58 +02003439int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Johan Hedberg561aafb2012-01-04 13:31:59 +02003440 u8 addr_type, u8 *dev_class, s8 rssi,
Johan Hedberg388fc8f2012-02-23 00:38:59 +02003441 u8 cfm_name, u8 ssp, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03003442{
Johan Hedberge319d2e2012-01-15 19:51:59 +02003443 char buf[512];
3444 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02003445 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03003446
Johan Hedberg1dc06092012-01-15 21:01:23 +02003447 /* Leave 5 bytes for a potential CoD field */
3448 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Andre Guedes7d262f82012-01-10 18:20:49 -03003449 return -EINVAL;
3450
Johan Hedberg1dc06092012-01-15 21:01:23 +02003451 memset(buf, 0, sizeof(buf));
3452
Johan Hedberge319d2e2012-01-15 19:51:59 +02003453 bacpy(&ev->addr.bdaddr, bdaddr);
3454 ev->addr.type = link_to_mgmt(link_type, addr_type);
3455 ev->rssi = rssi;
Johan Hedberg9a395a82012-02-23 00:00:32 +02003456 if (cfm_name)
3457 ev->flags[0] |= MGMT_DEV_FOUND_CONFIRM_NAME;
Johan Hedberg388fc8f2012-02-23 00:38:59 +02003458 if (!ssp)
3459 ev->flags[0] |= MGMT_DEV_FOUND_LEGACY_PAIRING;
Johan Hedberge17acd42011-03-30 23:57:16 +03003460
Johan Hedberg1dc06092012-01-15 21:01:23 +02003461 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02003462 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03003463
Johan Hedberg1dc06092012-01-15 21:01:23 +02003464 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
3465 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
3466 dev_class, 3);
3467
3468 put_unaligned_le16(eir_len, &ev->eir_len);
3469
3470 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03003471
Johan Hedberge319d2e2012-01-15 19:51:59 +02003472 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03003473}
Johan Hedberga88a9652011-03-30 13:18:12 +03003474
Johan Hedbergb644ba32012-01-17 21:48:47 +02003475int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
3476 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03003477{
Johan Hedbergb644ba32012-01-17 21:48:47 +02003478 struct mgmt_ev_device_found *ev;
3479 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
3480 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03003481
Johan Hedbergb644ba32012-01-17 21:48:47 +02003482 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03003483
Johan Hedbergb644ba32012-01-17 21:48:47 +02003484 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03003485
Johan Hedbergb644ba32012-01-17 21:48:47 +02003486 bacpy(&ev->addr.bdaddr, bdaddr);
3487 ev->addr.type = link_to_mgmt(link_type, addr_type);
3488 ev->rssi = rssi;
3489
3490 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
3491 name_len);
3492
3493 put_unaligned_le16(eir_len, &ev->eir_len);
3494
Johan Hedberg053c7e02012-02-04 00:06:00 +02003495 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev,
3496 sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03003497}
Johan Hedberg314b2382011-04-27 10:29:57 -04003498
Andre Guedes7a135102011-11-09 17:14:25 -03003499int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
Johan Hedberg164a6e72011-11-01 17:06:44 +02003500{
3501 struct pending_cmd *cmd;
Johan Hedbergf808e162012-02-19 12:52:07 +02003502 u8 type;
Johan Hedberg164a6e72011-11-01 17:06:44 +02003503 int err;
3504
Andre Guedes203159d2012-02-13 15:41:01 -03003505 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3506
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003507 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003508 if (!cmd)
3509 return -ENOENT;
3510
Johan Hedbergf808e162012-02-19 12:52:07 +02003511 type = hdev->discovery.type;
3512
3513 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
3514 &type, sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02003515 mgmt_pending_remove(cmd);
3516
3517 return err;
3518}
3519
Andre Guedese6d465c2011-11-09 17:14:26 -03003520int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
3521{
3522 struct pending_cmd *cmd;
3523 int err;
3524
3525 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
3526 if (!cmd)
3527 return -ENOENT;
3528
Johan Hedbergd9306502012-02-20 23:25:18 +02003529 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
3530 &hdev->discovery.type,
3531 sizeof(hdev->discovery.type));
Johan Hedberg03811012010-12-08 00:21:06 +02003532 mgmt_pending_remove(cmd);
3533
3534 return err;
3535}
Johan Hedberg314b2382011-04-27 10:29:57 -04003536
Johan Hedberg744cf192011-11-08 20:40:14 +02003537int mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04003538{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02003539 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02003540 struct pending_cmd *cmd;
3541
Andre Guedes343fb142011-11-22 17:14:19 -03003542 BT_DBG("%s discovering %u", hdev->name, discovering);
3543
Johan Hedberg164a6e72011-11-01 17:06:44 +02003544 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003545 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003546 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003547 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003548
3549 if (cmd != NULL) {
Johan Hedbergf808e162012-02-19 12:52:07 +02003550 u8 type = hdev->discovery.type;
3551
Johan Hedbergd9306502012-02-20 23:25:18 +02003552 cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0,
Johan Hedbergf808e162012-02-19 12:52:07 +02003553 &type, sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02003554 mgmt_pending_remove(cmd);
3555 }
3556
Johan Hedbergf963e8e2012-02-20 23:30:44 +02003557 memset(&ev, 0, sizeof(ev));
3558 ev.type = hdev->discovery.type;
3559 ev.discovering = discovering;
3560
3561 return mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04003562}
Antti Julku5e762442011-08-25 16:48:02 +03003563
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003564int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003565{
3566 struct pending_cmd *cmd;
3567 struct mgmt_ev_device_blocked ev;
3568
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003569 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003570
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003571 bacpy(&ev.addr.bdaddr, bdaddr);
3572 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003573
Johan Hedberg744cf192011-11-08 20:40:14 +02003574 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
3575 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003576}
3577
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003578int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003579{
3580 struct pending_cmd *cmd;
3581 struct mgmt_ev_device_unblocked ev;
3582
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003583 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003584
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003585 bacpy(&ev.addr.bdaddr, bdaddr);
3586 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003587
Johan Hedberg744cf192011-11-08 20:40:14 +02003588 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
3589 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003590}
Marcel Holtmannd7b7e792012-02-20 21:47:49 +01003591
3592module_param(enable_hs, bool, 0644);
3593MODULE_PARM_DESC(enable_hs, "Enable High Speed support");
3594
3595module_param(enable_le, bool, 0644);
3596MODULE_PARM_DESC(enable_le, "Enable Low Energy support");