blob: fa9a5896427858e0e8fd6fcb7eeae5c98e0a75f0 [file] [log] [blame]
Johan Hedberg03811012010-12-08 00:21:06 +02001/*
2 BlueZ - Bluetooth protocol stack for Linux
Johan Hedbergea585ab2012-02-17 14:50:39 +02003
Johan Hedberg03811012010-12-08 00:21:06 +02004 Copyright (C) 2010 Nokia Corporation
Johan Hedbergea585ab2012-02-17 14:50:39 +02005 Copyright (C) 2011-2012 Intel Corporation
Johan Hedberg03811012010-12-08 00:21:06 +02006
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License version 2 as
9 published by the Free Software Foundation;
10
11 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
12 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
13 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
14 IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
15 CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
16 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19
20 ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
21 COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
22 SOFTWARE IS DISCLAIMED.
23*/
24
25/* Bluetooth HCI Management interface */
26
Johan Hedbergca69b792011-11-11 18:10:00 +020027#include <linux/kernel.h>
Szymon Janc72359752011-02-17 14:16:32 +010028#include <linux/uaccess.h>
Paul Gortmaker3a9a2312011-05-27 09:12:25 -040029#include <linux/module.h>
Johan Hedberg03811012010-12-08 00:21:06 +020030#include <asm/unaligned.h>
31
32#include <net/bluetooth/bluetooth.h>
33#include <net/bluetooth/hci_core.h>
34#include <net/bluetooth/mgmt.h>
Brian Gix5fe57d92011-12-21 16:12:13 -080035#include <net/bluetooth/smp.h>
Johan Hedberg03811012010-12-08 00:21:06 +020036
Marcel Holtmannd7b7e792012-02-20 21:47:49 +010037bool enable_hs;
38bool enable_le;
39
Johan Hedberg2da9c552012-02-17 14:39:28 +020040#define MGMT_VERSION 1
41#define MGMT_REVISION 0
Johan Hedberg02d98122010-12-13 21:07:04 +020042
Johan Hedberge70bb2e2012-02-13 16:59:33 +020043static const u16 mgmt_commands[] = {
44 MGMT_OP_READ_INDEX_LIST,
45 MGMT_OP_READ_INFO,
46 MGMT_OP_SET_POWERED,
47 MGMT_OP_SET_DISCOVERABLE,
48 MGMT_OP_SET_CONNECTABLE,
49 MGMT_OP_SET_FAST_CONNECTABLE,
50 MGMT_OP_SET_PAIRABLE,
51 MGMT_OP_SET_LINK_SECURITY,
52 MGMT_OP_SET_SSP,
53 MGMT_OP_SET_HS,
54 MGMT_OP_SET_LE,
55 MGMT_OP_SET_DEV_CLASS,
56 MGMT_OP_SET_LOCAL_NAME,
57 MGMT_OP_ADD_UUID,
58 MGMT_OP_REMOVE_UUID,
59 MGMT_OP_LOAD_LINK_KEYS,
60 MGMT_OP_LOAD_LONG_TERM_KEYS,
61 MGMT_OP_DISCONNECT,
62 MGMT_OP_GET_CONNECTIONS,
63 MGMT_OP_PIN_CODE_REPLY,
64 MGMT_OP_PIN_CODE_NEG_REPLY,
65 MGMT_OP_SET_IO_CAPABILITY,
66 MGMT_OP_PAIR_DEVICE,
67 MGMT_OP_CANCEL_PAIR_DEVICE,
68 MGMT_OP_UNPAIR_DEVICE,
69 MGMT_OP_USER_CONFIRM_REPLY,
70 MGMT_OP_USER_CONFIRM_NEG_REPLY,
71 MGMT_OP_USER_PASSKEY_REPLY,
72 MGMT_OP_USER_PASSKEY_NEG_REPLY,
73 MGMT_OP_READ_LOCAL_OOB_DATA,
74 MGMT_OP_ADD_REMOTE_OOB_DATA,
75 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
76 MGMT_OP_START_DISCOVERY,
77 MGMT_OP_STOP_DISCOVERY,
78 MGMT_OP_CONFIRM_NAME,
79 MGMT_OP_BLOCK_DEVICE,
80 MGMT_OP_UNBLOCK_DEVICE,
81};
82
83static const u16 mgmt_events[] = {
84 MGMT_EV_CONTROLLER_ERROR,
85 MGMT_EV_INDEX_ADDED,
86 MGMT_EV_INDEX_REMOVED,
87 MGMT_EV_NEW_SETTINGS,
88 MGMT_EV_CLASS_OF_DEV_CHANGED,
89 MGMT_EV_LOCAL_NAME_CHANGED,
90 MGMT_EV_NEW_LINK_KEY,
91 MGMT_EV_NEW_LONG_TERM_KEY,
92 MGMT_EV_DEVICE_CONNECTED,
93 MGMT_EV_DEVICE_DISCONNECTED,
94 MGMT_EV_CONNECT_FAILED,
95 MGMT_EV_PIN_CODE_REQUEST,
96 MGMT_EV_USER_CONFIRM_REQUEST,
97 MGMT_EV_USER_PASSKEY_REQUEST,
98 MGMT_EV_AUTH_FAILED,
99 MGMT_EV_DEVICE_FOUND,
100 MGMT_EV_DISCOVERING,
101 MGMT_EV_DEVICE_BLOCKED,
102 MGMT_EV_DEVICE_UNBLOCKED,
103 MGMT_EV_DEVICE_UNPAIRED,
104};
105
Andre Guedes3fd24152012-02-03 17:48:01 -0300106/*
107 * These LE scan and inquiry parameters were chosen according to LE General
108 * Discovery Procedure specification.
109 */
110#define LE_SCAN_TYPE 0x01
111#define LE_SCAN_WIN 0x12
112#define LE_SCAN_INT 0x12
113#define LE_SCAN_TIMEOUT_LE_ONLY 10240 /* TGAP(gen_disc_scan_min) */
Andre Guedes5e0452c2012-02-17 20:39:38 -0300114#define LE_SCAN_TIMEOUT_BREDR_LE 5120 /* TGAP(100)/2 */
Andre Guedes3fd24152012-02-03 17:48:01 -0300115
Andre Guedese8777522012-02-03 17:48:02 -0300116#define INQUIRY_LEN_BREDR 0x08 /* TGAP(100) */
Andre Guedes5e0452c2012-02-17 20:39:38 -0300117#define INQUIRY_LEN_BREDR_LE 0x04 /* TGAP(100)/2 */
Andre Guedes2519a1f2011-11-07 11:45:24 -0300118
Marcel Holtmann17b02e62012-03-01 14:32:37 -0800119#define CACHE_TIMEOUT msecs_to_jiffies(2 * 1000)
Johan Hedberg7d785252011-12-15 00:47:39 +0200120
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200121#define hdev_is_powered(hdev) (test_bit(HCI_UP, &hdev->flags) && \
122 !test_bit(HCI_AUTO_OFF, &hdev->dev_flags))
123
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200124struct pending_cmd {
125 struct list_head list;
Johan Hedbergfc2f4b12011-11-09 13:58:56 +0200126 u16 opcode;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200127 int index;
Szymon Jancc68fb7f2011-03-22 13:12:19 +0100128 void *param;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200129 struct sock *sk;
Johan Hedberge9a416b2011-02-19 12:05:56 -0300130 void *user_data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200131};
132
Johan Hedbergca69b792011-11-11 18:10:00 +0200133/* HCI to MGMT error code conversion table */
134static u8 mgmt_status_table[] = {
135 MGMT_STATUS_SUCCESS,
136 MGMT_STATUS_UNKNOWN_COMMAND, /* Unknown Command */
137 MGMT_STATUS_NOT_CONNECTED, /* No Connection */
138 MGMT_STATUS_FAILED, /* Hardware Failure */
139 MGMT_STATUS_CONNECT_FAILED, /* Page Timeout */
140 MGMT_STATUS_AUTH_FAILED, /* Authentication Failed */
141 MGMT_STATUS_NOT_PAIRED, /* PIN or Key Missing */
142 MGMT_STATUS_NO_RESOURCES, /* Memory Full */
143 MGMT_STATUS_TIMEOUT, /* Connection Timeout */
144 MGMT_STATUS_NO_RESOURCES, /* Max Number of Connections */
145 MGMT_STATUS_NO_RESOURCES, /* Max Number of SCO Connections */
146 MGMT_STATUS_ALREADY_CONNECTED, /* ACL Connection Exists */
147 MGMT_STATUS_BUSY, /* Command Disallowed */
148 MGMT_STATUS_NO_RESOURCES, /* Rejected Limited Resources */
149 MGMT_STATUS_REJECTED, /* Rejected Security */
150 MGMT_STATUS_REJECTED, /* Rejected Personal */
151 MGMT_STATUS_TIMEOUT, /* Host Timeout */
152 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Feature */
153 MGMT_STATUS_INVALID_PARAMS, /* Invalid Parameters */
154 MGMT_STATUS_DISCONNECTED, /* OE User Ended Connection */
155 MGMT_STATUS_NO_RESOURCES, /* OE Low Resources */
156 MGMT_STATUS_DISCONNECTED, /* OE Power Off */
157 MGMT_STATUS_DISCONNECTED, /* Connection Terminated */
158 MGMT_STATUS_BUSY, /* Repeated Attempts */
159 MGMT_STATUS_REJECTED, /* Pairing Not Allowed */
160 MGMT_STATUS_FAILED, /* Unknown LMP PDU */
161 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Remote Feature */
162 MGMT_STATUS_REJECTED, /* SCO Offset Rejected */
163 MGMT_STATUS_REJECTED, /* SCO Interval Rejected */
164 MGMT_STATUS_REJECTED, /* Air Mode Rejected */
165 MGMT_STATUS_INVALID_PARAMS, /* Invalid LMP Parameters */
166 MGMT_STATUS_FAILED, /* Unspecified Error */
167 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported LMP Parameter Value */
168 MGMT_STATUS_FAILED, /* Role Change Not Allowed */
169 MGMT_STATUS_TIMEOUT, /* LMP Response Timeout */
170 MGMT_STATUS_FAILED, /* LMP Error Transaction Collision */
171 MGMT_STATUS_FAILED, /* LMP PDU Not Allowed */
172 MGMT_STATUS_REJECTED, /* Encryption Mode Not Accepted */
173 MGMT_STATUS_FAILED, /* Unit Link Key Used */
174 MGMT_STATUS_NOT_SUPPORTED, /* QoS Not Supported */
175 MGMT_STATUS_TIMEOUT, /* Instant Passed */
176 MGMT_STATUS_NOT_SUPPORTED, /* Pairing Not Supported */
177 MGMT_STATUS_FAILED, /* Transaction Collision */
178 MGMT_STATUS_INVALID_PARAMS, /* Unacceptable Parameter */
179 MGMT_STATUS_REJECTED, /* QoS Rejected */
180 MGMT_STATUS_NOT_SUPPORTED, /* Classification Not Supported */
181 MGMT_STATUS_REJECTED, /* Insufficient Security */
182 MGMT_STATUS_INVALID_PARAMS, /* Parameter Out Of Range */
183 MGMT_STATUS_BUSY, /* Role Switch Pending */
184 MGMT_STATUS_FAILED, /* Slot Violation */
185 MGMT_STATUS_FAILED, /* Role Switch Failed */
186 MGMT_STATUS_INVALID_PARAMS, /* EIR Too Large */
187 MGMT_STATUS_NOT_SUPPORTED, /* Simple Pairing Not Supported */
188 MGMT_STATUS_BUSY, /* Host Busy Pairing */
189 MGMT_STATUS_REJECTED, /* Rejected, No Suitable Channel */
190 MGMT_STATUS_BUSY, /* Controller Busy */
191 MGMT_STATUS_INVALID_PARAMS, /* Unsuitable Connection Interval */
192 MGMT_STATUS_TIMEOUT, /* Directed Advertising Timeout */
193 MGMT_STATUS_AUTH_FAILED, /* Terminated Due to MIC Failure */
194 MGMT_STATUS_CONNECT_FAILED, /* Connection Establishment Failed */
195 MGMT_STATUS_CONNECT_FAILED, /* MAC Connection Failed */
196};
197
198static u8 mgmt_status(u8 hci_status)
199{
200 if (hci_status < ARRAY_SIZE(mgmt_status_table))
201 return mgmt_status_table[hci_status];
202
203 return MGMT_STATUS_FAILED;
204}
205
Szymon Janc4e51eae2011-02-25 19:05:48 +0100206static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200207{
208 struct sk_buff *skb;
209 struct mgmt_hdr *hdr;
210 struct mgmt_ev_cmd_status *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300211 int err;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200212
Szymon Janc34eb5252011-02-28 14:10:08 +0100213 BT_DBG("sock %p, index %u, cmd %u, status %u", sk, index, cmd, status);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200214
215 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_ATOMIC);
216 if (!skb)
217 return -ENOMEM;
218
219 hdr = (void *) skb_put(skb, sizeof(*hdr));
220
221 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_STATUS);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100222 hdr->index = cpu_to_le16(index);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200223 hdr->len = cpu_to_le16(sizeof(*ev));
224
225 ev = (void *) skb_put(skb, sizeof(*ev));
226 ev->status = status;
227 put_unaligned_le16(cmd, &ev->opcode);
228
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300229 err = sock_queue_rcv_skb(sk, skb);
230 if (err < 0)
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200231 kfree_skb(skb);
232
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300233 return err;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200234}
235
Johan Hedbergaee9b212012-02-18 15:07:59 +0200236static int cmd_complete(struct sock *sk, u16 index, u16 cmd, u8 status,
237 void *rp, size_t rp_len)
Johan Hedberg02d98122010-12-13 21:07:04 +0200238{
239 struct sk_buff *skb;
240 struct mgmt_hdr *hdr;
241 struct mgmt_ev_cmd_complete *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300242 int err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200243
244 BT_DBG("sock %p", sk);
245
Johan Hedberga38528f2011-01-22 06:46:43 +0200246 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + rp_len, GFP_ATOMIC);
Johan Hedberg02d98122010-12-13 21:07:04 +0200247 if (!skb)
248 return -ENOMEM;
249
250 hdr = (void *) skb_put(skb, sizeof(*hdr));
Johan Hedberga38528f2011-01-22 06:46:43 +0200251
Johan Hedberg02d98122010-12-13 21:07:04 +0200252 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100253 hdr->index = cpu_to_le16(index);
Johan Hedberga38528f2011-01-22 06:46:43 +0200254 hdr->len = cpu_to_le16(sizeof(*ev) + rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200255
Johan Hedberga38528f2011-01-22 06:46:43 +0200256 ev = (void *) skb_put(skb, sizeof(*ev) + rp_len);
257 put_unaligned_le16(cmd, &ev->opcode);
Johan Hedbergaee9b212012-02-18 15:07:59 +0200258 ev->status = status;
Szymon Janc8020c162011-02-28 14:09:50 +0100259
260 if (rp)
261 memcpy(ev->data, rp, rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200262
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300263 err = sock_queue_rcv_skb(sk, skb);
264 if (err < 0)
Johan Hedberg02d98122010-12-13 21:07:04 +0200265 kfree_skb(skb);
266
Marcel Holtmanne5f0e152012-02-22 11:59:01 +0100267 return err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200268}
269
Johan 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 Hedbergaee9b212012-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 Hedbergaee9b212012-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 Hedbergaee9b212012-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 Hedbergf7b64e692010-12-13 21:07:06 +0200377
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200378 if (!(hdev->features[4] & LMP_NO_BREDR)) {
379 settings |= MGMT_SETTING_BREDR;
380 settings |= MGMT_SETTING_LINK_SECURITY;
381 }
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200382
Marcel Holtmannd7b7e792012-02-20 21:47:49 +0100383 if (enable_hs)
384 settings |= MGMT_SETTING_HS;
385
386 if (enable_le) {
387 if (hdev->features[4] & LMP_LE)
388 settings |= MGMT_SETTING_LE;
389 }
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200390
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200391 return settings;
392}
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200393
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200394static u32 get_current_settings(struct hci_dev *hdev)
395{
396 u32 settings = 0;
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200397
Johan Hedbergf1f0eb02012-02-21 17:15:41 +0200398 if (hdev_is_powered(hdev))
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100399 settings |= MGMT_SETTING_POWERED;
400
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200401 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200402 settings |= MGMT_SETTING_CONNECTABLE;
403
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200404 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200405 settings |= MGMT_SETTING_DISCOVERABLE;
406
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200407 if (test_bit(HCI_PAIRABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200408 settings |= MGMT_SETTING_PAIRABLE;
409
410 if (!(hdev->features[4] & LMP_NO_BREDR))
411 settings |= MGMT_SETTING_BREDR;
412
Johan Hedberg06199cf2012-02-22 16:37:11 +0200413 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200414 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200415
Johan Hedberg47990ea2012-02-22 11:58:37 +0200416 if (test_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200417 settings |= MGMT_SETTING_LINK_SECURITY;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200418
Johan Hedberg84bde9d6c2012-01-25 14:21:06 +0200419 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200420 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200421
Johan Hedberg6d80dfd2012-02-20 23:50:38 +0200422 if (test_bit(HCI_HS_ENABLED, &hdev->dev_flags))
423 settings |= MGMT_SETTING_HS;
424
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200425 return settings;
Johan Hedbergc542a062011-01-26 13:11:03 +0200426}
427
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300428#define PNP_INFO_SVCLASS_ID 0x1200
429
430static u8 bluetooth_base_uuid[] = {
431 0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80,
432 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
433};
434
435static u16 get_uuid16(u8 *uuid128)
436{
437 u32 val;
438 int i;
439
440 for (i = 0; i < 12; i++) {
441 if (bluetooth_base_uuid[i] != uuid128[i])
442 return 0;
443 }
444
445 memcpy(&val, &uuid128[12], 4);
446
447 val = le32_to_cpu(val);
448 if (val > 0xffff)
449 return 0;
450
451 return (u16) val;
452}
453
454static void create_eir(struct hci_dev *hdev, u8 *data)
455{
456 u8 *ptr = data;
457 u16 eir_len = 0;
458 u16 uuid16_list[HCI_MAX_EIR_LENGTH / sizeof(u16)];
459 int i, truncated = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200460 struct bt_uuid *uuid;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300461 size_t name_len;
462
463 name_len = strlen(hdev->dev_name);
464
465 if (name_len > 0) {
466 /* EIR Data type */
467 if (name_len > 48) {
468 name_len = 48;
469 ptr[1] = EIR_NAME_SHORT;
470 } else
471 ptr[1] = EIR_NAME_COMPLETE;
472
473 /* EIR Data length */
474 ptr[0] = name_len + 1;
475
476 memcpy(ptr + 2, hdev->dev_name, name_len);
477
478 eir_len += (name_len + 2);
479 ptr += (name_len + 2);
480 }
481
482 memset(uuid16_list, 0, sizeof(uuid16_list));
483
484 /* Group all UUID16 types */
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200485 list_for_each_entry(uuid, &hdev->uuids, list) {
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300486 u16 uuid16;
487
488 uuid16 = get_uuid16(uuid->uuid);
489 if (uuid16 == 0)
490 return;
491
492 if (uuid16 < 0x1100)
493 continue;
494
495 if (uuid16 == PNP_INFO_SVCLASS_ID)
496 continue;
497
498 /* Stop if not enough space to put next UUID */
499 if (eir_len + 2 + sizeof(u16) > HCI_MAX_EIR_LENGTH) {
500 truncated = 1;
501 break;
502 }
503
504 /* Check for duplicates */
505 for (i = 0; uuid16_list[i] != 0; i++)
506 if (uuid16_list[i] == uuid16)
507 break;
508
509 if (uuid16_list[i] == 0) {
510 uuid16_list[i] = uuid16;
511 eir_len += sizeof(u16);
512 }
513 }
514
515 if (uuid16_list[0] != 0) {
516 u8 *length = ptr;
517
518 /* EIR Data type */
519 ptr[1] = truncated ? EIR_UUID16_SOME : EIR_UUID16_ALL;
520
521 ptr += 2;
522 eir_len += 2;
523
524 for (i = 0; uuid16_list[i] != 0; i++) {
525 *ptr++ = (uuid16_list[i] & 0x00ff);
526 *ptr++ = (uuid16_list[i] & 0xff00) >> 8;
527 }
528
529 /* EIR Data length */
530 *length = (i * sizeof(u16)) + 1;
531 }
532}
533
534static int update_eir(struct hci_dev *hdev)
535{
536 struct hci_cp_write_eir cp;
537
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200538 if (!hdev_is_powered(hdev))
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200539 return 0;
540
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300541 if (!(hdev->features[6] & LMP_EXT_INQ))
542 return 0;
543
Johan Hedberg84bde9d6c2012-01-25 14:21:06 +0200544 if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300545 return 0;
546
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200547 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300548 return 0;
549
550 memset(&cp, 0, sizeof(cp));
551
552 create_eir(hdev, cp.data);
553
554 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
555 return 0;
556
557 memcpy(hdev->eir, cp.data, sizeof(cp.data));
558
559 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
560}
561
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200562static u8 get_service_classes(struct hci_dev *hdev)
563{
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300564 struct bt_uuid *uuid;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200565 u8 val = 0;
566
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300567 list_for_each_entry(uuid, &hdev->uuids, list)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200568 val |= uuid->svc_hint;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200569
570 return val;
571}
572
573static int update_class(struct hci_dev *hdev)
574{
575 u8 cod[3];
Johan Hedbergc95f0ba2012-02-23 22:54:38 +0200576 int err;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200577
578 BT_DBG("%s", hdev->name);
579
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200580 if (!hdev_is_powered(hdev))
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200581 return 0;
582
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200583 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200584 return 0;
585
586 cod[0] = hdev->minor_class;
587 cod[1] = hdev->major_class;
588 cod[2] = get_service_classes(hdev);
589
590 if (memcmp(cod, hdev->dev_class, 3) == 0)
591 return 0;
592
Johan Hedbergc95f0ba2012-02-23 22:54:38 +0200593 err = hci_send_cmd(hdev, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
594 if (err == 0)
595 set_bit(HCI_PENDING_CLASS, &hdev->dev_flags);
596
597 return err;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200598}
599
Johan Hedberg7d785252011-12-15 00:47:39 +0200600static void service_cache_off(struct work_struct *work)
601{
602 struct hci_dev *hdev = container_of(work, struct hci_dev,
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 Hedberg0cbf4ed2012-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 Hedberg0cbf4ed2012-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 Hedbergaee9b212012-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 Hedbergf7b64e692010-12-13 21:07:06 +0200849
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300850 hci_dev_lock(hdev);
Johan Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-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)) {
Marcel Holtmann17b02e62012-03-01 14:32:37 -08001301 schedule_delayed_work(&hdev->service_cache, CACHE_TIMEOUT);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001302 return true;
1303 }
1304
1305 return false;
1306}
1307
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001308static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
1309 u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001310{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001311 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001312 struct pending_cmd *cmd;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001313 struct list_head *p, *n;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001314 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 +02001315 int err, found;
1316
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001317 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001318
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001319 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001320
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001321 if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001322 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001323 MGMT_STATUS_BUSY);
1324 goto unlock;
1325 }
1326
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001327 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
1328 err = hci_uuids_clear(hdev);
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001329
Johan Hedberg24b78d02012-02-23 23:24:30 +02001330 if (enable_service_cache(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001331 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID,
1332 0, hdev->dev_class, 3);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001333 goto unlock;
1334 }
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001335
Johan Hedberg9246a862012-02-23 21:33:16 +02001336 goto update_class;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001337 }
1338
1339 found = 0;
1340
1341 list_for_each_safe(p, n, &hdev->uuids) {
1342 struct bt_uuid *match = list_entry(p, struct bt_uuid, list);
1343
1344 if (memcmp(match->uuid, cp->uuid, 16) != 0)
1345 continue;
1346
1347 list_del(&match->list);
1348 found++;
1349 }
1350
1351 if (found == 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001352 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Johan Hedbergca69b792011-11-11 18:10:00 +02001353 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001354 goto unlock;
1355 }
1356
Johan Hedberg9246a862012-02-23 21:33:16 +02001357update_class:
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001358 err = update_class(hdev);
1359 if (err < 0)
1360 goto unlock;
1361
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001362 err = update_eir(hdev);
1363 if (err < 0)
1364 goto unlock;
1365
Johan Hedberg90e70452012-02-23 23:09:40 +02001366 if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001367 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0,
Johan Hedberg9997a532012-02-23 15:57:46 +02001368 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001369 goto unlock;
1370 }
1371
1372 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
1373 if (!cmd) {
1374 err = -ENOMEM;
1375 goto unlock;
1376 }
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001377
1378unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001379 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001380 return err;
1381}
1382
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001383static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
1384 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001385{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001386 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001387 struct pending_cmd *cmd;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001388 int err;
1389
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001390 BT_DBG("request for %s", hdev->name);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001391
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001392 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001393
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001394 if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001395 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001396 MGMT_STATUS_BUSY);
1397 goto unlock;
1398 }
1399
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001400 hdev->major_class = cp->major;
1401 hdev->minor_class = cp->minor;
1402
Johan Hedberg932f5ff2012-02-22 22:11:32 +02001403 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001404 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Johan Hedberg932f5ff2012-02-22 22:11:32 +02001405 hdev->dev_class, 3);
1406 goto unlock;
1407 }
1408
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001409 if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02001410 hci_dev_unlock(hdev);
1411 cancel_delayed_work_sync(&hdev->service_cache);
1412 hci_dev_lock(hdev);
Johan Hedberg14c0b602011-12-15 00:47:37 +02001413 update_eir(hdev);
Johan Hedberg7d785252011-12-15 00:47:39 +02001414 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02001415
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001416 err = update_class(hdev);
Johan Hedberg90e70452012-02-23 23:09:40 +02001417 if (err < 0)
1418 goto unlock;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001419
Johan Hedberg90e70452012-02-23 23:09:40 +02001420 if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001421 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Johan Hedberg8ec37032012-02-22 22:02:50 +02001422 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001423 goto unlock;
1424 }
1425
1426 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
1427 if (!cmd) {
1428 err = -ENOMEM;
1429 goto unlock;
1430 }
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001431
Johan Hedbergb5235a62012-02-21 14:32:24 +02001432unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001433 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001434 return err;
1435}
1436
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001437static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
1438 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001439{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001440 struct mgmt_cp_load_link_keys *cp = data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001441 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001442 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001443
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001444 key_count = get_unaligned_le16(&cp->key_count);
1445
Johan Hedberg86742e12011-11-07 23:13:38 +02001446 expected_len = sizeof(*cp) + key_count *
1447 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001448 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001449 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001450 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001451 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
Johan Hedbergca69b792011-11-11 18:10:00 +02001452 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001453 }
1454
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001455 BT_DBG("%s debug_keys %u key_count %u", hdev->name, cp->debug_keys,
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001456 key_count);
1457
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001458 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001459
1460 hci_link_keys_clear(hdev);
1461
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001462 set_bit(HCI_LINK_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001463
1464 if (cp->debug_keys)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001465 set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001466 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001467 clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001468
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001469 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001470 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001471
Johan Hedbergd753fdc2012-02-17 14:06:34 +02001472 hci_add_link_key(hdev, NULL, 0, &key->addr.bdaddr, key->val,
1473 key->type, key->pin_len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001474 }
1475
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001476 cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02001477
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001478 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001479
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001480 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001481}
1482
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001483static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
1484 u8 addr_type, struct sock *skip_sk)
1485{
1486 struct mgmt_ev_device_unpaired ev;
1487
1488 bacpy(&ev.addr.bdaddr, bdaddr);
1489 ev.addr.type = addr_type;
1490
1491 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
1492 skip_sk);
1493}
1494
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001495static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
1496 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001497{
Johan Hedberg124f6e32012-02-09 13:50:12 +02001498 struct mgmt_cp_unpair_device *cp = data;
1499 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001500 struct hci_cp_disconnect dc;
1501 struct pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001502 struct hci_conn *conn;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001503 int err;
1504
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001505 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001506
Johan Hedberga8a1d192011-11-10 15:54:38 +02001507 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02001508 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1509 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001510
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001511 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001512 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001513 MGMT_STATUS_NOT_POWERED,
1514 &rp, sizeof(rp));
1515 goto unlock;
1516 }
1517
Johan Hedberg124f6e32012-02-09 13:50:12 +02001518 if (cp->addr.type == MGMT_ADDR_BREDR)
1519 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
1520 else
1521 err = hci_remove_ltk(hdev, &cp->addr.bdaddr);
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03001522
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001523 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001524 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001525 MGMT_STATUS_NOT_PAIRED,
1526 &rp, sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001527 goto unlock;
1528 }
1529
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001530 if (cp->disconnect) {
1531 if (cp->addr.type == MGMT_ADDR_BREDR)
1532 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
1533 &cp->addr.bdaddr);
1534 else
1535 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
1536 &cp->addr.bdaddr);
1537 } else {
1538 conn = NULL;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001539 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001540
Johan Hedberga8a1d192011-11-10 15:54:38 +02001541 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001542 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0,
Johan Hedbergaee9b212012-02-18 15:07:59 +02001543 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001544 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001545 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001546 }
1547
Johan Hedberg124f6e32012-02-09 13:50:12 +02001548 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
1549 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02001550 if (!cmd) {
1551 err = -ENOMEM;
1552 goto unlock;
1553 }
1554
1555 put_unaligned_le16(conn->handle, &dc.handle);
1556 dc.reason = 0x13; /* Remote User Terminated Connection */
1557 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1558 if (err < 0)
1559 mgmt_pending_remove(cmd);
1560
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001561unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001562 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001563 return err;
1564}
1565
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001566static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
1567 u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02001568{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001569 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001570 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03001571 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001572 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001573 int err;
1574
1575 BT_DBG("");
1576
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001577 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001578
1579 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001580 err = cmd_status(sk, hdev->id, MGMT_OP_DISCONNECT,
Johan Hedbergca69b792011-11-11 18:10:00 +02001581 MGMT_STATUS_NOT_POWERED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001582 goto failed;
1583 }
1584
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001585 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001586 err = cmd_status(sk, hdev->id, MGMT_OP_DISCONNECT,
Johan Hedbergca69b792011-11-11 18:10:00 +02001587 MGMT_STATUS_BUSY);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001588 goto failed;
1589 }
1590
Johan Hedberg88c3df12012-02-09 14:27:38 +02001591 if (cp->addr.type == MGMT_ADDR_BREDR)
1592 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
1593 else
1594 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03001595
Johan Hedberg8962ee72011-01-20 12:40:27 +02001596 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001597 err = cmd_status(sk, hdev->id, MGMT_OP_DISCONNECT,
Johan Hedbergca69b792011-11-11 18:10:00 +02001598 MGMT_STATUS_NOT_CONNECTED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001599 goto failed;
1600 }
1601
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001602 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001603 if (!cmd) {
1604 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001605 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001606 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001607
1608 put_unaligned_le16(conn->handle, &dc.handle);
1609 dc.reason = 0x13; /* Remote User Terminated Connection */
1610
1611 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1612 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001613 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001614
1615failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001616 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001617 return err;
1618}
1619
Johan Hedberg48264f02011-11-09 13:58:58 +02001620static u8 link_to_mgmt(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02001621{
1622 switch (link_type) {
1623 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02001624 switch (addr_type) {
1625 case ADDR_LE_DEV_PUBLIC:
1626 return MGMT_ADDR_LE_PUBLIC;
1627 case ADDR_LE_DEV_RANDOM:
1628 return MGMT_ADDR_LE_RANDOM;
1629 default:
1630 return MGMT_ADDR_INVALID;
1631 }
Johan Hedberg4c659c32011-11-07 23:13:39 +02001632 case ACL_LINK:
1633 return MGMT_ADDR_BREDR;
1634 default:
1635 return MGMT_ADDR_INVALID;
1636 }
1637}
1638
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02001639static int get_connections(struct sock *sk, struct hci_dev *hdev,
1640 void *data, u16 data_len)
Johan Hedberg2784eb42011-01-21 13:56:35 +02001641{
Johan Hedberg2784eb42011-01-21 13:56:35 +02001642 struct mgmt_rp_get_connections *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001643 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02001644 size_t rp_len;
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001645 int err;
1646 u16 i;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001647
1648 BT_DBG("");
1649
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001650 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001651
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001652 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001653 err = cmd_status(sk, hdev->id, MGMT_OP_GET_CONNECTIONS,
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001654 MGMT_STATUS_NOT_POWERED);
1655 goto unlock;
1656 }
1657
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001658 i = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02001659 list_for_each_entry(c, &hdev->conn_hash.list, list) {
1660 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001661 i++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001662 }
1663
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001664 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberga38528f2011-01-22 06:46:43 +02001665 rp = kmalloc(rp_len, GFP_ATOMIC);
1666 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02001667 err = -ENOMEM;
1668 goto unlock;
1669 }
1670
Johan Hedberg2784eb42011-01-21 13:56:35 +02001671 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001672 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02001673 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
1674 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001675 bacpy(&rp->addr[i].bdaddr, &c->dst);
Johan Hedberg48264f02011-11-09 13:58:58 +02001676 rp->addr[i].type = link_to_mgmt(c->type, c->dst_type);
Johan Hedberg4c659c32011-11-07 23:13:39 +02001677 if (rp->addr[i].type == MGMT_ADDR_INVALID)
1678 continue;
1679 i++;
1680 }
1681
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001682 put_unaligned_le16(i, &rp->conn_count);
1683
Johan Hedberg4c659c32011-11-07 23:13:39 +02001684 /* Recalculate length in case of filtered SCO connections, etc */
1685 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02001686
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001687 err = cmd_complete(sk, hdev->id, MGMT_OP_GET_CONNECTIONS, 0, rp,
1688 rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001689
Johan Hedberga38528f2011-01-22 06:46:43 +02001690 kfree(rp);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001691
1692unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001693 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001694 return err;
1695}
1696
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001697static int send_pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
1698 struct mgmt_cp_pin_code_neg_reply *cp)
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001699{
1700 struct pending_cmd *cmd;
1701 int err;
1702
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001703 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001704 sizeof(*cp));
1705 if (!cmd)
1706 return -ENOMEM;
1707
Johan Hedbergd8457692012-02-17 14:24:57 +02001708 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
1709 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001710 if (err < 0)
1711 mgmt_pending_remove(cmd);
1712
1713 return err;
1714}
1715
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001716static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data,
1717 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001718{
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001719 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001720 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001721 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03001722 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001723 int err;
1724
1725 BT_DBG("");
1726
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001727 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001728
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001729 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001730 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001731 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001732 goto failed;
1733 }
1734
Johan Hedbergd8457692012-02-17 14:24:57 +02001735 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001736 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001737 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001738 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001739 goto failed;
1740 }
1741
1742 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02001743 struct mgmt_cp_pin_code_neg_reply ncp;
1744
1745 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001746
1747 BT_ERR("PIN code is not 16 bytes long");
1748
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001749 err = send_pin_code_neg_reply(sk, hdev, &ncp);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001750 if (err >= 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001751 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001752 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001753
1754 goto failed;
1755 }
1756
Gustavo F. Padovan00abfe42012-03-01 00:37:10 -03001757 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001758 if (!cmd) {
1759 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001760 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001761 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02001762
Johan Hedbergd8457692012-02-17 14:24:57 +02001763 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001764 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02001765 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02001766
1767 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
1768 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001769 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001770
1771failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001772 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001773 return err;
1774}
1775
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001776static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
1777 void *data, u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001778{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001779 struct mgmt_cp_pin_code_neg_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001780 int err;
1781
1782 BT_DBG("");
1783
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001784 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001785
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001786 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001787 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001788 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001789 goto failed;
1790 }
1791
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001792 err = send_pin_code_neg_reply(sk, hdev, cp);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001793
1794failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001795 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001796 return err;
1797}
1798
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001799static int set_io_capability(struct sock *sk, struct hci_dev *hdev,
1800 void *data, u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001801{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001802 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001803
1804 BT_DBG("");
1805
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001806 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001807
1808 hdev->io_capability = cp->io_capability;
1809
1810 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Szymon Jancb8534e02011-03-01 16:55:34 +01001811 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001812
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001813 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001814
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001815 return cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, 0,
1816 NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001817}
1818
Johan Hedberge9a416b2011-02-19 12:05:56 -03001819static inline struct pending_cmd *find_pairing(struct hci_conn *conn)
1820{
1821 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001822 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001823
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001824 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03001825 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
1826 continue;
1827
Johan Hedberge9a416b2011-02-19 12:05:56 -03001828 if (cmd->user_data != conn)
1829 continue;
1830
1831 return cmd;
1832 }
1833
1834 return NULL;
1835}
1836
1837static void pairing_complete(struct pending_cmd *cmd, u8 status)
1838{
1839 struct mgmt_rp_pair_device rp;
1840 struct hci_conn *conn = cmd->user_data;
1841
Johan Hedbergba4e5642011-11-11 00:07:34 +02001842 bacpy(&rp.addr.bdaddr, &conn->dst);
1843 rp.addr.type = link_to_mgmt(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001844
Johan Hedbergaee9b212012-02-18 15:07:59 +02001845 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, status,
1846 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001847
1848 /* So we don't get further callbacks for this connection */
1849 conn->connect_cfm_cb = NULL;
1850 conn->security_cfm_cb = NULL;
1851 conn->disconn_cfm_cb = NULL;
1852
1853 hci_conn_put(conn);
1854
Johan Hedberga664b5b2011-02-19 12:06:02 -03001855 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001856}
1857
1858static void pairing_complete_cb(struct hci_conn *conn, u8 status)
1859{
1860 struct pending_cmd *cmd;
1861
1862 BT_DBG("status %u", status);
1863
Johan Hedberg56e5cb82011-11-08 20:40:16 +02001864 cmd = find_pairing(conn);
1865 if (!cmd)
1866 BT_DBG("Unable to find a pending command");
1867 else
Johan Hedberge2113262012-02-18 15:20:03 +02001868 pairing_complete(cmd, mgmt_status(status));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001869}
1870
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001871static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
1872 u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001873{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001874 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02001875 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001876 struct pending_cmd *cmd;
1877 u8 sec_level, auth_type;
1878 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001879 int err;
1880
1881 BT_DBG("");
1882
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001883 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001884
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001885 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001886 err = cmd_status(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001887 MGMT_STATUS_NOT_POWERED);
1888 goto unlock;
1889 }
1890
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001891 sec_level = BT_SECURITY_MEDIUM;
1892 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001893 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001894 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03001895 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001896
Johan Hedbergba4e5642011-11-11 00:07:34 +02001897 if (cp->addr.type == MGMT_ADDR_BREDR)
1898 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr, sec_level,
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001899 auth_type);
1900 else
Johan Hedbergba4e5642011-11-11 00:07:34 +02001901 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr, sec_level,
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001902 auth_type);
1903
Johan Hedberg1425acb2011-11-11 00:07:35 +02001904 memset(&rp, 0, sizeof(rp));
1905 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1906 rp.addr.type = cp->addr.type;
1907
Ville Tervo30e76272011-02-22 16:10:53 -03001908 if (IS_ERR(conn)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001909 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Johan Hedberge2113262012-02-18 15:20:03 +02001910 MGMT_STATUS_CONNECT_FAILED,
1911 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001912 goto unlock;
1913 }
1914
1915 if (conn->connect_cfm_cb) {
1916 hci_conn_put(conn);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001917 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Johan Hedberge2113262012-02-18 15:20:03 +02001918 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001919 goto unlock;
1920 }
1921
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001922 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001923 if (!cmd) {
1924 err = -ENOMEM;
1925 hci_conn_put(conn);
1926 goto unlock;
1927 }
1928
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001929 /* For LE, just connecting isn't a proof that the pairing finished */
Johan Hedbergba4e5642011-11-11 00:07:34 +02001930 if (cp->addr.type == MGMT_ADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001931 conn->connect_cfm_cb = pairing_complete_cb;
1932
Johan Hedberge9a416b2011-02-19 12:05:56 -03001933 conn->security_cfm_cb = pairing_complete_cb;
1934 conn->disconn_cfm_cb = pairing_complete_cb;
1935 conn->io_capability = cp->io_cap;
1936 cmd->user_data = conn;
1937
1938 if (conn->state == BT_CONNECTED &&
1939 hci_conn_security(conn, sec_level, auth_type))
1940 pairing_complete(cmd, 0);
1941
1942 err = 0;
1943
1944unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001945 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001946 return err;
1947}
1948
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001949static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev,
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02001950 void *data, u16 len)
Johan Hedberg28424702012-02-02 04:02:29 +02001951{
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02001952 struct mgmt_addr_info *addr = data;
Johan Hedberg28424702012-02-02 04:02:29 +02001953 struct pending_cmd *cmd;
1954 struct hci_conn *conn;
1955 int err;
1956
1957 BT_DBG("");
1958
Johan Hedberg28424702012-02-02 04:02:29 +02001959 hci_dev_lock(hdev);
1960
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001961 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001962 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001963 MGMT_STATUS_NOT_POWERED);
1964 goto unlock;
1965 }
1966
Johan Hedberg28424702012-02-02 04:02:29 +02001967 cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
1968 if (!cmd) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001969 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Johan Hedberg28424702012-02-02 04:02:29 +02001970 MGMT_STATUS_INVALID_PARAMS);
1971 goto unlock;
1972 }
1973
1974 conn = cmd->user_data;
1975
1976 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001977 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Johan Hedberg28424702012-02-02 04:02:29 +02001978 MGMT_STATUS_INVALID_PARAMS);
1979 goto unlock;
1980 }
1981
1982 pairing_complete(cmd, MGMT_STATUS_CANCELLED);
1983
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001984 err = cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0,
1985 addr, sizeof(*addr));
Johan Hedberg28424702012-02-02 04:02:29 +02001986unlock:
1987 hci_dev_unlock(hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02001988 return err;
1989}
1990
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001991static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
1992 bdaddr_t *bdaddr, u8 type, u16 mgmt_op,
1993 u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03001994{
Johan Hedberga5c29682011-02-19 12:05:57 -03001995 struct pending_cmd *cmd;
Brian Gix0df4c182011-11-16 13:53:13 -08001996 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03001997 int err;
1998
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001999 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02002000
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002001 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002002 err = cmd_status(sk, hdev->id, mgmt_op,
2003 MGMT_STATUS_NOT_POWERED);
Brian Gix0df4c182011-11-16 13:53:13 -08002004 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002005 }
2006
Johan Hedberg272d90d2012-02-09 15:26:12 +02002007 if (type == MGMT_ADDR_BREDR)
2008 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, bdaddr);
2009 else
Brian Gix47c15e22011-11-16 13:53:14 -08002010 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, bdaddr);
Brian Gix47c15e22011-11-16 13:53:14 -08002011
Johan Hedberg272d90d2012-02-09 15:26:12 +02002012 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002013 err = cmd_status(sk, hdev->id, mgmt_op,
Johan Hedberg272d90d2012-02-09 15:26:12 +02002014 MGMT_STATUS_NOT_CONNECTED);
2015 goto done;
2016 }
2017
2018 if (type == MGMT_ADDR_LE_PUBLIC || type == MGMT_ADDR_LE_RANDOM) {
Brian Gix47c15e22011-11-16 13:53:14 -08002019 /* Continue with pairing via SMP */
Brian Gix5fe57d92011-12-21 16:12:13 -08002020 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix47c15e22011-11-16 13:53:14 -08002021
Brian Gix5fe57d92011-12-21 16:12:13 -08002022 if (!err)
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002023 err = cmd_status(sk, hdev->id, mgmt_op,
Brian Gix5fe57d92011-12-21 16:12:13 -08002024 MGMT_STATUS_SUCCESS);
2025 else
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002026 err = cmd_status(sk, hdev->id, mgmt_op,
Brian Gix5fe57d92011-12-21 16:12:13 -08002027 MGMT_STATUS_FAILED);
2028
Brian Gix47c15e22011-11-16 13:53:14 -08002029 goto done;
2030 }
2031
Brian Gix0df4c182011-11-16 13:53:13 -08002032 cmd = mgmt_pending_add(sk, mgmt_op, hdev, bdaddr, sizeof(*bdaddr));
Johan Hedberga5c29682011-02-19 12:05:57 -03002033 if (!cmd) {
2034 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08002035 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002036 }
2037
Brian Gix0df4c182011-11-16 13:53:13 -08002038 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08002039 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
2040 struct hci_cp_user_passkey_reply cp;
2041
2042 bacpy(&cp.bdaddr, bdaddr);
2043 cp.passkey = passkey;
2044 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
2045 } else
2046 err = hci_send_cmd(hdev, hci_op, sizeof(*bdaddr), bdaddr);
2047
Johan Hedberga664b5b2011-02-19 12:06:02 -03002048 if (err < 0)
2049 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002050
Brian Gix0df4c182011-11-16 13:53:13 -08002051done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002052 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002053 return err;
2054}
2055
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002056static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev,
2057 void *data, u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002058{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002059 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002060
2061 BT_DBG("");
2062
2063 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002064 return cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY,
Brian Gix0df4c182011-11-16 13:53:13 -08002065 MGMT_STATUS_INVALID_PARAMS);
2066
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002067 return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
Johan Hedberg272d90d2012-02-09 15:26:12 +02002068 MGMT_OP_USER_CONFIRM_REPLY,
2069 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002070}
2071
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002072static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev,
2073 void *data, u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002074{
Johan Hedbergc9c26592011-12-15 00:47:41 +02002075 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002076
2077 BT_DBG("");
2078
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002079 return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
Johan Hedberg272d90d2012-02-09 15:26:12 +02002080 MGMT_OP_USER_CONFIRM_NEG_REPLY,
2081 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002082}
2083
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002084static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev,
2085 void *data, u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002086{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002087 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002088
2089 BT_DBG("");
2090
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002091 return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
Johan Hedberg272d90d2012-02-09 15:26:12 +02002092 MGMT_OP_USER_PASSKEY_REPLY,
2093 HCI_OP_USER_PASSKEY_REPLY,
2094 cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08002095}
2096
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002097static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
2098 void *data, u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002099{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002100 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002101
2102 BT_DBG("");
2103
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002104 return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
Johan Hedberg272d90d2012-02-09 15:26:12 +02002105 MGMT_OP_USER_PASSKEY_NEG_REPLY,
2106 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08002107}
2108
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002109static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
Johan Hedbergb312b1612011-03-16 14:29:37 +02002110 u16 len)
2111{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002112 struct mgmt_cp_set_local_name *mgmt_cp = data;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002113 struct hci_cp_write_local_name hci_cp;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002114 struct pending_cmd *cmd;
2115 int err;
2116
2117 BT_DBG("");
2118
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002119 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002120
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002121 memcpy(hdev->short_name, mgmt_cp->short_name,
2122 sizeof(hdev->short_name));
2123
Johan Hedbergb5235a62012-02-21 14:32:24 +02002124 if (!hdev_is_powered(hdev)) {
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002125 memcpy(hdev->dev_name, mgmt_cp->name, sizeof(hdev->dev_name));
2126
2127 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
2128 data, len);
2129 if (err < 0)
2130 goto failed;
2131
2132 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data, len,
2133 sk);
2134
Johan Hedbergb5235a62012-02-21 14:32:24 +02002135 goto failed;
2136 }
2137
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002138 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002139 if (!cmd) {
2140 err = -ENOMEM;
2141 goto failed;
2142 }
2143
2144 memcpy(hci_cp.name, mgmt_cp->name, sizeof(hci_cp.name));
2145 err = hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(hci_cp),
2146 &hci_cp);
2147 if (err < 0)
2148 mgmt_pending_remove(cmd);
2149
2150failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002151 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002152 return err;
2153}
2154
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002155static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
2156 void *data, u16 data_len)
Szymon Jancc35938b2011-03-22 13:12:21 +01002157{
Szymon Jancc35938b2011-03-22 13:12:21 +01002158 struct pending_cmd *cmd;
2159 int err;
2160
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002161 BT_DBG("%s", hdev->name);
Szymon Jancc35938b2011-03-22 13:12:21 +01002162
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002163 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002164
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002165 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002166 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002167 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002168 goto unlock;
2169 }
2170
2171 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002172 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002173 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002174 goto unlock;
2175 }
2176
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002177 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002178 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002179 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01002180 goto unlock;
2181 }
2182
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002183 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01002184 if (!cmd) {
2185 err = -ENOMEM;
2186 goto unlock;
2187 }
2188
2189 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
2190 if (err < 0)
2191 mgmt_pending_remove(cmd);
2192
2193unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002194 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002195 return err;
2196}
2197
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002198static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
2199 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002200{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002201 struct mgmt_cp_add_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002202 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002203 int err;
2204
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002205 BT_DBG("%s ", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01002206
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002207 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002208
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002209 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002210 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA,
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002211 MGMT_STATUS_NOT_POWERED,
2212 &cp->addr, sizeof(cp->addr));
2213 goto unlock;
2214 }
2215
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002216 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, cp->hash,
Szymon Janc2763eda2011-03-22 13:12:22 +01002217 cp->randomizer);
2218 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002219 status = MGMT_STATUS_FAILED;
Szymon Janc2763eda2011-03-22 13:12:22 +01002220 else
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002221 status = 0;
2222
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002223 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA, status,
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002224 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002225
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002226unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002227 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002228 return err;
2229}
2230
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002231static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002232 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002233{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002234 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002235 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002236 int err;
2237
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002238 BT_DBG("%s", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01002239
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002240 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002241
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002242 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002243 err = cmd_complete(sk, hdev->id,
2244 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2245 MGMT_STATUS_NOT_POWERED,
2246 &cp->addr, sizeof(cp->addr));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002247 goto unlock;
2248 }
2249
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002250 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr);
Szymon Janc2763eda2011-03-22 13:12:22 +01002251 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002252 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01002253 else
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002254 status = 0;
2255
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002256 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2257 status, &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002258
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002259unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002260 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002261 return err;
2262}
2263
Andre Guedes5e0452c2012-02-17 20:39:38 -03002264int mgmt_interleaved_discovery(struct hci_dev *hdev)
2265{
2266 int err;
2267
2268 BT_DBG("%s", hdev->name);
2269
2270 hci_dev_lock(hdev);
2271
2272 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR_LE);
2273 if (err < 0)
2274 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2275
2276 hci_dev_unlock(hdev);
2277
2278 return err;
2279}
2280
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002281static int start_discovery(struct sock *sk, struct hci_dev *hdev,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002282 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002283{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002284 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002285 struct pending_cmd *cmd;
Johan Hedberg14a53662011-04-27 10:29:56 -04002286 int err;
2287
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002288 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04002289
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002290 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002291
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002292 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002293 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Johan Hedbergca69b792011-11-11 18:10:00 +02002294 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02002295 goto failed;
2296 }
2297
Johan Hedbergff9ef572012-01-04 14:23:45 +02002298 if (hdev->discovery.state != DISCOVERY_STOPPED) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002299 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2300 MGMT_STATUS_BUSY);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002301 goto failed;
2302 }
2303
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002304 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002305 if (!cmd) {
2306 err = -ENOMEM;
2307 goto failed;
2308 }
2309
Andre Guedes4aab14e2012-02-17 20:39:36 -03002310 hdev->discovery.type = cp->type;
2311
2312 switch (hdev->discovery.type) {
Andre Guedesf39799f2012-02-17 20:39:35 -03002313 case DISCOV_TYPE_BREDR:
Andre Guedes8b901292012-02-23 18:09:27 -03002314 if (lmp_bredr_capable(hdev))
2315 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
2316 else
2317 err = -ENOTSUPP;
Andre Guedesf39799f2012-02-17 20:39:35 -03002318 break;
2319
2320 case DISCOV_TYPE_LE:
Andre Guedes8b901292012-02-23 18:09:27 -03002321 if (lmp_host_le_capable(hdev))
2322 err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT,
Andre Guedes3fd24152012-02-03 17:48:01 -03002323 LE_SCAN_WIN, LE_SCAN_TIMEOUT_LE_ONLY);
Andre Guedes8b901292012-02-23 18:09:27 -03002324 else
2325 err = -ENOTSUPP;
Andre Guedesf39799f2012-02-17 20:39:35 -03002326 break;
2327
Andre Guedes5e0452c2012-02-17 20:39:38 -03002328 case DISCOV_TYPE_INTERLEAVED:
Andre Guedes426c1892012-02-24 11:41:04 -03002329 if (lmp_host_le_capable(hdev) && lmp_bredr_capable(hdev))
2330 err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT,
2331 LE_SCAN_WIN, LE_SCAN_TIMEOUT_BREDR_LE);
2332 else
2333 err = -ENOTSUPP;
Andre Guedes5e0452c2012-02-17 20:39:38 -03002334 break;
2335
Andre Guedesf39799f2012-02-17 20:39:35 -03002336 default:
Andre Guedes3fd24152012-02-03 17:48:01 -03002337 err = -EINVAL;
Andre Guedesf39799f2012-02-17 20:39:35 -03002338 }
Andre Guedes3fd24152012-02-03 17:48:01 -03002339
Johan Hedberg14a53662011-04-27 10:29:56 -04002340 if (err < 0)
2341 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002342 else
2343 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002344
2345failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002346 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002347 return err;
2348}
2349
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002350static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
2351 u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002352{
Johan Hedbergd9306502012-02-20 23:25:18 +02002353 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002354 struct pending_cmd *cmd;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002355 struct hci_cp_remote_name_req_cancel cp;
2356 struct inquiry_entry *e;
Johan Hedberg14a53662011-04-27 10:29:56 -04002357 int err;
2358
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002359 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04002360
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002361 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002362
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002363 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002364 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Johan Hedbergd9306502012-02-20 23:25:18 +02002365 MGMT_STATUS_REJECTED,
2366 &mgmt_cp->type, sizeof(mgmt_cp->type));
2367 goto unlock;
2368 }
2369
2370 if (hdev->discovery.type != mgmt_cp->type) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002371 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Johan Hedbergd9306502012-02-20 23:25:18 +02002372 MGMT_STATUS_INVALID_PARAMS,
2373 &mgmt_cp->type, sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002374 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02002375 }
2376
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002377 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002378 if (!cmd) {
2379 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002380 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04002381 }
2382
Andre Guedes343f9352012-02-17 20:39:37 -03002383 if (hdev->discovery.state == DISCOVERY_FINDING) {
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002384 err = hci_cancel_inquiry(hdev);
2385 if (err < 0)
2386 mgmt_pending_remove(cmd);
2387 else
2388 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
2389 goto unlock;
2390 }
2391
2392 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY, NAME_PENDING);
2393 if (!e) {
2394 mgmt_pending_remove(cmd);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002395 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY, 0,
Johan Hedbergd9306502012-02-20 23:25:18 +02002396 &mgmt_cp->type, sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002397 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2398 goto unlock;
2399 }
2400
2401 bacpy(&cp.bdaddr, &e->data.bdaddr);
2402 err = hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ_CANCEL,
2403 sizeof(cp), &cp);
Johan Hedberg14a53662011-04-27 10:29:56 -04002404 if (err < 0)
2405 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002406 else
2407 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002408
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002409unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002410 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002411 return err;
2412}
2413
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002414static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
2415 u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02002416{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002417 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002418 struct inquiry_entry *e;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002419 int err;
2420
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002421 BT_DBG("%s", hdev->name);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002422
Johan Hedberg561aafb2012-01-04 13:31:59 +02002423 hci_dev_lock(hdev);
2424
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002425 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002426 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002427 MGMT_STATUS_FAILED);
2428 goto failed;
2429 }
2430
Johan Hedberga198e7b2012-02-17 14:27:06 +02002431 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002432 if (!e) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002433 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
2434 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002435 goto failed;
2436 }
2437
2438 if (cp->name_known) {
2439 e->name_state = NAME_KNOWN;
2440 list_del(&e->list);
2441 } else {
2442 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e202012-01-09 00:53:02 +02002443 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002444 }
2445
2446 err = 0;
2447
2448failed:
2449 hci_dev_unlock(hdev);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002450 return err;
2451}
2452
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002453static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
2454 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002455{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002456 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002457 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03002458 int err;
2459
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002460 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03002461
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002462 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002463
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002464 err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002465 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002466 status = MGMT_STATUS_FAILED;
Antti Julku7fbec222011-06-15 12:01:15 +03002467 else
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002468 status = 0;
2469
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002470 err = cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status,
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002471 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03002472
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002473 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002474
2475 return err;
2476}
2477
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002478static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
2479 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002480{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002481 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002482 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03002483 int err;
2484
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002485 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03002486
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002487 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002488
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002489 err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002490 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002491 status = MGMT_STATUS_INVALID_PARAMS;
Antti Julku7fbec222011-06-15 12:01:15 +03002492 else
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002493 status = 0;
2494
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002495 err = cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status,
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002496 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03002497
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002498 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002499
2500 return err;
2501}
2502
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002503static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
2504 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03002505{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002506 struct mgmt_mode *cp = data;
Antti Julkuf6422ec2011-06-22 13:11:56 +03002507 struct hci_cp_write_page_scan_activity acp;
2508 u8 type;
2509 int err;
2510
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002511 BT_DBG("%s", hdev->name);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002512
Johan Hedberg5400c042012-02-21 16:40:33 +02002513 if (!hdev_is_powered(hdev))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002514 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedberg5400c042012-02-21 16:40:33 +02002515 MGMT_STATUS_NOT_POWERED);
2516
2517 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002518 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
2519 MGMT_STATUS_REJECTED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002520
2521 hci_dev_lock(hdev);
2522
Johan Hedbergf7c6869ce2011-12-15 00:47:36 +02002523 if (cp->val) {
Antti Julkuf6422ec2011-06-22 13:11:56 +03002524 type = PAGE_SCAN_TYPE_INTERLACED;
2525 acp.interval = 0x0024; /* 22.5 msec page scan interval */
2526 } else {
2527 type = PAGE_SCAN_TYPE_STANDARD; /* default */
2528 acp.interval = 0x0800; /* default 1.28 sec page scan */
2529 }
2530
2531 acp.window = 0x0012; /* default 11.25 msec page scan window */
2532
2533 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
2534 sizeof(acp), &acp);
2535 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002536 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
2537 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002538 goto done;
2539 }
2540
2541 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
2542 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002543 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
2544 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002545 goto done;
2546 }
2547
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002548 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE, 0,
Johan Hedbergaee9b212012-02-18 15:07:59 +02002549 NULL, 0);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002550done:
2551 hci_dev_unlock(hdev);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002552 return err;
2553}
2554
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002555static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002556 void *cp_data, u16 len)
2557{
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002558 struct mgmt_cp_load_long_term_keys *cp = cp_data;
2559 u16 key_count, expected_len;
2560 int i;
2561
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002562 key_count = get_unaligned_le16(&cp->key_count);
2563
2564 expected_len = sizeof(*cp) + key_count *
2565 sizeof(struct mgmt_ltk_info);
2566 if (expected_len != len) {
2567 BT_ERR("load_keys: expected %u bytes, got %u bytes",
2568 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002569 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002570 EINVAL);
2571 }
2572
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002573 BT_DBG("%s key_count %u", hdev->name, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002574
2575 hci_dev_lock(hdev);
2576
2577 hci_smp_ltks_clear(hdev);
2578
2579 for (i = 0; i < key_count; i++) {
2580 struct mgmt_ltk_info *key = &cp->keys[i];
2581 u8 type;
2582
2583 if (key->master)
2584 type = HCI_SMP_LTK;
2585 else
2586 type = HCI_SMP_LTK_SLAVE;
2587
2588 hci_add_ltk(hdev, &key->addr.bdaddr, key->addr.type,
2589 type, 0, key->authenticated, key->val,
2590 key->enc_size, key->ediv, key->rand);
2591 }
2592
2593 hci_dev_unlock(hdev);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002594
2595 return 0;
2596}
2597
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002598struct mgmt_handler {
2599 int (*func) (struct sock *sk, struct hci_dev *hdev,
2600 void *data, u16 data_len);
Johan Hedbergbe22b542012-03-01 22:24:41 +02002601 bool var_len;
2602 size_t data_len;
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002603} mgmt_handlers[] = {
2604 { NULL }, /* 0x0000 (no command) */
Johan Hedbergbe22b542012-03-01 22:24:41 +02002605 { read_version, false, MGMT_READ_VERSION_SIZE },
2606 { read_commands, false, MGMT_READ_COMMANDS_SIZE },
2607 { read_index_list, false, MGMT_READ_INDEX_LIST_SIZE },
2608 { read_controller_info, false, MGMT_READ_INFO_SIZE },
2609 { set_powered, false, MGMT_SETTING_SIZE },
2610 { set_discoverable, false, MGMT_SET_DISCOVERABLE_SIZE },
2611 { set_connectable, false, MGMT_SETTING_SIZE },
2612 { set_fast_connectable, false, MGMT_SETTING_SIZE },
2613 { set_pairable, false, MGMT_SETTING_SIZE },
2614 { set_link_security, false, MGMT_SETTING_SIZE },
2615 { set_ssp, false, MGMT_SETTING_SIZE },
2616 { set_hs, false, MGMT_SETTING_SIZE },
2617 { set_le, false, MGMT_SETTING_SIZE },
2618 { set_dev_class, false, MGMT_SET_DEV_CLASS_SIZE },
2619 { set_local_name, false, MGMT_SET_LOCAL_NAME_SIZE },
2620 { add_uuid, false, MGMT_ADD_UUID_SIZE },
2621 { remove_uuid, false, MGMT_REMOVE_UUID_SIZE },
2622 { load_link_keys, true, MGMT_LOAD_LINK_KEYS_SIZE },
2623 { load_long_term_keys, true, MGMT_LOAD_LONG_TERM_KEYS_SIZE },
2624 { disconnect, false, MGMT_DISCONNECT_SIZE },
2625 { get_connections, false, MGMT_GET_CONNECTIONS_SIZE },
2626 { pin_code_reply, false, MGMT_PIN_CODE_REPLY_SIZE },
2627 { pin_code_neg_reply, false, MGMT_PIN_CODE_NEG_REPLY_SIZE },
2628 { set_io_capability, false, MGMT_SET_IO_CAPABILITY_SIZE },
2629 { pair_device, false, MGMT_PAIR_DEVICE_SIZE },
2630 { cancel_pair_device, false, MGMT_CANCEL_PAIR_DEVICE_SIZE },
2631 { unpair_device, false, MGMT_UNPAIR_DEVICE_SIZE },
2632 { user_confirm_reply, false, MGMT_USER_CONFIRM_REPLY_SIZE },
2633 { user_confirm_neg_reply, false, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
2634 { user_passkey_reply, false, MGMT_USER_PASSKEY_REPLY_SIZE },
2635 { user_passkey_neg_reply, false, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
2636 { read_local_oob_data, false, MGMT_READ_LOCAL_OOB_DATA_SIZE },
2637 { add_remote_oob_data, false, MGMT_ADD_REMOTE_OOB_DATA_SIZE },
2638 { remove_remote_oob_data, false, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
2639 { start_discovery, false, MGMT_START_DISCOVERY_SIZE },
2640 { stop_discovery, false, MGMT_STOP_DISCOVERY_SIZE },
2641 { confirm_name, false, MGMT_CONFIRM_NAME_SIZE },
2642 { block_device, false, MGMT_BLOCK_DEVICE_SIZE },
2643 { unblock_device, false, MGMT_UNBLOCK_DEVICE_SIZE },
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002644};
2645
2646
Johan Hedberg03811012010-12-08 00:21:06 +02002647int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
2648{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002649 void *buf;
2650 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02002651 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002652 u16 opcode, index, len;
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002653 struct hci_dev *hdev = NULL;
Johan Hedbergbe22b542012-03-01 22:24:41 +02002654 struct mgmt_handler *handler;
Johan Hedberg03811012010-12-08 00:21:06 +02002655 int err;
2656
2657 BT_DBG("got %zu bytes", msglen);
2658
2659 if (msglen < sizeof(*hdr))
2660 return -EINVAL;
2661
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03002662 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02002663 if (!buf)
2664 return -ENOMEM;
2665
2666 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
2667 err = -EFAULT;
2668 goto done;
2669 }
2670
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002671 hdr = buf;
Johan Hedberg03811012010-12-08 00:21:06 +02002672 opcode = get_unaligned_le16(&hdr->opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002673 index = get_unaligned_le16(&hdr->index);
Johan Hedberg03811012010-12-08 00:21:06 +02002674 len = get_unaligned_le16(&hdr->len);
2675
2676 if (len != msglen - sizeof(*hdr)) {
2677 err = -EINVAL;
2678 goto done;
2679 }
2680
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002681 if (index != MGMT_INDEX_NONE) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002682 hdev = hci_dev_get(index);
2683 if (!hdev) {
2684 err = cmd_status(sk, index, opcode,
Johan Hedberg5f159032012-03-02 03:13:19 +02002685 MGMT_STATUS_INVALID_INDEX);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002686 goto done;
2687 }
2688 }
2689
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002690 if (opcode >= ARRAY_SIZE(mgmt_handlers) ||
2691 mgmt_handlers[opcode].func == NULL) {
Johan Hedberg03811012010-12-08 00:21:06 +02002692 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02002693 err = cmd_status(sk, index, opcode,
2694 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002695 goto done;
Johan Hedberg03811012010-12-08 00:21:06 +02002696 }
2697
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002698 if ((hdev && opcode < MGMT_OP_READ_INFO) ||
2699 (!hdev && opcode >= MGMT_OP_READ_INFO)) {
2700 err = cmd_status(sk, index, opcode,
Johan Hedberg5f159032012-03-02 03:13:19 +02002701 MGMT_STATUS_INVALID_INDEX);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002702 goto done;
2703 }
2704
Johan Hedbergbe22b542012-03-01 22:24:41 +02002705 handler = &mgmt_handlers[opcode];
2706
2707 if ((handler->var_len && len < handler->data_len) ||
2708 (!handler->var_len && len != handler->data_len)) {
2709 err = cmd_status(sk, index, opcode,
2710 MGMT_STATUS_INVALID_PARAMS);
2711 goto done;
2712 }
2713
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002714 if (hdev)
2715 mgmt_init_hdev(sk, hdev);
2716
2717 cp = buf + sizeof(*hdr);
2718
Johan Hedbergbe22b542012-03-01 22:24:41 +02002719 err = handler->func(sk, hdev, cp, len);
Johan Hedberge41d8b42010-12-13 21:07:03 +02002720 if (err < 0)
2721 goto done;
2722
Johan Hedberg03811012010-12-08 00:21:06 +02002723 err = msglen;
2724
2725done:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002726 if (hdev)
2727 hci_dev_put(hdev);
2728
Johan Hedberg03811012010-12-08 00:21:06 +02002729 kfree(buf);
2730 return err;
2731}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002732
Johan Hedbergb24752f2011-11-03 14:40:33 +02002733static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
2734{
2735 u8 *status = data;
2736
2737 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
2738 mgmt_pending_remove(cmd);
2739}
2740
Johan Hedberg744cf192011-11-08 20:40:14 +02002741int mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002742{
Johan Hedberg744cf192011-11-08 20:40:14 +02002743 return mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002744}
2745
Johan Hedberg744cf192011-11-08 20:40:14 +02002746int mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002747{
Johan Hedberg5f159032012-03-02 03:13:19 +02002748 u8 status = MGMT_STATUS_INVALID_INDEX;
Johan Hedbergb24752f2011-11-03 14:40:33 +02002749
Johan Hedberg744cf192011-11-08 20:40:14 +02002750 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002751
Johan Hedberg744cf192011-11-08 20:40:14 +02002752 return mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002753}
2754
Johan Hedberg73f22f62010-12-29 16:00:25 +02002755struct cmd_lookup {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002756 struct sock *sk;
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002757 struct hci_dev *hdev;
Johan Hedberg90e70452012-02-23 23:09:40 +02002758 u8 mgmt_status;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002759};
2760
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002761static void settings_rsp(struct pending_cmd *cmd, void *data)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002762{
Johan Hedberg73f22f62010-12-29 16:00:25 +02002763 struct cmd_lookup *match = data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002764
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002765 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002766
2767 list_del(&cmd->list);
2768
2769 if (match->sk == NULL) {
2770 match->sk = cmd->sk;
2771 sock_hold(match->sk);
2772 }
2773
2774 mgmt_pending_free(cmd);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002775}
Johan Hedberg5add6af2010-12-16 10:00:37 +02002776
Johan Hedberg744cf192011-11-08 20:40:14 +02002777int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg5add6af2010-12-16 10:00:37 +02002778{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002779 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002780 int err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002781
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002782 if (!test_bit(HCI_MGMT, &hdev->dev_flags))
2783 return 0;
2784
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002785 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
Johan Hedberg5add6af2010-12-16 10:00:37 +02002786
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002787 if (powered) {
2788 u8 scan = 0;
2789
2790 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
2791 scan |= SCAN_PAGE;
2792 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
2793 scan |= SCAN_INQUIRY;
2794
2795 if (scan)
2796 hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
Johan Hedberg504c8dc2012-02-23 13:30:41 +02002797
2798 update_class(hdev);
2799 update_eir(hdev);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002800 } else {
Johan Hedbergd4f68522012-03-02 03:07:07 +02002801 u8 status = MGMT_STATUS_NOT_POWERED;
Johan Hedberg744cf192011-11-08 20:40:14 +02002802 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002803 }
2804
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02002805 err = new_settings(hdev, match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002806
2807 if (match.sk)
2808 sock_put(match.sk);
2809
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002810 return err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002811}
Johan Hedberg73f22f62010-12-29 16:00:25 +02002812
Johan Hedberg744cf192011-11-08 20:40:14 +02002813int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg73f22f62010-12-29 16:00:25 +02002814{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002815 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002816 bool changed = false;
2817 int err = 0;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002818
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002819 if (discoverable) {
2820 if (!test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
2821 changed = true;
2822 } else {
2823 if (test_and_clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
2824 changed = true;
2825 }
Johan Hedberg73f22f62010-12-29 16:00:25 +02002826
Johan Hedberged9b5f22012-02-21 20:47:06 +02002827 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp,
2828 &match);
2829
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02002830 if (changed)
2831 err = new_settings(hdev, match.sk);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002832
Johan Hedberg73f22f62010-12-29 16:00:25 +02002833 if (match.sk)
2834 sock_put(match.sk);
2835
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002836 return err;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002837}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002838
Johan Hedberg744cf192011-11-08 20:40:14 +02002839int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002840{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002841 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002842 bool changed = false;
2843 int err = 0;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002844
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002845 if (connectable) {
2846 if (!test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags))
2847 changed = true;
2848 } else {
2849 if (test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags))
2850 changed = true;
2851 }
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002852
Johan Hedberged9b5f22012-02-21 20:47:06 +02002853 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev, settings_rsp,
2854 &match);
2855
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02002856 if (changed)
2857 err = new_settings(hdev, match.sk);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002858
2859 if (match.sk)
2860 sock_put(match.sk);
2861
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002862 return err;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002863}
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002864
Johan Hedberg744cf192011-11-08 20:40:14 +02002865int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002866{
Johan Hedbergca69b792011-11-11 18:10:00 +02002867 u8 mgmt_err = mgmt_status(status);
2868
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002869 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02002870 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Johan Hedbergca69b792011-11-11 18:10:00 +02002871 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002872
2873 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02002874 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Johan Hedbergca69b792011-11-11 18:10:00 +02002875 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002876
2877 return 0;
2878}
2879
Johan Hedberg744cf192011-11-08 20:40:14 +02002880int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
2881 u8 persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002882{
Johan Hedberg86742e12011-11-07 23:13:38 +02002883 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002884
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002885 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002886
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002887 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02002888 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
2889 ev.key.addr.type = MGMT_ADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002890 ev.key.type = key->type;
2891 memcpy(ev.key.val, key->val, 16);
2892 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002893
Johan Hedberg744cf192011-11-08 20:40:14 +02002894 return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002895}
Johan Hedbergf7520542011-01-20 12:34:39 +02002896
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002897int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
2898{
2899 struct mgmt_ev_new_long_term_key ev;
2900
2901 memset(&ev, 0, sizeof(ev));
2902
2903 ev.store_hint = persistent;
2904 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
2905 ev.key.addr.type = key->bdaddr_type;
2906 ev.key.authenticated = key->authenticated;
2907 ev.key.enc_size = key->enc_size;
2908 ev.key.ediv = key->ediv;
2909
2910 if (key->type == HCI_SMP_LTK)
2911 ev.key.master = 1;
2912
2913 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
2914 memcpy(ev.key.val, key->val, sizeof(key->val));
2915
2916 return mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev,
2917 &ev, sizeof(ev), NULL);
2918}
2919
Johan Hedbergafc747a2012-01-15 18:11:07 +02002920int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Johan Hedberg08c79b62012-02-23 22:31:51 +02002921 u8 addr_type, u32 flags, u8 *name,
2922 u8 name_len, u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02002923{
Johan Hedbergb644ba32012-01-17 21:48:47 +02002924 char buf[512];
2925 struct mgmt_ev_device_connected *ev = (void *) buf;
2926 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02002927
Johan Hedbergb644ba32012-01-17 21:48:47 +02002928 bacpy(&ev->addr.bdaddr, bdaddr);
2929 ev->addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02002930
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02002931 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02002932
Johan Hedbergb644ba32012-01-17 21:48:47 +02002933 if (name_len > 0)
2934 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
2935 name, name_len);
2936
2937 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
2938 eir_len = eir_append_data(&ev->eir[eir_len], eir_len,
2939 EIR_CLASS_OF_DEV, dev_class, 3);
2940
2941 put_unaligned_le16(eir_len, &ev->eir_len);
2942
2943 return mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
2944 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02002945}
2946
Johan Hedberg8962ee72011-01-20 12:40:27 +02002947static void disconnect_rsp(struct pending_cmd *cmd, void *data)
2948{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01002949 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002950 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02002951 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002952
Johan Hedberg88c3df12012-02-09 14:27:38 +02002953 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2954 rp.addr.type = cp->addr.type;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002955
Johan Hedbergaee9b212012-02-18 15:07:59 +02002956 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, 0, &rp,
2957 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002958
2959 *sk = cmd->sk;
2960 sock_hold(*sk);
2961
Johan Hedberga664b5b2011-02-19 12:06:02 -03002962 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002963}
2964
Johan Hedberg124f6e32012-02-09 13:50:12 +02002965static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02002966{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002967 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02002968 struct mgmt_cp_unpair_device *cp = cmd->param;
2969 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002970
2971 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02002972 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2973 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002974
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002975 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
2976
Johan Hedbergaee9b212012-02-18 15:07:59 +02002977 cmd_complete(cmd->sk, cmd->index, cmd->opcode, 0, &rp, sizeof(rp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02002978
2979 mgmt_pending_remove(cmd);
2980}
2981
Johan Hedbergafc747a2012-01-15 18:11:07 +02002982int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
2983 u8 link_type, u8 addr_type)
Johan Hedbergf7520542011-01-20 12:34:39 +02002984{
Johan Hedberg4c659c32011-11-07 23:13:39 +02002985 struct mgmt_addr_info ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002986 struct sock *sk = NULL;
2987 int err;
2988
Johan Hedberg744cf192011-11-08 20:40:14 +02002989 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02002990
Johan Hedbergf7520542011-01-20 12:34:39 +02002991 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02002992 ev.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02002993
Johan Hedbergafc747a2012-01-15 18:11:07 +02002994 err = mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev),
2995 sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002996
2997 if (sk)
2998 sock_put(sk);
2999
Johan Hedberg124f6e32012-02-09 13:50:12 +02003000 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003001 hdev);
Johan Hedberga8a1d192011-11-10 15:54:38 +02003002
Johan Hedberg8962ee72011-01-20 12:40:27 +02003003 return err;
3004}
3005
Johan Hedberg88c3df12012-02-09 14:27:38 +02003006int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
3007 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02003008{
Johan Hedberg88c3df12012-02-09 14:27:38 +02003009 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003010 struct pending_cmd *cmd;
3011 int err;
3012
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003013 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003014 if (!cmd)
3015 return -ENOENT;
3016
Johan Hedberg88c3df12012-02-09 14:27:38 +02003017 bacpy(&rp.addr.bdaddr, bdaddr);
3018 rp.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02003019
Johan Hedberg88c3df12012-02-09 14:27:38 +02003020 err = cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
Johan Hedbergaee9b212012-02-18 15:07:59 +02003021 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003022
Johan Hedberga664b5b2011-02-19 12:06:02 -03003023 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003024
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003025 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
3026 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003027 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02003028}
Johan Hedberg17d5c042011-01-22 06:09:08 +02003029
Johan Hedberg48264f02011-11-09 13:58:58 +02003030int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
3031 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02003032{
3033 struct mgmt_ev_connect_failed ev;
3034
Johan Hedberg4c659c32011-11-07 23:13:39 +02003035 bacpy(&ev.addr.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02003036 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003037 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003038
Johan Hedberg744cf192011-11-08 20:40:14 +02003039 return mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003040}
Johan Hedberg980e1a52011-01-22 06:10:07 +02003041
Johan Hedberg744cf192011-11-08 20:40:14 +02003042int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003043{
3044 struct mgmt_ev_pin_code_request ev;
3045
Johan Hedbergd8457692012-02-17 14:24:57 +02003046 bacpy(&ev.addr.bdaddr, bdaddr);
3047 ev.addr.type = MGMT_ADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02003048 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003049
Johan Hedberg744cf192011-11-08 20:40:14 +02003050 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01003051 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003052}
3053
Johan Hedberg744cf192011-11-08 20:40:14 +02003054int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3055 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003056{
3057 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003058 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003059 int err;
3060
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003061 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003062 if (!cmd)
3063 return -ENOENT;
3064
Johan Hedbergd8457692012-02-17 14:24:57 +02003065 bacpy(&rp.addr.bdaddr, bdaddr);
3066 rp.addr.type = MGMT_ADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003067
Johan Hedbergaee9b212012-02-18 15:07:59 +02003068 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
3069 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003070
Johan Hedberga664b5b2011-02-19 12:06:02 -03003071 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003072
3073 return err;
3074}
3075
Johan Hedberg744cf192011-11-08 20:40:14 +02003076int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3077 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003078{
3079 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003080 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003081 int err;
3082
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003083 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003084 if (!cmd)
3085 return -ENOENT;
3086
Johan Hedbergd8457692012-02-17 14:24:57 +02003087 bacpy(&rp.addr.bdaddr, bdaddr);
3088 rp.addr.type = MGMT_ADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003089
Johan Hedbergaee9b212012-02-18 15:07:59 +02003090 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
3091 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003092
Johan Hedberga664b5b2011-02-19 12:06:02 -03003093 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003094
3095 return err;
3096}
Johan Hedberga5c29682011-02-19 12:05:57 -03003097
Johan Hedberg744cf192011-11-08 20:40:14 +02003098int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003099 u8 link_type, u8 addr_type, __le32 value,
3100 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03003101{
3102 struct mgmt_ev_user_confirm_request ev;
3103
Johan Hedberg744cf192011-11-08 20:40:14 +02003104 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03003105
Johan Hedberg272d90d2012-02-09 15:26:12 +02003106 bacpy(&ev.addr.bdaddr, bdaddr);
3107 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07003108 ev.confirm_hint = confirm_hint;
Johan Hedberga5c29682011-02-19 12:05:57 -03003109 put_unaligned_le32(value, &ev.value);
3110
Johan Hedberg744cf192011-11-08 20:40:14 +02003111 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01003112 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03003113}
3114
Johan Hedberg272d90d2012-02-09 15:26:12 +02003115int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
3116 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08003117{
3118 struct mgmt_ev_user_passkey_request ev;
3119
3120 BT_DBG("%s", hdev->name);
3121
Johan Hedberg272d90d2012-02-09 15:26:12 +02003122 bacpy(&ev.addr.bdaddr, bdaddr);
3123 ev.addr.type = link_to_mgmt(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08003124
3125 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
3126 NULL);
3127}
3128
Brian Gix0df4c182011-11-16 13:53:13 -08003129static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003130 u8 link_type, u8 addr_type, u8 status,
3131 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03003132{
3133 struct pending_cmd *cmd;
3134 struct mgmt_rp_user_confirm_reply rp;
3135 int err;
3136
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003137 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03003138 if (!cmd)
3139 return -ENOENT;
3140
Johan Hedberg272d90d2012-02-09 15:26:12 +02003141 bacpy(&rp.addr.bdaddr, bdaddr);
3142 rp.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergaee9b212012-02-18 15:07:59 +02003143 err = cmd_complete(cmd->sk, hdev->id, opcode, mgmt_status(status),
3144 &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03003145
Johan Hedberga664b5b2011-02-19 12:06:02 -03003146 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03003147
3148 return err;
3149}
3150
Johan Hedberg744cf192011-11-08 20:40:14 +02003151int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003152 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003153{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003154 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3155 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003156}
3157
Johan Hedberg272d90d2012-02-09 15:26:12 +02003158int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3159 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003160{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003161 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3162 status, MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003163}
Johan Hedberg2a611692011-02-19 12:06:00 -03003164
Brian Gix604086b2011-11-23 08:28:33 -08003165int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003166 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003167{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003168 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3169 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003170}
3171
Johan Hedberg272d90d2012-02-09 15:26:12 +02003172int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3173 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003174{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003175 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3176 status, MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003177}
3178
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003179int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
3180 u8 addr_type, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03003181{
3182 struct mgmt_ev_auth_failed ev;
3183
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003184 bacpy(&ev.addr.bdaddr, bdaddr);
3185 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003186 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03003187
Johan Hedberg744cf192011-11-08 20:40:14 +02003188 return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03003189}
Johan Hedbergb312b1612011-03-16 14:29:37 +02003190
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003191int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
3192{
3193 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg47990ea2012-02-22 11:58:37 +02003194 bool changed = false;
3195 int err = 0;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003196
3197 if (status) {
3198 u8 mgmt_err = mgmt_status(status);
3199 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
3200 cmd_status_rsp, &mgmt_err);
3201 return 0;
3202 }
3203
Johan Hedberg47990ea2012-02-22 11:58:37 +02003204 if (test_bit(HCI_AUTH, &hdev->flags)) {
3205 if (!test_and_set_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
3206 changed = true;
3207 } else {
3208 if (test_and_clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
3209 changed = true;
3210 }
3211
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003212 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
3213 &match);
3214
Johan Hedberg47990ea2012-02-22 11:58:37 +02003215 if (changed)
3216 err = new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003217
3218 if (match.sk)
3219 sock_put(match.sk);
3220
3221 return err;
3222}
3223
Johan Hedbergcacaf522012-02-21 00:52:42 +02003224static int clear_eir(struct hci_dev *hdev)
3225{
3226 struct hci_cp_write_eir cp;
3227
3228 if (!(hdev->features[6] & LMP_EXT_INQ))
3229 return 0;
3230
Johan Hedbergc80da272012-02-22 15:38:48 +02003231 memset(hdev->eir, 0, sizeof(hdev->eir));
3232
Johan Hedbergcacaf522012-02-21 00:52:42 +02003233 memset(&cp, 0, sizeof(cp));
3234
3235 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
3236}
3237
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003238int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003239{
3240 struct cmd_lookup match = { NULL, hdev };
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003241 bool changed = false;
3242 int err = 0;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003243
3244 if (status) {
3245 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003246
3247 if (enable && test_and_clear_bit(HCI_SSP_ENABLED,
3248 &hdev->dev_flags))
3249 err = new_settings(hdev, NULL);
3250
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003251 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev,
3252 cmd_status_rsp, &mgmt_err);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003253
3254 return err;
3255 }
3256
3257 if (enable) {
3258 if (!test_and_set_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3259 changed = true;
3260 } else {
3261 if (test_and_clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3262 changed = true;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003263 }
3264
3265 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
3266
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003267 if (changed)
3268 err = new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003269
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02003270 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003271 sock_put(match.sk);
3272
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02003273 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3274 update_eir(hdev);
3275 else
3276 clear_eir(hdev);
Johan Hedbergcacaf522012-02-21 00:52:42 +02003277
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003278 return err;
3279}
3280
Johan Hedberg90e70452012-02-23 23:09:40 +02003281static void class_rsp(struct pending_cmd *cmd, void *data)
3282{
3283 struct cmd_lookup *match = data;
3284
3285 cmd_complete(cmd->sk, cmd->index, cmd->opcode, match->mgmt_status,
3286 match->hdev->dev_class, 3);
3287
3288 list_del(&cmd->list);
3289
3290 if (match->sk == NULL) {
3291 match->sk = cmd->sk;
3292 sock_hold(match->sk);
3293 }
3294
3295 mgmt_pending_free(cmd);
3296}
3297
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003298int mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
3299 u8 status)
3300{
Johan Hedberg90e70452012-02-23 23:09:40 +02003301 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
3302 int err = 0;
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003303
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02003304 clear_bit(HCI_PENDING_CLASS, &hdev->dev_flags);
3305
Johan Hedberg90e70452012-02-23 23:09:40 +02003306 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, class_rsp, &match);
3307 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, class_rsp, &match);
3308 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, class_rsp, &match);
3309
3310 if (!status)
3311 err = mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
3312 dev_class, 3, NULL);
3313
3314 if (match.sk)
3315 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003316
3317 return err;
3318}
3319
Johan Hedberg744cf192011-11-08 20:40:14 +02003320int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02003321{
3322 struct pending_cmd *cmd;
3323 struct mgmt_cp_set_local_name ev;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003324 bool changed = false;
3325 int err = 0;
3326
3327 if (memcmp(name, hdev->dev_name, sizeof(hdev->dev_name)) != 0) {
3328 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
3329 changed = true;
3330 }
Johan Hedbergb312b1612011-03-16 14:29:37 +02003331
3332 memset(&ev, 0, sizeof(ev));
3333 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003334 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003335
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003336 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003337 if (!cmd)
3338 goto send_event;
3339
Johan Hedberg7bdaae42012-02-22 21:39:58 +02003340 /* Always assume that either the short or the complete name has
3341 * changed if there was a pending mgmt command */
3342 changed = true;
3343
Johan Hedbergb312b1612011-03-16 14:29:37 +02003344 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02003345 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
Johan Hedbergca69b792011-11-11 18:10:00 +02003346 mgmt_status(status));
Johan Hedbergb312b1612011-03-16 14:29:37 +02003347 goto failed;
3348 }
3349
Johan Hedbergaee9b212012-02-18 15:07:59 +02003350 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0, &ev,
Johan Hedbergb312b1612011-03-16 14:29:37 +02003351 sizeof(ev));
3352 if (err < 0)
3353 goto failed;
3354
3355send_event:
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003356 if (changed)
3357 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev,
3358 sizeof(ev), cmd ? cmd->sk : NULL);
3359
Johan Hedbergf51d5b22012-02-22 18:17:32 +02003360 update_eir(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003361
3362failed:
3363 if (cmd)
3364 mgmt_pending_remove(cmd);
3365 return err;
3366}
Szymon Jancc35938b2011-03-22 13:12:21 +01003367
Johan Hedberg744cf192011-11-08 20:40:14 +02003368int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
3369 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01003370{
3371 struct pending_cmd *cmd;
3372 int err;
3373
Johan Hedberg744cf192011-11-08 20:40:14 +02003374 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01003375
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003376 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003377 if (!cmd)
3378 return -ENOENT;
3379
3380 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02003381 err = cmd_status(cmd->sk, hdev->id,
Johan Hedbergca69b792011-11-11 18:10:00 +02003382 MGMT_OP_READ_LOCAL_OOB_DATA,
3383 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01003384 } else {
3385 struct mgmt_rp_read_local_oob_data rp;
3386
3387 memcpy(rp.hash, hash, sizeof(rp.hash));
3388 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
3389
Johan Hedberg744cf192011-11-08 20:40:14 +02003390 err = cmd_complete(cmd->sk, hdev->id,
3391 MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergaee9b212012-02-18 15:07:59 +02003392 0, &rp, sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01003393 }
3394
3395 mgmt_pending_remove(cmd);
3396
3397 return err;
3398}
Johan Hedberge17acd42011-03-30 23:57:16 +03003399
Johan Hedberg06199cf2012-02-22 16:37:11 +02003400int mgmt_le_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
3401{
3402 struct cmd_lookup match = { NULL, hdev };
3403 bool changed = false;
3404 int err = 0;
3405
3406 if (status) {
3407 u8 mgmt_err = mgmt_status(status);
3408
3409 if (enable && test_and_clear_bit(HCI_LE_ENABLED,
3410 &hdev->dev_flags))
3411 err = new_settings(hdev, NULL);
3412
3413 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev,
3414 cmd_status_rsp, &mgmt_err);
3415
3416 return err;
3417 }
3418
3419 if (enable) {
3420 if (!test_and_set_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3421 changed = true;
3422 } else {
3423 if (test_and_clear_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3424 changed = true;
3425 }
3426
3427 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
3428
3429 if (changed)
3430 err = new_settings(hdev, match.sk);
3431
3432 if (match.sk)
3433 sock_put(match.sk);
3434
3435 return err;
3436}
3437
Johan Hedberg48264f02011-11-09 13:58:58 +02003438int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Johan Hedberg561aafb2012-01-04 13:31:59 +02003439 u8 addr_type, u8 *dev_class, s8 rssi,
Johan Hedberg388fc8f2012-02-23 00:38:59 +02003440 u8 cfm_name, u8 ssp, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03003441{
Johan Hedberge319d2e2012-01-15 19:51:59 +02003442 char buf[512];
3443 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02003444 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03003445
Johan Hedberg1dc06092012-01-15 21:01:23 +02003446 /* Leave 5 bytes for a potential CoD field */
3447 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Andre Guedes7d262f82012-01-10 18:20:49 -03003448 return -EINVAL;
3449
Johan Hedberg1dc06092012-01-15 21:01:23 +02003450 memset(buf, 0, sizeof(buf));
3451
Johan Hedberge319d2e2012-01-15 19:51:59 +02003452 bacpy(&ev->addr.bdaddr, bdaddr);
3453 ev->addr.type = link_to_mgmt(link_type, addr_type);
3454 ev->rssi = rssi;
Johan Hedberg9a395a82012-02-23 00:00:32 +02003455 if (cfm_name)
3456 ev->flags[0] |= MGMT_DEV_FOUND_CONFIRM_NAME;
Johan Hedberg388fc8f2012-02-23 00:38:59 +02003457 if (!ssp)
3458 ev->flags[0] |= MGMT_DEV_FOUND_LEGACY_PAIRING;
Johan Hedberge17acd42011-03-30 23:57:16 +03003459
Johan Hedberg1dc06092012-01-15 21:01:23 +02003460 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02003461 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03003462
Johan Hedberg1dc06092012-01-15 21:01:23 +02003463 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
3464 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
3465 dev_class, 3);
3466
3467 put_unaligned_le16(eir_len, &ev->eir_len);
3468
3469 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03003470
Johan Hedberge319d2e2012-01-15 19:51:59 +02003471 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03003472}
Johan Hedberga88a9652011-03-30 13:18:12 +03003473
Johan Hedbergb644ba32012-01-17 21:48:47 +02003474int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
3475 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03003476{
Johan Hedbergb644ba32012-01-17 21:48:47 +02003477 struct mgmt_ev_device_found *ev;
3478 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
3479 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03003480
Johan Hedbergb644ba32012-01-17 21:48:47 +02003481 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03003482
Johan Hedbergb644ba32012-01-17 21:48:47 +02003483 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03003484
Johan Hedbergb644ba32012-01-17 21:48:47 +02003485 bacpy(&ev->addr.bdaddr, bdaddr);
3486 ev->addr.type = link_to_mgmt(link_type, addr_type);
3487 ev->rssi = rssi;
3488
3489 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
3490 name_len);
3491
3492 put_unaligned_le16(eir_len, &ev->eir_len);
3493
Johan Hedberg053c7e02012-02-04 00:06:00 +02003494 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev,
3495 sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03003496}
Johan Hedberg314b2382011-04-27 10:29:57 -04003497
Andre Guedes7a135102011-11-09 17:14:25 -03003498int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
Johan Hedberg164a6e72011-11-01 17:06:44 +02003499{
3500 struct pending_cmd *cmd;
Johan Hedbergf808e162012-02-19 12:52:07 +02003501 u8 type;
Johan Hedberg164a6e72011-11-01 17:06:44 +02003502 int err;
3503
Andre Guedes203159d2012-02-13 15:41:01 -03003504 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3505
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003506 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003507 if (!cmd)
3508 return -ENOENT;
3509
Johan Hedbergf808e162012-02-19 12:52:07 +02003510 type = hdev->discovery.type;
3511
3512 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
3513 &type, sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02003514 mgmt_pending_remove(cmd);
3515
3516 return err;
3517}
3518
Andre Guedese6d465c2011-11-09 17:14:26 -03003519int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
3520{
3521 struct pending_cmd *cmd;
3522 int err;
3523
3524 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
3525 if (!cmd)
3526 return -ENOENT;
3527
Johan Hedbergd9306502012-02-20 23:25:18 +02003528 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
3529 &hdev->discovery.type,
3530 sizeof(hdev->discovery.type));
Johan Hedberg03811012010-12-08 00:21:06 +02003531 mgmt_pending_remove(cmd);
3532
3533 return err;
3534}
Johan Hedberg314b2382011-04-27 10:29:57 -04003535
Johan Hedberg744cf192011-11-08 20:40:14 +02003536int mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04003537{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02003538 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02003539 struct pending_cmd *cmd;
3540
Andre Guedes343fb142011-11-22 17:14:19 -03003541 BT_DBG("%s discovering %u", hdev->name, discovering);
3542
Johan Hedberg164a6e72011-11-01 17:06:44 +02003543 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003544 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003545 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003546 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003547
3548 if (cmd != NULL) {
Johan Hedbergf808e162012-02-19 12:52:07 +02003549 u8 type = hdev->discovery.type;
3550
Johan Hedbergd9306502012-02-20 23:25:18 +02003551 cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0,
Johan Hedbergf808e162012-02-19 12:52:07 +02003552 &type, sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02003553 mgmt_pending_remove(cmd);
3554 }
3555
Johan Hedbergf963e8e2012-02-20 23:30:44 +02003556 memset(&ev, 0, sizeof(ev));
3557 ev.type = hdev->discovery.type;
3558 ev.discovering = discovering;
3559
3560 return mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04003561}
Antti Julku5e762442011-08-25 16:48:02 +03003562
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003563int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003564{
3565 struct pending_cmd *cmd;
3566 struct mgmt_ev_device_blocked ev;
3567
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003568 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003569
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003570 bacpy(&ev.addr.bdaddr, bdaddr);
3571 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003572
Johan Hedberg744cf192011-11-08 20:40:14 +02003573 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
3574 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003575}
3576
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003577int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003578{
3579 struct pending_cmd *cmd;
3580 struct mgmt_ev_device_unblocked ev;
3581
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003582 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003583
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003584 bacpy(&ev.addr.bdaddr, bdaddr);
3585 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003586
Johan Hedberg744cf192011-11-08 20:40:14 +02003587 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
3588 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003589}
Marcel Holtmannd7b7e792012-02-20 21:47:49 +01003590
3591module_param(enable_hs, bool, 0644);
3592MODULE_PARM_DESC(enable_hs, "Enable High Speed support");
3593
3594module_param(enable_le, bool, 0644);
3595MODULE_PARM_DESC(enable_le, "Enable Low Energy support");