blob: 4ca009268afbc9143981e37374e34b24c337349d [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 Hedberg4f87da82012-03-02 19:55:56 +0200618 if (test_and_set_bit(HCI_MGMT, &hdev->dev_flags))
Johan Hedberg6a919082012-02-28 06:17:26 +0200619 return;
620
Johan Hedberg4f87da82012-03-02 19:55:56 +0200621 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
Johan Hedberg7d785252011-12-15 00:47:39 +0200622
Johan Hedberg4f87da82012-03-02 19:55:56 +0200623 /* Non-mgmt controlled devices get this bit set
624 * implicitly so that pairing works for them, however
625 * for mgmt we require user-space to explicitly enable
626 * it
627 */
628 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedberg7d785252011-12-15 00:47:39 +0200629}
630
Johan Hedberg0f4e68c2012-02-28 17:18:30 +0200631static int read_controller_info(struct sock *sk, struct hci_dev *hdev,
632 void *data, u16 data_len)
Johan Hedberg03811012010-12-08 00:21:06 +0200633{
634 struct mgmt_rp_read_info rp;
Johan Hedberg03811012010-12-08 00:21:06 +0200635
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200636 BT_DBG("sock %p %s", sk, hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200637
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300638 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200639
Johan Hedberg03811012010-12-08 00:21:06 +0200640 memset(&rp, 0, sizeof(rp));
641
Johan Hedberg03811012010-12-08 00:21:06 +0200642 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200643
644 rp.version = hdev->hci_ver;
645
Johan Hedberg03811012010-12-08 00:21:06 +0200646 put_unaligned_le16(hdev->manufacturer, &rp.manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200647
648 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
649 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
650
651 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedberg03811012010-12-08 00:21:06 +0200652
653 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
Johan Hedberg27fcc362012-02-22 21:46:22 +0200654 memcpy(rp.short_name, hdev->short_name, sizeof(hdev->short_name));
Johan Hedberg03811012010-12-08 00:21:06 +0200655
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300656 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200657
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200658 return cmd_complete(sk, hdev->id, MGMT_OP_READ_INFO, 0, &rp,
659 sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +0200660}
661
662static void mgmt_pending_free(struct pending_cmd *cmd)
663{
664 sock_put(cmd->sk);
665 kfree(cmd->param);
666 kfree(cmd);
667}
668
669static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
670 struct hci_dev *hdev,
671 void *data, u16 len)
672{
673 struct pending_cmd *cmd;
674
675 cmd = kmalloc(sizeof(*cmd), GFP_ATOMIC);
676 if (!cmd)
677 return NULL;
678
679 cmd->opcode = opcode;
680 cmd->index = hdev->id;
681
682 cmd->param = kmalloc(len, GFP_ATOMIC);
683 if (!cmd->param) {
684 kfree(cmd);
685 return NULL;
686 }
687
688 if (data)
689 memcpy(cmd->param, data, len);
690
691 cmd->sk = sk;
692 sock_hold(sk);
693
694 list_add(&cmd->list, &hdev->mgmt_pending);
695
696 return cmd;
697}
698
699static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
700 void (*cb)(struct pending_cmd *cmd, void *data),
701 void *data)
702{
703 struct list_head *p, *n;
704
705 list_for_each_safe(p, n, &hdev->mgmt_pending) {
706 struct pending_cmd *cmd;
707
708 cmd = list_entry(p, struct pending_cmd, list);
709
710 if (opcode > 0 && cmd->opcode != opcode)
711 continue;
712
713 cb(cmd, data);
714 }
715}
716
717static struct pending_cmd *mgmt_pending_find(u16 opcode, struct hci_dev *hdev)
718{
719 struct pending_cmd *cmd;
720
721 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
722 if (cmd->opcode == opcode)
723 return cmd;
724 }
725
726 return NULL;
727}
728
729static void mgmt_pending_remove(struct pending_cmd *cmd)
730{
731 list_del(&cmd->list);
732 mgmt_pending_free(cmd);
733}
734
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200735static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +0200736{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200737 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +0200738
Johan Hedbergaee9b212012-02-18 15:07:59 +0200739 return cmd_complete(sk, hdev->id, opcode, 0, &settings,
740 sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +0200741}
742
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200743static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data,
744 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200745{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300746 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200747 struct pending_cmd *cmd;
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200748 int err;
Johan Hedberg03811012010-12-08 00:21:06 +0200749
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200750 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200751
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300752 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200753
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100754 if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) {
755 cancel_delayed_work(&hdev->power_off);
756
757 if (cp->val) {
758 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
759 mgmt_powered(hdev, 1);
760 goto failed;
761 }
762 }
763
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200764 if (!!cp->val == hdev_is_powered(hdev)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200765 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200766 goto failed;
767 }
768
769 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200770 err = cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
Johan Hedbergca69b792011-11-11 18:10:00 +0200771 MGMT_STATUS_BUSY);
Johan Hedberg03811012010-12-08 00:21:06 +0200772 goto failed;
773 }
774
775 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
776 if (!cmd) {
777 err = -ENOMEM;
778 goto failed;
779 }
780
781 if (cp->val)
Gustavo F. Padovan7f971042011-12-18 12:40:32 -0200782 schedule_work(&hdev->power_on);
Johan Hedberg03811012010-12-08 00:21:06 +0200783 else
Gustavo F. Padovan80b7ab32011-12-17 14:52:27 -0200784 schedule_work(&hdev->power_off.work);
Johan Hedberg03811012010-12-08 00:21:06 +0200785
786 err = 0;
787
788failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300789 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200790 return err;
791}
792
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200793static int mgmt_event(u16 event, struct hci_dev *hdev, void *data,
794 u16 data_len, struct sock *skip_sk)
795{
796 struct sk_buff *skb;
797 struct mgmt_hdr *hdr;
798
799 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_ATOMIC);
800 if (!skb)
801 return -ENOMEM;
802
803 hdr = (void *) skb_put(skb, sizeof(*hdr));
804 hdr->opcode = cpu_to_le16(event);
805 if (hdev)
806 hdr->index = cpu_to_le16(hdev->id);
807 else
808 hdr->index = cpu_to_le16(MGMT_INDEX_NONE);
809 hdr->len = cpu_to_le16(data_len);
810
811 if (data)
812 memcpy(skb_put(skb, data_len), data, data_len);
813
Marcel Holtmann97e0bde2012-02-22 13:49:28 +0100814 /* Time stamp */
815 __net_timestamp(skb);
816
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200817 hci_send_to_control(skb, skip_sk);
818 kfree_skb(skb);
819
820 return 0;
821}
822
823static int new_settings(struct hci_dev *hdev, struct sock *skip)
824{
825 __le32 ev;
826
827 ev = cpu_to_le32(get_current_settings(hdev));
828
829 return mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), skip);
830}
831
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200832static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
833 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200834{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300835 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200836 struct pending_cmd *cmd;
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200837 u16 timeout;
Johan Hedberg03811012010-12-08 00:21:06 +0200838 u8 scan;
839 int err;
840
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200841 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200842
Marcel Holtmann24c54a92012-02-22 18:06:34 +0100843 timeout = get_unaligned_le16(&cp->timeout);
844 if (!cp->val && timeout > 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200845 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +0200846 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200847
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300848 hci_dev_lock(hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200849
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200850 if (!hdev_is_powered(hdev) && timeout > 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200851 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +0200852 MGMT_STATUS_NOT_POWERED);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200853 goto failed;
854 }
855
856 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
857 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200858 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +0200859 MGMT_STATUS_BUSY);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200860 goto failed;
861 }
862
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200863 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200864 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200865 MGMT_STATUS_REJECTED);
866 goto failed;
867 }
868
869 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200870 bool changed = false;
871
872 if (!!cp->val != test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
873 change_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
874 changed = true;
875 }
876
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200877 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200878 if (err < 0)
879 goto failed;
880
881 if (changed)
882 err = new_settings(hdev, sk);
883
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200884 goto failed;
885 }
886
887 if (!!cp->val == test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
Marcel Holtmann955638e2012-02-22 18:21:00 +0100888 if (hdev->discov_timeout > 0) {
889 cancel_delayed_work(&hdev->discov_off);
890 hdev->discov_timeout = 0;
891 }
892
893 if (cp->val && timeout > 0) {
894 hdev->discov_timeout = timeout;
895 queue_delayed_work(hdev->workqueue, &hdev->discov_off,
896 msecs_to_jiffies(hdev->discov_timeout * 1000));
897 }
898
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200899 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200900 goto failed;
901 }
902
903 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
904 if (!cmd) {
905 err = -ENOMEM;
906 goto failed;
907 }
908
909 scan = SCAN_PAGE;
910
911 if (cp->val)
912 scan |= SCAN_INQUIRY;
913 else
914 cancel_delayed_work(&hdev->discov_off);
915
916 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
917 if (err < 0)
918 mgmt_pending_remove(cmd);
919
Johan Hedberg03811012010-12-08 00:21:06 +0200920 if (cp->val)
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200921 hdev->discov_timeout = timeout;
Johan Hedberg03811012010-12-08 00:21:06 +0200922
923failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300924 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200925 return err;
926}
927
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200928static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
929 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200930{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300931 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200932 struct pending_cmd *cmd;
933 u8 scan;
934 int err;
935
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200936 BT_DBG("request for %s", hdev->name);
Johan Hedberge41d8b42010-12-13 21:07:03 +0200937
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300938 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200939
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200940 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200941 bool changed = false;
942
943 if (!!cp->val != test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
944 changed = true;
945
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +0200946 if (cp->val) {
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200947 set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +0200948 } else {
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200949 clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
950 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
951 }
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200952
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200953 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200954 if (err < 0)
955 goto failed;
956
957 if (changed)
958 err = new_settings(hdev, sk);
959
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200960 goto failed;
961 }
962
963 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
964 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200965 err = cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +0200966 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200967 goto failed;
968 }
969
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200970 if (!!cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200971 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200972 goto failed;
973 }
974
975 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
976 if (!cmd) {
977 err = -ENOMEM;
978 goto failed;
979 }
980
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +0200981 if (cp->val) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200982 scan = SCAN_PAGE;
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +0200983 } else {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200984 scan = 0;
985
Johan Hedbergdf2c6c52012-02-21 19:15:49 +0200986 if (test_bit(HCI_ISCAN, &hdev->flags) &&
987 hdev->discov_timeout > 0)
988 cancel_delayed_work(&hdev->discov_off);
989 }
990
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200991 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
992 if (err < 0)
993 mgmt_pending_remove(cmd);
994
995failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300996 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200997 return err;
998}
999
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001000static int set_pairable(struct sock *sk, struct hci_dev *hdev, void *data,
1001 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001002{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001003 struct mgmt_mode *cp = data;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001004 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001005
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001006 BT_DBG("request for %s", hdev->name);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001007
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001008 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001009
1010 if (cp->val)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001011 set_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001012 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001013 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001014
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001015 err = send_settings_rsp(sk, MGMT_OP_SET_PAIRABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001016 if (err < 0)
1017 goto failed;
1018
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001019 err = new_settings(hdev, sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001020
1021failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001022 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001023 return err;
1024}
Johan Hedberg72a734e2010-12-30 00:38:22 +02001025
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001026static int set_link_security(struct sock *sk, struct hci_dev *hdev,
1027 void *data, u16 len)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001028{
1029 struct mgmt_mode *cp = data;
1030 struct pending_cmd *cmd;
Johan Hedberg816a11d2012-02-26 13:04:52 +02001031 u8 val;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001032 int err;
1033
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001034 BT_DBG("request for %s", hdev->name);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001035
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001036 hci_dev_lock(hdev);
1037
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001038 if (!hdev_is_powered(hdev)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001039 bool changed = false;
1040
1041 if (!!cp->val != test_bit(HCI_LINK_SECURITY,
1042 &hdev->dev_flags)) {
1043 change_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
1044 changed = true;
1045 }
1046
1047 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1048 if (err < 0)
1049 goto failed;
1050
1051 if (changed)
1052 err = new_settings(hdev, sk);
1053
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001054 goto failed;
1055 }
1056
1057 if (mgmt_pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001058 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001059 MGMT_STATUS_BUSY);
1060 goto failed;
1061 }
1062
1063 val = !!cp->val;
1064
1065 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1066 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1067 goto failed;
1068 }
1069
1070 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1071 if (!cmd) {
1072 err = -ENOMEM;
1073 goto failed;
1074 }
1075
1076 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1077 if (err < 0) {
1078 mgmt_pending_remove(cmd);
1079 goto failed;
1080 }
1081
1082failed:
1083 hci_dev_unlock(hdev);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001084 return err;
1085}
1086
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001087static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001088{
1089 struct mgmt_mode *cp = data;
1090 struct pending_cmd *cmd;
Johan Hedberg816a11d2012-02-26 13:04:52 +02001091 u8 val;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001092 int err;
1093
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001094 BT_DBG("request for %s", hdev->name);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001095
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001096 hci_dev_lock(hdev);
1097
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001098 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001099 err = cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001100 MGMT_STATUS_NOT_SUPPORTED);
1101 goto failed;
1102 }
1103
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001104 val = !!cp->val;
1105
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001106 if (!hdev_is_powered(hdev)) {
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001107 bool changed = false;
1108
1109 if (val != test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) {
1110 change_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
1111 changed = true;
1112 }
1113
1114 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1115 if (err < 0)
1116 goto failed;
1117
1118 if (changed)
1119 err = new_settings(hdev, sk);
1120
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001121 goto failed;
1122 }
1123
1124 if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001125 err = cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1126 MGMT_STATUS_BUSY);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001127 goto failed;
1128 }
1129
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001130 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) == val) {
1131 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1132 goto failed;
1133 }
1134
1135 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1136 if (!cmd) {
1137 err = -ENOMEM;
1138 goto failed;
1139 }
1140
1141 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, sizeof(val), &val);
1142 if (err < 0) {
1143 mgmt_pending_remove(cmd);
1144 goto failed;
1145 }
1146
1147failed:
1148 hci_dev_unlock(hdev);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001149 return err;
1150}
1151
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001152static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001153{
1154 struct mgmt_mode *cp = data;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001155
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001156 BT_DBG("request for %s", hdev->name);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001157
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001158 if (!enable_hs)
1159 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1160 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001161
1162 if (cp->val)
1163 set_bit(HCI_HS_ENABLED, &hdev->dev_flags);
1164 else
1165 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
1166
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001167 return send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001168}
1169
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001170static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001171{
1172 struct mgmt_mode *cp = data;
1173 struct hci_cp_write_le_host_supported hci_cp;
1174 struct pending_cmd *cmd;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001175 int err;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001176 u8 val, enabled;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001177
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001178 BT_DBG("request for %s", hdev->name);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001179
Johan Hedberg1de028c2012-02-29 19:55:35 -08001180 hci_dev_lock(hdev);
1181
Johan Hedberg06199cf2012-02-22 16:37:11 +02001182 if (!enable_le || !(hdev->features[4] & LMP_LE)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001183 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
Johan Hedberg06199cf2012-02-22 16:37:11 +02001184 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001185 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001186 }
1187
1188 val = !!cp->val;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001189 enabled = !!(hdev->host_features[0] & LMP_HOST_LE);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001190
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001191 if (!hdev_is_powered(hdev) || val == enabled) {
Johan Hedberg06199cf2012-02-22 16:37:11 +02001192 bool changed = false;
1193
1194 if (val != test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
1195 change_bit(HCI_LE_ENABLED, &hdev->dev_flags);
1196 changed = true;
1197 }
1198
1199 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1200 if (err < 0)
Johan Hedberg1de028c2012-02-29 19:55:35 -08001201 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001202
1203 if (changed)
1204 err = new_settings(hdev, sk);
1205
Johan Hedberg1de028c2012-02-29 19:55:35 -08001206 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001207 }
1208
1209 if (mgmt_pending_find(MGMT_OP_SET_LE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001210 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1211 MGMT_STATUS_BUSY);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001212 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001213 }
1214
1215 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
1216 if (!cmd) {
1217 err = -ENOMEM;
Johan Hedberg1de028c2012-02-29 19:55:35 -08001218 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001219 }
1220
1221 memset(&hci_cp, 0, sizeof(hci_cp));
1222
1223 if (val) {
1224 hci_cp.le = val;
1225 hci_cp.simul = !!(hdev->features[6] & LMP_SIMUL_LE_BR);
1226 }
1227
1228 err = hci_send_cmd(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED,
1229 sizeof(hci_cp), &hci_cp);
1230 if (err < 0) {
1231 mgmt_pending_remove(cmd);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001232 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001233 }
1234
Johan Hedberg1de028c2012-02-29 19:55:35 -08001235unlock:
1236 hci_dev_unlock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001237 return err;
1238}
1239
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001240static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001241{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001242 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001243 struct pending_cmd *cmd;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001244 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001245 int err;
1246
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001247 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001248
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001249 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001250
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001251 if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001252 err = cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID,
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001253 MGMT_STATUS_BUSY);
1254 goto failed;
1255 }
1256
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001257 uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC);
1258 if (!uuid) {
1259 err = -ENOMEM;
1260 goto failed;
1261 }
1262
1263 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001264 uuid->svc_hint = cp->svc_hint;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001265
1266 list_add(&uuid->list, &hdev->uuids);
1267
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001268 err = update_class(hdev);
1269 if (err < 0)
1270 goto failed;
1271
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001272 err = update_eir(hdev);
1273 if (err < 0)
1274 goto failed;
1275
Johan Hedberg90e70452012-02-23 23:09:40 +02001276 if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001277 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0,
Johan Hedberg90e70452012-02-23 23:09:40 +02001278 hdev->dev_class, 3);
1279 goto failed;
1280 }
1281
1282 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len);
1283 if (!cmd) {
1284 err = -ENOMEM;
1285 goto failed;
1286 }
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001287
1288failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001289 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001290 return err;
1291}
1292
Johan Hedberg24b78d02012-02-23 23:24:30 +02001293static bool enable_service_cache(struct hci_dev *hdev)
1294{
1295 if (!hdev_is_powered(hdev))
1296 return false;
1297
1298 if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Marcel Holtmann17b02e62012-03-01 14:32:37 -08001299 schedule_delayed_work(&hdev->service_cache, CACHE_TIMEOUT);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001300 return true;
1301 }
1302
1303 return false;
1304}
1305
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001306static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
1307 u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001308{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001309 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001310 struct pending_cmd *cmd;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001311 struct list_head *p, *n;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001312 u8 bt_uuid_any[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001313 int err, found;
1314
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001315 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001316
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001317 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001318
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001319 if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001320 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001321 MGMT_STATUS_BUSY);
1322 goto unlock;
1323 }
1324
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001325 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
1326 err = hci_uuids_clear(hdev);
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001327
Johan Hedberg24b78d02012-02-23 23:24:30 +02001328 if (enable_service_cache(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001329 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID,
1330 0, hdev->dev_class, 3);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001331 goto unlock;
1332 }
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001333
Johan Hedberg9246a862012-02-23 21:33:16 +02001334 goto update_class;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001335 }
1336
1337 found = 0;
1338
1339 list_for_each_safe(p, n, &hdev->uuids) {
1340 struct bt_uuid *match = list_entry(p, struct bt_uuid, list);
1341
1342 if (memcmp(match->uuid, cp->uuid, 16) != 0)
1343 continue;
1344
1345 list_del(&match->list);
1346 found++;
1347 }
1348
1349 if (found == 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001350 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Johan Hedbergca69b792011-11-11 18:10:00 +02001351 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001352 goto unlock;
1353 }
1354
Johan Hedberg9246a862012-02-23 21:33:16 +02001355update_class:
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001356 err = update_class(hdev);
1357 if (err < 0)
1358 goto unlock;
1359
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001360 err = update_eir(hdev);
1361 if (err < 0)
1362 goto unlock;
1363
Johan Hedberg90e70452012-02-23 23:09:40 +02001364 if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001365 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0,
Johan Hedberg9997a532012-02-23 15:57:46 +02001366 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001367 goto unlock;
1368 }
1369
1370 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
1371 if (!cmd) {
1372 err = -ENOMEM;
1373 goto unlock;
1374 }
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001375
1376unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001377 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001378 return err;
1379}
1380
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001381static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
1382 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001383{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001384 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001385 struct pending_cmd *cmd;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001386 int err;
1387
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001388 BT_DBG("request for %s", hdev->name);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001389
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001390 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001391
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001392 if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001393 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001394 MGMT_STATUS_BUSY);
1395 goto unlock;
1396 }
1397
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001398 hdev->major_class = cp->major;
1399 hdev->minor_class = cp->minor;
1400
Johan Hedberg932f5ff2012-02-22 22:11:32 +02001401 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001402 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Johan Hedberg932f5ff2012-02-22 22:11:32 +02001403 hdev->dev_class, 3);
1404 goto unlock;
1405 }
1406
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001407 if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02001408 hci_dev_unlock(hdev);
1409 cancel_delayed_work_sync(&hdev->service_cache);
1410 hci_dev_lock(hdev);
Johan Hedberg14c0b602011-12-15 00:47:37 +02001411 update_eir(hdev);
Johan Hedberg7d785252011-12-15 00:47:39 +02001412 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02001413
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001414 err = update_class(hdev);
Johan Hedberg90e70452012-02-23 23:09:40 +02001415 if (err < 0)
1416 goto unlock;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001417
Johan Hedberg90e70452012-02-23 23:09:40 +02001418 if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001419 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Johan Hedberg8ec37032012-02-22 22:02:50 +02001420 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001421 goto unlock;
1422 }
1423
1424 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
1425 if (!cmd) {
1426 err = -ENOMEM;
1427 goto unlock;
1428 }
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001429
Johan Hedbergb5235a62012-02-21 14:32:24 +02001430unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001431 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001432 return err;
1433}
1434
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001435static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
1436 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001437{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001438 struct mgmt_cp_load_link_keys *cp = data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001439 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001440 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001441
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001442 key_count = get_unaligned_le16(&cp->key_count);
1443
Johan Hedberg86742e12011-11-07 23:13:38 +02001444 expected_len = sizeof(*cp) + key_count *
1445 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001446 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001447 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001448 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001449 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
Johan Hedbergca69b792011-11-11 18:10:00 +02001450 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001451 }
1452
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001453 BT_DBG("%s debug_keys %u key_count %u", hdev->name, cp->debug_keys,
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001454 key_count);
1455
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001456 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001457
1458 hci_link_keys_clear(hdev);
1459
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001460 set_bit(HCI_LINK_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001461
1462 if (cp->debug_keys)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001463 set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001464 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001465 clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001466
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001467 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001468 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001469
Johan Hedbergd753fdc2012-02-17 14:06:34 +02001470 hci_add_link_key(hdev, NULL, 0, &key->addr.bdaddr, key->val,
1471 key->type, key->pin_len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001472 }
1473
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001474 cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02001475
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001476 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001477
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001478 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001479}
1480
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001481static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
1482 u8 addr_type, struct sock *skip_sk)
1483{
1484 struct mgmt_ev_device_unpaired ev;
1485
1486 bacpy(&ev.addr.bdaddr, bdaddr);
1487 ev.addr.type = addr_type;
1488
1489 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
1490 skip_sk);
1491}
1492
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001493static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
1494 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001495{
Johan Hedberg124f6e32012-02-09 13:50:12 +02001496 struct mgmt_cp_unpair_device *cp = data;
1497 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001498 struct hci_cp_disconnect dc;
1499 struct pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001500 struct hci_conn *conn;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001501 int err;
1502
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001503 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001504
Johan Hedberga8a1d192011-11-10 15:54:38 +02001505 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02001506 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1507 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001508
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001509 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001510 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001511 MGMT_STATUS_NOT_POWERED,
1512 &rp, sizeof(rp));
1513 goto unlock;
1514 }
1515
Johan Hedberg124f6e32012-02-09 13:50:12 +02001516 if (cp->addr.type == MGMT_ADDR_BREDR)
1517 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
1518 else
1519 err = hci_remove_ltk(hdev, &cp->addr.bdaddr);
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03001520
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001521 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001522 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001523 MGMT_STATUS_NOT_PAIRED,
1524 &rp, sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001525 goto unlock;
1526 }
1527
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001528 if (cp->disconnect) {
1529 if (cp->addr.type == MGMT_ADDR_BREDR)
1530 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
1531 &cp->addr.bdaddr);
1532 else
1533 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
1534 &cp->addr.bdaddr);
1535 } else {
1536 conn = NULL;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001537 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001538
Johan Hedberga8a1d192011-11-10 15:54:38 +02001539 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001540 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0,
Johan Hedbergaee9b212012-02-18 15:07:59 +02001541 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001542 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001543 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001544 }
1545
Johan Hedberg124f6e32012-02-09 13:50:12 +02001546 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
1547 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02001548 if (!cmd) {
1549 err = -ENOMEM;
1550 goto unlock;
1551 }
1552
1553 put_unaligned_le16(conn->handle, &dc.handle);
1554 dc.reason = 0x13; /* Remote User Terminated Connection */
1555 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1556 if (err < 0)
1557 mgmt_pending_remove(cmd);
1558
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001559unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001560 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001561 return err;
1562}
1563
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001564static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
1565 u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02001566{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001567 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001568 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03001569 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001570 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001571 int err;
1572
1573 BT_DBG("");
1574
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001575 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001576
1577 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001578 err = cmd_status(sk, hdev->id, MGMT_OP_DISCONNECT,
Johan Hedbergca69b792011-11-11 18:10:00 +02001579 MGMT_STATUS_NOT_POWERED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001580 goto failed;
1581 }
1582
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001583 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001584 err = cmd_status(sk, hdev->id, MGMT_OP_DISCONNECT,
Johan Hedbergca69b792011-11-11 18:10:00 +02001585 MGMT_STATUS_BUSY);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001586 goto failed;
1587 }
1588
Johan Hedberg88c3df12012-02-09 14:27:38 +02001589 if (cp->addr.type == MGMT_ADDR_BREDR)
1590 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
1591 else
1592 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03001593
Johan Hedberg8962ee72011-01-20 12:40:27 +02001594 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001595 err = cmd_status(sk, hdev->id, MGMT_OP_DISCONNECT,
Johan Hedbergca69b792011-11-11 18:10:00 +02001596 MGMT_STATUS_NOT_CONNECTED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001597 goto failed;
1598 }
1599
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001600 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001601 if (!cmd) {
1602 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001603 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001604 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001605
1606 put_unaligned_le16(conn->handle, &dc.handle);
1607 dc.reason = 0x13; /* Remote User Terminated Connection */
1608
1609 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1610 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001611 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001612
1613failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001614 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001615 return err;
1616}
1617
Johan Hedberg48264f02011-11-09 13:58:58 +02001618static u8 link_to_mgmt(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02001619{
1620 switch (link_type) {
1621 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02001622 switch (addr_type) {
1623 case ADDR_LE_DEV_PUBLIC:
1624 return MGMT_ADDR_LE_PUBLIC;
1625 case ADDR_LE_DEV_RANDOM:
1626 return MGMT_ADDR_LE_RANDOM;
1627 default:
1628 return MGMT_ADDR_INVALID;
1629 }
Johan Hedberg4c659c32011-11-07 23:13:39 +02001630 case ACL_LINK:
1631 return MGMT_ADDR_BREDR;
1632 default:
1633 return MGMT_ADDR_INVALID;
1634 }
1635}
1636
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02001637static int get_connections(struct sock *sk, struct hci_dev *hdev,
1638 void *data, u16 data_len)
Johan Hedberg2784eb42011-01-21 13:56:35 +02001639{
Johan Hedberg2784eb42011-01-21 13:56:35 +02001640 struct mgmt_rp_get_connections *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001641 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02001642 size_t rp_len;
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001643 int err;
1644 u16 i;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001645
1646 BT_DBG("");
1647
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001648 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001649
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001650 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001651 err = cmd_status(sk, hdev->id, MGMT_OP_GET_CONNECTIONS,
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001652 MGMT_STATUS_NOT_POWERED);
1653 goto unlock;
1654 }
1655
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001656 i = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02001657 list_for_each_entry(c, &hdev->conn_hash.list, list) {
1658 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001659 i++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001660 }
1661
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001662 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberga38528f2011-01-22 06:46:43 +02001663 rp = kmalloc(rp_len, GFP_ATOMIC);
1664 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02001665 err = -ENOMEM;
1666 goto unlock;
1667 }
1668
Johan Hedberg2784eb42011-01-21 13:56:35 +02001669 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001670 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02001671 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
1672 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001673 bacpy(&rp->addr[i].bdaddr, &c->dst);
Johan Hedberg48264f02011-11-09 13:58:58 +02001674 rp->addr[i].type = link_to_mgmt(c->type, c->dst_type);
Johan Hedberg4c659c32011-11-07 23:13:39 +02001675 if (rp->addr[i].type == MGMT_ADDR_INVALID)
1676 continue;
1677 i++;
1678 }
1679
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001680 put_unaligned_le16(i, &rp->conn_count);
1681
Johan Hedberg4c659c32011-11-07 23:13:39 +02001682 /* Recalculate length in case of filtered SCO connections, etc */
1683 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02001684
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001685 err = cmd_complete(sk, hdev->id, MGMT_OP_GET_CONNECTIONS, 0, rp,
1686 rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001687
Johan Hedberga38528f2011-01-22 06:46:43 +02001688 kfree(rp);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001689
1690unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001691 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001692 return err;
1693}
1694
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001695static int send_pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
1696 struct mgmt_cp_pin_code_neg_reply *cp)
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001697{
1698 struct pending_cmd *cmd;
1699 int err;
1700
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001701 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001702 sizeof(*cp));
1703 if (!cmd)
1704 return -ENOMEM;
1705
Johan Hedbergd8457692012-02-17 14:24:57 +02001706 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
1707 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001708 if (err < 0)
1709 mgmt_pending_remove(cmd);
1710
1711 return err;
1712}
1713
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001714static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data,
1715 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001716{
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001717 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001718 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001719 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03001720 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001721 int err;
1722
1723 BT_DBG("");
1724
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001725 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001726
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001727 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001728 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001729 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001730 goto failed;
1731 }
1732
Johan Hedbergd8457692012-02-17 14:24:57 +02001733 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001734 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001735 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001736 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001737 goto failed;
1738 }
1739
1740 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02001741 struct mgmt_cp_pin_code_neg_reply ncp;
1742
1743 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001744
1745 BT_ERR("PIN code is not 16 bytes long");
1746
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001747 err = send_pin_code_neg_reply(sk, hdev, &ncp);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001748 if (err >= 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001749 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001750 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001751
1752 goto failed;
1753 }
1754
Gustavo F. Padovan00abfe42012-03-01 00:37:10 -03001755 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001756 if (!cmd) {
1757 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001758 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001759 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02001760
Johan Hedbergd8457692012-02-17 14:24:57 +02001761 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001762 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02001763 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02001764
1765 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
1766 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001767 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001768
1769failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001770 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001771 return err;
1772}
1773
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001774static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
1775 void *data, u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001776{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001777 struct mgmt_cp_pin_code_neg_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001778 int err;
1779
1780 BT_DBG("");
1781
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001782 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001783
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001784 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001785 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001786 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001787 goto failed;
1788 }
1789
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001790 err = send_pin_code_neg_reply(sk, hdev, cp);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001791
1792failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001793 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001794 return err;
1795}
1796
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001797static int set_io_capability(struct sock *sk, struct hci_dev *hdev,
1798 void *data, u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001799{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001800 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001801
1802 BT_DBG("");
1803
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001804 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001805
1806 hdev->io_capability = cp->io_capability;
1807
1808 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Szymon Jancb8534e02011-03-01 16:55:34 +01001809 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001810
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001811 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001812
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001813 return cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, 0,
1814 NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001815}
1816
Johan Hedberge9a416b2011-02-19 12:05:56 -03001817static inline struct pending_cmd *find_pairing(struct hci_conn *conn)
1818{
1819 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001820 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001821
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001822 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03001823 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
1824 continue;
1825
Johan Hedberge9a416b2011-02-19 12:05:56 -03001826 if (cmd->user_data != conn)
1827 continue;
1828
1829 return cmd;
1830 }
1831
1832 return NULL;
1833}
1834
1835static void pairing_complete(struct pending_cmd *cmd, u8 status)
1836{
1837 struct mgmt_rp_pair_device rp;
1838 struct hci_conn *conn = cmd->user_data;
1839
Johan Hedbergba4e5642011-11-11 00:07:34 +02001840 bacpy(&rp.addr.bdaddr, &conn->dst);
1841 rp.addr.type = link_to_mgmt(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001842
Johan Hedbergaee9b212012-02-18 15:07:59 +02001843 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, status,
1844 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001845
1846 /* So we don't get further callbacks for this connection */
1847 conn->connect_cfm_cb = NULL;
1848 conn->security_cfm_cb = NULL;
1849 conn->disconn_cfm_cb = NULL;
1850
1851 hci_conn_put(conn);
1852
Johan Hedberga664b5b2011-02-19 12:06:02 -03001853 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001854}
1855
1856static void pairing_complete_cb(struct hci_conn *conn, u8 status)
1857{
1858 struct pending_cmd *cmd;
1859
1860 BT_DBG("status %u", status);
1861
Johan Hedberg56e5cb82011-11-08 20:40:16 +02001862 cmd = find_pairing(conn);
1863 if (!cmd)
1864 BT_DBG("Unable to find a pending command");
1865 else
Johan Hedberge2113262012-02-18 15:20:03 +02001866 pairing_complete(cmd, mgmt_status(status));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001867}
1868
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001869static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
1870 u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001871{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001872 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02001873 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001874 struct pending_cmd *cmd;
1875 u8 sec_level, auth_type;
1876 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001877 int err;
1878
1879 BT_DBG("");
1880
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001881 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001882
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001883 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001884 err = cmd_status(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001885 MGMT_STATUS_NOT_POWERED);
1886 goto unlock;
1887 }
1888
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001889 sec_level = BT_SECURITY_MEDIUM;
1890 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001891 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001892 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03001893 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001894
Johan Hedbergba4e5642011-11-11 00:07:34 +02001895 if (cp->addr.type == MGMT_ADDR_BREDR)
1896 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr, sec_level,
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001897 auth_type);
1898 else
Johan Hedbergba4e5642011-11-11 00:07:34 +02001899 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr, sec_level,
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001900 auth_type);
1901
Johan Hedberg1425acb2011-11-11 00:07:35 +02001902 memset(&rp, 0, sizeof(rp));
1903 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1904 rp.addr.type = cp->addr.type;
1905
Ville Tervo30e76272011-02-22 16:10:53 -03001906 if (IS_ERR(conn)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001907 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Johan Hedberge2113262012-02-18 15:20:03 +02001908 MGMT_STATUS_CONNECT_FAILED,
1909 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001910 goto unlock;
1911 }
1912
1913 if (conn->connect_cfm_cb) {
1914 hci_conn_put(conn);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001915 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Johan Hedberge2113262012-02-18 15:20:03 +02001916 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001917 goto unlock;
1918 }
1919
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001920 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001921 if (!cmd) {
1922 err = -ENOMEM;
1923 hci_conn_put(conn);
1924 goto unlock;
1925 }
1926
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001927 /* For LE, just connecting isn't a proof that the pairing finished */
Johan Hedbergba4e5642011-11-11 00:07:34 +02001928 if (cp->addr.type == MGMT_ADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001929 conn->connect_cfm_cb = pairing_complete_cb;
1930
Johan Hedberge9a416b2011-02-19 12:05:56 -03001931 conn->security_cfm_cb = pairing_complete_cb;
1932 conn->disconn_cfm_cb = pairing_complete_cb;
1933 conn->io_capability = cp->io_cap;
1934 cmd->user_data = conn;
1935
1936 if (conn->state == BT_CONNECTED &&
1937 hci_conn_security(conn, sec_level, auth_type))
1938 pairing_complete(cmd, 0);
1939
1940 err = 0;
1941
1942unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001943 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001944 return err;
1945}
1946
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001947static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev,
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02001948 void *data, u16 len)
Johan Hedberg28424702012-02-02 04:02:29 +02001949{
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02001950 struct mgmt_addr_info *addr = data;
Johan Hedberg28424702012-02-02 04:02:29 +02001951 struct pending_cmd *cmd;
1952 struct hci_conn *conn;
1953 int err;
1954
1955 BT_DBG("");
1956
Johan Hedberg28424702012-02-02 04:02:29 +02001957 hci_dev_lock(hdev);
1958
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001959 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001960 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001961 MGMT_STATUS_NOT_POWERED);
1962 goto unlock;
1963 }
1964
Johan Hedberg28424702012-02-02 04:02:29 +02001965 cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
1966 if (!cmd) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001967 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Johan Hedberg28424702012-02-02 04:02:29 +02001968 MGMT_STATUS_INVALID_PARAMS);
1969 goto unlock;
1970 }
1971
1972 conn = cmd->user_data;
1973
1974 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001975 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Johan Hedberg28424702012-02-02 04:02:29 +02001976 MGMT_STATUS_INVALID_PARAMS);
1977 goto unlock;
1978 }
1979
1980 pairing_complete(cmd, MGMT_STATUS_CANCELLED);
1981
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001982 err = cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0,
1983 addr, sizeof(*addr));
Johan Hedberg28424702012-02-02 04:02:29 +02001984unlock:
1985 hci_dev_unlock(hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02001986 return err;
1987}
1988
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001989static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
1990 bdaddr_t *bdaddr, u8 type, u16 mgmt_op,
1991 u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03001992{
Johan Hedberga5c29682011-02-19 12:05:57 -03001993 struct pending_cmd *cmd;
Brian Gix0df4c182011-11-16 13:53:13 -08001994 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03001995 int err;
1996
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001997 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02001998
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001999 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002000 err = cmd_status(sk, hdev->id, mgmt_op,
2001 MGMT_STATUS_NOT_POWERED);
Brian Gix0df4c182011-11-16 13:53:13 -08002002 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002003 }
2004
Johan Hedberg272d90d2012-02-09 15:26:12 +02002005 if (type == MGMT_ADDR_BREDR)
2006 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, bdaddr);
2007 else
Brian Gix47c15e22011-11-16 13:53:14 -08002008 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, bdaddr);
Brian Gix47c15e22011-11-16 13:53:14 -08002009
Johan Hedberg272d90d2012-02-09 15:26:12 +02002010 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002011 err = cmd_status(sk, hdev->id, mgmt_op,
Johan Hedberg272d90d2012-02-09 15:26:12 +02002012 MGMT_STATUS_NOT_CONNECTED);
2013 goto done;
2014 }
2015
2016 if (type == MGMT_ADDR_LE_PUBLIC || type == MGMT_ADDR_LE_RANDOM) {
Brian Gix47c15e22011-11-16 13:53:14 -08002017 /* Continue with pairing via SMP */
Brian Gix5fe57d92011-12-21 16:12:13 -08002018 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix47c15e22011-11-16 13:53:14 -08002019
Brian Gix5fe57d92011-12-21 16:12:13 -08002020 if (!err)
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002021 err = cmd_status(sk, hdev->id, mgmt_op,
Brian Gix5fe57d92011-12-21 16:12:13 -08002022 MGMT_STATUS_SUCCESS);
2023 else
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002024 err = cmd_status(sk, hdev->id, mgmt_op,
Brian Gix5fe57d92011-12-21 16:12:13 -08002025 MGMT_STATUS_FAILED);
2026
Brian Gix47c15e22011-11-16 13:53:14 -08002027 goto done;
2028 }
2029
Brian Gix0df4c182011-11-16 13:53:13 -08002030 cmd = mgmt_pending_add(sk, mgmt_op, hdev, bdaddr, sizeof(*bdaddr));
Johan Hedberga5c29682011-02-19 12:05:57 -03002031 if (!cmd) {
2032 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08002033 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002034 }
2035
Brian Gix0df4c182011-11-16 13:53:13 -08002036 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08002037 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
2038 struct hci_cp_user_passkey_reply cp;
2039
2040 bacpy(&cp.bdaddr, bdaddr);
2041 cp.passkey = passkey;
2042 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
2043 } else
2044 err = hci_send_cmd(hdev, hci_op, sizeof(*bdaddr), bdaddr);
2045
Johan Hedberga664b5b2011-02-19 12:06:02 -03002046 if (err < 0)
2047 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002048
Brian Gix0df4c182011-11-16 13:53:13 -08002049done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002050 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002051 return err;
2052}
2053
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002054static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev,
2055 void *data, u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002056{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002057 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002058
2059 BT_DBG("");
2060
2061 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002062 return cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY,
Brian Gix0df4c182011-11-16 13:53:13 -08002063 MGMT_STATUS_INVALID_PARAMS);
2064
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002065 return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
Johan Hedberg272d90d2012-02-09 15:26:12 +02002066 MGMT_OP_USER_CONFIRM_REPLY,
2067 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002068}
2069
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002070static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev,
2071 void *data, u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002072{
Johan Hedbergc9c26592011-12-15 00:47:41 +02002073 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002074
2075 BT_DBG("");
2076
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002077 return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
Johan Hedberg272d90d2012-02-09 15:26:12 +02002078 MGMT_OP_USER_CONFIRM_NEG_REPLY,
2079 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002080}
2081
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002082static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev,
2083 void *data, u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002084{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002085 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002086
2087 BT_DBG("");
2088
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002089 return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
Johan Hedberg272d90d2012-02-09 15:26:12 +02002090 MGMT_OP_USER_PASSKEY_REPLY,
2091 HCI_OP_USER_PASSKEY_REPLY,
2092 cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08002093}
2094
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002095static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
2096 void *data, u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002097{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002098 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002099
2100 BT_DBG("");
2101
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002102 return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
Johan Hedberg272d90d2012-02-09 15:26:12 +02002103 MGMT_OP_USER_PASSKEY_NEG_REPLY,
2104 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08002105}
2106
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002107static int update_name(struct hci_dev *hdev, const char *name)
2108{
2109 struct hci_cp_write_local_name cp;
2110
2111 memcpy(cp.name, name, sizeof(cp.name));
2112
2113 return hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(cp), &cp);
2114}
2115
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002116static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
Johan Hedbergb312b1612011-03-16 14:29:37 +02002117 u16 len)
2118{
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002119 struct mgmt_cp_set_local_name *cp = data;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002120 struct pending_cmd *cmd;
2121 int err;
2122
2123 BT_DBG("");
2124
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002125 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002126
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002127 memcpy(hdev->short_name, cp->short_name, sizeof(hdev->short_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002128
Johan Hedbergb5235a62012-02-21 14:32:24 +02002129 if (!hdev_is_powered(hdev)) {
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002130 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002131
2132 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
2133 data, len);
2134 if (err < 0)
2135 goto failed;
2136
2137 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data, len,
2138 sk);
2139
Johan Hedbergb5235a62012-02-21 14:32:24 +02002140 goto failed;
2141 }
2142
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002143 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002144 if (!cmd) {
2145 err = -ENOMEM;
2146 goto failed;
2147 }
2148
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002149 err = update_name(hdev, cp->name);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002150 if (err < 0)
2151 mgmt_pending_remove(cmd);
2152
2153failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002154 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002155 return err;
2156}
2157
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002158static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
2159 void *data, u16 data_len)
Szymon Jancc35938b2011-03-22 13:12:21 +01002160{
Szymon Jancc35938b2011-03-22 13:12:21 +01002161 struct pending_cmd *cmd;
2162 int err;
2163
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002164 BT_DBG("%s", hdev->name);
Szymon Jancc35938b2011-03-22 13:12:21 +01002165
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002166 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002167
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002168 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002169 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002170 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002171 goto unlock;
2172 }
2173
2174 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002175 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002176 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002177 goto unlock;
2178 }
2179
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002180 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002181 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002182 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01002183 goto unlock;
2184 }
2185
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002186 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01002187 if (!cmd) {
2188 err = -ENOMEM;
2189 goto unlock;
2190 }
2191
2192 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
2193 if (err < 0)
2194 mgmt_pending_remove(cmd);
2195
2196unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002197 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002198 return err;
2199}
2200
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002201static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
2202 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002203{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002204 struct mgmt_cp_add_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002205 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002206 int err;
2207
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002208 BT_DBG("%s ", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01002209
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002210 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002211
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002212 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002213 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA,
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002214 MGMT_STATUS_NOT_POWERED,
2215 &cp->addr, sizeof(cp->addr));
2216 goto unlock;
2217 }
2218
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002219 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, cp->hash,
Szymon Janc2763eda2011-03-22 13:12:22 +01002220 cp->randomizer);
2221 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002222 status = MGMT_STATUS_FAILED;
Szymon Janc2763eda2011-03-22 13:12:22 +01002223 else
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002224 status = 0;
2225
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002226 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA, status,
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002227 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002228
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002229unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002230 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002231 return err;
2232}
2233
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002234static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002235 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002236{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002237 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002238 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002239 int err;
2240
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002241 BT_DBG("%s", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01002242
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002243 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002244
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002245 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002246 err = cmd_complete(sk, hdev->id,
2247 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2248 MGMT_STATUS_NOT_POWERED,
2249 &cp->addr, sizeof(cp->addr));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002250 goto unlock;
2251 }
2252
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002253 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr);
Szymon Janc2763eda2011-03-22 13:12:22 +01002254 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002255 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01002256 else
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002257 status = 0;
2258
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002259 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2260 status, &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002261
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002262unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002263 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002264 return err;
2265}
2266
Andre Guedes5e0452c2012-02-17 20:39:38 -03002267int mgmt_interleaved_discovery(struct hci_dev *hdev)
2268{
2269 int err;
2270
2271 BT_DBG("%s", hdev->name);
2272
2273 hci_dev_lock(hdev);
2274
2275 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR_LE);
2276 if (err < 0)
2277 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2278
2279 hci_dev_unlock(hdev);
2280
2281 return err;
2282}
2283
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002284static int start_discovery(struct sock *sk, struct hci_dev *hdev,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002285 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002286{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002287 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002288 struct pending_cmd *cmd;
Johan Hedberg14a53662011-04-27 10:29:56 -04002289 int err;
2290
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002291 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04002292
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002293 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002294
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002295 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002296 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Johan Hedbergca69b792011-11-11 18:10:00 +02002297 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02002298 goto failed;
2299 }
2300
Johan Hedbergff9ef572012-01-04 14:23:45 +02002301 if (hdev->discovery.state != DISCOVERY_STOPPED) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002302 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2303 MGMT_STATUS_BUSY);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002304 goto failed;
2305 }
2306
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002307 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002308 if (!cmd) {
2309 err = -ENOMEM;
2310 goto failed;
2311 }
2312
Andre Guedes4aab14e2012-02-17 20:39:36 -03002313 hdev->discovery.type = cp->type;
2314
2315 switch (hdev->discovery.type) {
Andre Guedesf39799f2012-02-17 20:39:35 -03002316 case DISCOV_TYPE_BREDR:
Andre Guedes8b901292012-02-23 18:09:27 -03002317 if (lmp_bredr_capable(hdev))
2318 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
2319 else
2320 err = -ENOTSUPP;
Andre Guedesf39799f2012-02-17 20:39:35 -03002321 break;
2322
2323 case DISCOV_TYPE_LE:
Andre Guedes8b901292012-02-23 18:09:27 -03002324 if (lmp_host_le_capable(hdev))
2325 err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT,
Andre Guedes3fd24152012-02-03 17:48:01 -03002326 LE_SCAN_WIN, LE_SCAN_TIMEOUT_LE_ONLY);
Andre Guedes8b901292012-02-23 18:09:27 -03002327 else
2328 err = -ENOTSUPP;
Andre Guedesf39799f2012-02-17 20:39:35 -03002329 break;
2330
Andre Guedes5e0452c2012-02-17 20:39:38 -03002331 case DISCOV_TYPE_INTERLEAVED:
Andre Guedes426c1892012-02-24 11:41:04 -03002332 if (lmp_host_le_capable(hdev) && lmp_bredr_capable(hdev))
2333 err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT,
2334 LE_SCAN_WIN, LE_SCAN_TIMEOUT_BREDR_LE);
2335 else
2336 err = -ENOTSUPP;
Andre Guedes5e0452c2012-02-17 20:39:38 -03002337 break;
2338
Andre Guedesf39799f2012-02-17 20:39:35 -03002339 default:
Andre Guedes3fd24152012-02-03 17:48:01 -03002340 err = -EINVAL;
Andre Guedesf39799f2012-02-17 20:39:35 -03002341 }
Andre Guedes3fd24152012-02-03 17:48:01 -03002342
Johan Hedberg14a53662011-04-27 10:29:56 -04002343 if (err < 0)
2344 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002345 else
2346 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002347
2348failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002349 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002350 return err;
2351}
2352
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002353static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
2354 u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002355{
Johan Hedbergd9306502012-02-20 23:25:18 +02002356 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002357 struct pending_cmd *cmd;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002358 struct hci_cp_remote_name_req_cancel cp;
2359 struct inquiry_entry *e;
Johan Hedberg14a53662011-04-27 10:29:56 -04002360 int err;
2361
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002362 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04002363
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002364 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002365
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002366 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002367 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Johan Hedbergd9306502012-02-20 23:25:18 +02002368 MGMT_STATUS_REJECTED,
2369 &mgmt_cp->type, sizeof(mgmt_cp->type));
2370 goto unlock;
2371 }
2372
2373 if (hdev->discovery.type != mgmt_cp->type) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002374 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Johan Hedbergd9306502012-02-20 23:25:18 +02002375 MGMT_STATUS_INVALID_PARAMS,
2376 &mgmt_cp->type, sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002377 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02002378 }
2379
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002380 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002381 if (!cmd) {
2382 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002383 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04002384 }
2385
Andre Guedes343f9352012-02-17 20:39:37 -03002386 if (hdev->discovery.state == DISCOVERY_FINDING) {
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002387 err = hci_cancel_inquiry(hdev);
2388 if (err < 0)
2389 mgmt_pending_remove(cmd);
2390 else
2391 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
2392 goto unlock;
2393 }
2394
2395 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY, NAME_PENDING);
2396 if (!e) {
2397 mgmt_pending_remove(cmd);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002398 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY, 0,
Johan Hedbergd9306502012-02-20 23:25:18 +02002399 &mgmt_cp->type, sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002400 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2401 goto unlock;
2402 }
2403
2404 bacpy(&cp.bdaddr, &e->data.bdaddr);
2405 err = hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ_CANCEL,
2406 sizeof(cp), &cp);
Johan Hedberg14a53662011-04-27 10:29:56 -04002407 if (err < 0)
2408 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002409 else
2410 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002411
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002412unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002413 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002414 return err;
2415}
2416
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002417static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
2418 u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02002419{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002420 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002421 struct inquiry_entry *e;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002422 int err;
2423
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002424 BT_DBG("%s", hdev->name);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002425
Johan Hedberg561aafb2012-01-04 13:31:59 +02002426 hci_dev_lock(hdev);
2427
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002428 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002429 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002430 MGMT_STATUS_FAILED);
2431 goto failed;
2432 }
2433
Johan Hedberga198e7b2012-02-17 14:27:06 +02002434 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002435 if (!e) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002436 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
2437 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002438 goto failed;
2439 }
2440
2441 if (cp->name_known) {
2442 e->name_state = NAME_KNOWN;
2443 list_del(&e->list);
2444 } else {
2445 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e202012-01-09 00:53:02 +02002446 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002447 }
2448
2449 err = 0;
2450
2451failed:
2452 hci_dev_unlock(hdev);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002453 return err;
2454}
2455
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002456static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
2457 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002458{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002459 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002460 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03002461 int err;
2462
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002463 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03002464
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002465 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002466
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002467 err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002468 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002469 status = MGMT_STATUS_FAILED;
Antti Julku7fbec222011-06-15 12:01:15 +03002470 else
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002471 status = 0;
2472
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002473 err = cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status,
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002474 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03002475
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002476 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002477
2478 return err;
2479}
2480
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002481static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
2482 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002483{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002484 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002485 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03002486 int err;
2487
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002488 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03002489
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002490 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002491
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002492 err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002493 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002494 status = MGMT_STATUS_INVALID_PARAMS;
Antti Julku7fbec222011-06-15 12:01:15 +03002495 else
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002496 status = 0;
2497
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002498 err = cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status,
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002499 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03002500
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002501 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002502
2503 return err;
2504}
2505
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002506static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
2507 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03002508{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002509 struct mgmt_mode *cp = data;
Antti Julkuf6422ec2011-06-22 13:11:56 +03002510 struct hci_cp_write_page_scan_activity acp;
2511 u8 type;
2512 int err;
2513
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002514 BT_DBG("%s", hdev->name);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002515
Johan Hedberg5400c042012-02-21 16:40:33 +02002516 if (!hdev_is_powered(hdev))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002517 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedberg5400c042012-02-21 16:40:33 +02002518 MGMT_STATUS_NOT_POWERED);
2519
2520 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002521 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
2522 MGMT_STATUS_REJECTED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002523
2524 hci_dev_lock(hdev);
2525
Johan Hedbergf7c6869ce2011-12-15 00:47:36 +02002526 if (cp->val) {
Antti Julkuf6422ec2011-06-22 13:11:56 +03002527 type = PAGE_SCAN_TYPE_INTERLACED;
2528 acp.interval = 0x0024; /* 22.5 msec page scan interval */
2529 } else {
2530 type = PAGE_SCAN_TYPE_STANDARD; /* default */
2531 acp.interval = 0x0800; /* default 1.28 sec page scan */
2532 }
2533
2534 acp.window = 0x0012; /* default 11.25 msec page scan window */
2535
2536 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
2537 sizeof(acp), &acp);
2538 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002539 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
2540 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002541 goto done;
2542 }
2543
2544 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
2545 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002546 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
2547 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002548 goto done;
2549 }
2550
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002551 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE, 0,
Johan Hedbergaee9b212012-02-18 15:07:59 +02002552 NULL, 0);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002553done:
2554 hci_dev_unlock(hdev);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002555 return err;
2556}
2557
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002558static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002559 void *cp_data, u16 len)
2560{
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002561 struct mgmt_cp_load_long_term_keys *cp = cp_data;
2562 u16 key_count, expected_len;
2563 int i;
2564
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002565 key_count = get_unaligned_le16(&cp->key_count);
2566
2567 expected_len = sizeof(*cp) + key_count *
2568 sizeof(struct mgmt_ltk_info);
2569 if (expected_len != len) {
2570 BT_ERR("load_keys: expected %u bytes, got %u bytes",
2571 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002572 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002573 EINVAL);
2574 }
2575
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002576 BT_DBG("%s key_count %u", hdev->name, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002577
2578 hci_dev_lock(hdev);
2579
2580 hci_smp_ltks_clear(hdev);
2581
2582 for (i = 0; i < key_count; i++) {
2583 struct mgmt_ltk_info *key = &cp->keys[i];
2584 u8 type;
2585
2586 if (key->master)
2587 type = HCI_SMP_LTK;
2588 else
2589 type = HCI_SMP_LTK_SLAVE;
2590
2591 hci_add_ltk(hdev, &key->addr.bdaddr, key->addr.type,
2592 type, 0, key->authenticated, key->val,
2593 key->enc_size, key->ediv, key->rand);
2594 }
2595
2596 hci_dev_unlock(hdev);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002597
2598 return 0;
2599}
2600
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002601struct mgmt_handler {
2602 int (*func) (struct sock *sk, struct hci_dev *hdev,
2603 void *data, u16 data_len);
Johan Hedbergbe22b542012-03-01 22:24:41 +02002604 bool var_len;
2605 size_t data_len;
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002606} mgmt_handlers[] = {
2607 { NULL }, /* 0x0000 (no command) */
Johan Hedbergbe22b542012-03-01 22:24:41 +02002608 { read_version, false, MGMT_READ_VERSION_SIZE },
2609 { read_commands, false, MGMT_READ_COMMANDS_SIZE },
2610 { read_index_list, false, MGMT_READ_INDEX_LIST_SIZE },
2611 { read_controller_info, false, MGMT_READ_INFO_SIZE },
2612 { set_powered, false, MGMT_SETTING_SIZE },
2613 { set_discoverable, false, MGMT_SET_DISCOVERABLE_SIZE },
2614 { set_connectable, false, MGMT_SETTING_SIZE },
2615 { set_fast_connectable, false, MGMT_SETTING_SIZE },
2616 { set_pairable, false, MGMT_SETTING_SIZE },
2617 { set_link_security, false, MGMT_SETTING_SIZE },
2618 { set_ssp, false, MGMT_SETTING_SIZE },
2619 { set_hs, false, MGMT_SETTING_SIZE },
2620 { set_le, false, MGMT_SETTING_SIZE },
2621 { set_dev_class, false, MGMT_SET_DEV_CLASS_SIZE },
2622 { set_local_name, false, MGMT_SET_LOCAL_NAME_SIZE },
2623 { add_uuid, false, MGMT_ADD_UUID_SIZE },
2624 { remove_uuid, false, MGMT_REMOVE_UUID_SIZE },
2625 { load_link_keys, true, MGMT_LOAD_LINK_KEYS_SIZE },
2626 { load_long_term_keys, true, MGMT_LOAD_LONG_TERM_KEYS_SIZE },
2627 { disconnect, false, MGMT_DISCONNECT_SIZE },
2628 { get_connections, false, MGMT_GET_CONNECTIONS_SIZE },
2629 { pin_code_reply, false, MGMT_PIN_CODE_REPLY_SIZE },
2630 { pin_code_neg_reply, false, MGMT_PIN_CODE_NEG_REPLY_SIZE },
2631 { set_io_capability, false, MGMT_SET_IO_CAPABILITY_SIZE },
2632 { pair_device, false, MGMT_PAIR_DEVICE_SIZE },
2633 { cancel_pair_device, false, MGMT_CANCEL_PAIR_DEVICE_SIZE },
2634 { unpair_device, false, MGMT_UNPAIR_DEVICE_SIZE },
2635 { user_confirm_reply, false, MGMT_USER_CONFIRM_REPLY_SIZE },
2636 { user_confirm_neg_reply, false, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
2637 { user_passkey_reply, false, MGMT_USER_PASSKEY_REPLY_SIZE },
2638 { user_passkey_neg_reply, false, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
2639 { read_local_oob_data, false, MGMT_READ_LOCAL_OOB_DATA_SIZE },
2640 { add_remote_oob_data, false, MGMT_ADD_REMOTE_OOB_DATA_SIZE },
2641 { remove_remote_oob_data, false, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
2642 { start_discovery, false, MGMT_START_DISCOVERY_SIZE },
2643 { stop_discovery, false, MGMT_STOP_DISCOVERY_SIZE },
2644 { confirm_name, false, MGMT_CONFIRM_NAME_SIZE },
2645 { block_device, false, MGMT_BLOCK_DEVICE_SIZE },
2646 { unblock_device, false, MGMT_UNBLOCK_DEVICE_SIZE },
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002647};
2648
2649
Johan Hedberg03811012010-12-08 00:21:06 +02002650int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
2651{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002652 void *buf;
2653 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02002654 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002655 u16 opcode, index, len;
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002656 struct hci_dev *hdev = NULL;
Johan Hedbergbe22b542012-03-01 22:24:41 +02002657 struct mgmt_handler *handler;
Johan Hedberg03811012010-12-08 00:21:06 +02002658 int err;
2659
2660 BT_DBG("got %zu bytes", msglen);
2661
2662 if (msglen < sizeof(*hdr))
2663 return -EINVAL;
2664
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03002665 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02002666 if (!buf)
2667 return -ENOMEM;
2668
2669 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
2670 err = -EFAULT;
2671 goto done;
2672 }
2673
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002674 hdr = buf;
Johan Hedberg03811012010-12-08 00:21:06 +02002675 opcode = get_unaligned_le16(&hdr->opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002676 index = get_unaligned_le16(&hdr->index);
Johan Hedberg03811012010-12-08 00:21:06 +02002677 len = get_unaligned_le16(&hdr->len);
2678
2679 if (len != msglen - sizeof(*hdr)) {
2680 err = -EINVAL;
2681 goto done;
2682 }
2683
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002684 if (index != MGMT_INDEX_NONE) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002685 hdev = hci_dev_get(index);
2686 if (!hdev) {
2687 err = cmd_status(sk, index, opcode,
Johan Hedberg5f159032012-03-02 03:13:19 +02002688 MGMT_STATUS_INVALID_INDEX);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002689 goto done;
2690 }
2691 }
2692
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002693 if (opcode >= ARRAY_SIZE(mgmt_handlers) ||
2694 mgmt_handlers[opcode].func == NULL) {
Johan Hedberg03811012010-12-08 00:21:06 +02002695 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02002696 err = cmd_status(sk, index, opcode,
2697 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002698 goto done;
Johan Hedberg03811012010-12-08 00:21:06 +02002699 }
2700
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002701 if ((hdev && opcode < MGMT_OP_READ_INFO) ||
2702 (!hdev && opcode >= MGMT_OP_READ_INFO)) {
2703 err = cmd_status(sk, index, opcode,
Johan Hedberg5f159032012-03-02 03:13:19 +02002704 MGMT_STATUS_INVALID_INDEX);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002705 goto done;
2706 }
2707
Johan Hedbergbe22b542012-03-01 22:24:41 +02002708 handler = &mgmt_handlers[opcode];
2709
2710 if ((handler->var_len && len < handler->data_len) ||
2711 (!handler->var_len && len != handler->data_len)) {
2712 err = cmd_status(sk, index, opcode,
2713 MGMT_STATUS_INVALID_PARAMS);
2714 goto done;
2715 }
2716
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002717 if (hdev)
2718 mgmt_init_hdev(sk, hdev);
2719
2720 cp = buf + sizeof(*hdr);
2721
Johan Hedbergbe22b542012-03-01 22:24:41 +02002722 err = handler->func(sk, hdev, cp, len);
Johan Hedberge41d8b42010-12-13 21:07:03 +02002723 if (err < 0)
2724 goto done;
2725
Johan Hedberg03811012010-12-08 00:21:06 +02002726 err = msglen;
2727
2728done:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002729 if (hdev)
2730 hci_dev_put(hdev);
2731
Johan Hedberg03811012010-12-08 00:21:06 +02002732 kfree(buf);
2733 return err;
2734}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002735
Johan Hedbergb24752f2011-11-03 14:40:33 +02002736static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
2737{
2738 u8 *status = data;
2739
2740 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
2741 mgmt_pending_remove(cmd);
2742}
2743
Johan Hedberg744cf192011-11-08 20:40:14 +02002744int mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002745{
Johan Hedberg744cf192011-11-08 20:40:14 +02002746 return mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002747}
2748
Johan Hedberg744cf192011-11-08 20:40:14 +02002749int mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002750{
Johan Hedberg5f159032012-03-02 03:13:19 +02002751 u8 status = MGMT_STATUS_INVALID_INDEX;
Johan Hedbergb24752f2011-11-03 14:40:33 +02002752
Johan Hedberg744cf192011-11-08 20:40:14 +02002753 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002754
Johan Hedberg744cf192011-11-08 20:40:14 +02002755 return mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002756}
2757
Johan Hedberg73f22f62010-12-29 16:00:25 +02002758struct cmd_lookup {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002759 struct sock *sk;
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002760 struct hci_dev *hdev;
Johan Hedberg90e70452012-02-23 23:09:40 +02002761 u8 mgmt_status;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002762};
2763
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002764static void settings_rsp(struct pending_cmd *cmd, void *data)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002765{
Johan Hedberg73f22f62010-12-29 16:00:25 +02002766 struct cmd_lookup *match = data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002767
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002768 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002769
2770 list_del(&cmd->list);
2771
2772 if (match->sk == NULL) {
2773 match->sk = cmd->sk;
2774 sock_hold(match->sk);
2775 }
2776
2777 mgmt_pending_free(cmd);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002778}
Johan Hedberg5add6af2010-12-16 10:00:37 +02002779
Johan Hedberg744cf192011-11-08 20:40:14 +02002780int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg5add6af2010-12-16 10:00:37 +02002781{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002782 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002783 int err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002784
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002785 if (!test_bit(HCI_MGMT, &hdev->dev_flags))
2786 return 0;
2787
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002788 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
Johan Hedberg5add6af2010-12-16 10:00:37 +02002789
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002790 if (powered) {
2791 u8 scan = 0;
2792
2793 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
2794 scan |= SCAN_PAGE;
2795 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
2796 scan |= SCAN_INQUIRY;
2797
2798 if (scan)
2799 hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
Johan Hedberg504c8dc2012-02-23 13:30:41 +02002800
2801 update_class(hdev);
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002802 update_name(hdev, hdev->dev_name);
Johan Hedberg504c8dc2012-02-23 13:30:41 +02002803 update_eir(hdev);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002804 } else {
Johan Hedbergd4f68522012-03-02 03:07:07 +02002805 u8 status = MGMT_STATUS_NOT_POWERED;
Johan Hedberg744cf192011-11-08 20:40:14 +02002806 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002807 }
2808
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02002809 err = new_settings(hdev, match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002810
2811 if (match.sk)
2812 sock_put(match.sk);
2813
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002814 return err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002815}
Johan Hedberg73f22f62010-12-29 16:00:25 +02002816
Johan Hedberg744cf192011-11-08 20:40:14 +02002817int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg73f22f62010-12-29 16:00:25 +02002818{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002819 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002820 bool changed = false;
2821 int err = 0;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002822
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002823 if (discoverable) {
2824 if (!test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
2825 changed = true;
2826 } else {
2827 if (test_and_clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
2828 changed = true;
2829 }
Johan Hedberg73f22f62010-12-29 16:00:25 +02002830
Johan Hedberged9b5f22012-02-21 20:47:06 +02002831 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp,
2832 &match);
2833
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02002834 if (changed)
2835 err = new_settings(hdev, match.sk);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002836
Johan Hedberg73f22f62010-12-29 16:00:25 +02002837 if (match.sk)
2838 sock_put(match.sk);
2839
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002840 return err;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002841}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002842
Johan Hedberg744cf192011-11-08 20:40:14 +02002843int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002844{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002845 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002846 bool changed = false;
2847 int err = 0;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002848
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002849 if (connectable) {
2850 if (!test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags))
2851 changed = true;
2852 } else {
2853 if (test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags))
2854 changed = true;
2855 }
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002856
Johan Hedberged9b5f22012-02-21 20:47:06 +02002857 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev, settings_rsp,
2858 &match);
2859
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02002860 if (changed)
2861 err = new_settings(hdev, match.sk);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002862
2863 if (match.sk)
2864 sock_put(match.sk);
2865
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002866 return err;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002867}
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002868
Johan Hedberg744cf192011-11-08 20:40:14 +02002869int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002870{
Johan Hedbergca69b792011-11-11 18:10:00 +02002871 u8 mgmt_err = mgmt_status(status);
2872
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002873 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02002874 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Johan Hedbergca69b792011-11-11 18:10:00 +02002875 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002876
2877 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02002878 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Johan Hedbergca69b792011-11-11 18:10:00 +02002879 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002880
2881 return 0;
2882}
2883
Johan Hedberg744cf192011-11-08 20:40:14 +02002884int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
2885 u8 persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002886{
Johan Hedberg86742e12011-11-07 23:13:38 +02002887 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002888
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002889 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002890
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002891 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02002892 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
2893 ev.key.addr.type = MGMT_ADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002894 ev.key.type = key->type;
2895 memcpy(ev.key.val, key->val, 16);
2896 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002897
Johan Hedberg744cf192011-11-08 20:40:14 +02002898 return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002899}
Johan Hedbergf7520542011-01-20 12:34:39 +02002900
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002901int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
2902{
2903 struct mgmt_ev_new_long_term_key ev;
2904
2905 memset(&ev, 0, sizeof(ev));
2906
2907 ev.store_hint = persistent;
2908 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
2909 ev.key.addr.type = key->bdaddr_type;
2910 ev.key.authenticated = key->authenticated;
2911 ev.key.enc_size = key->enc_size;
2912 ev.key.ediv = key->ediv;
2913
2914 if (key->type == HCI_SMP_LTK)
2915 ev.key.master = 1;
2916
2917 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
2918 memcpy(ev.key.val, key->val, sizeof(key->val));
2919
2920 return mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev,
2921 &ev, sizeof(ev), NULL);
2922}
2923
Johan Hedbergafc747a2012-01-15 18:11:07 +02002924int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Johan Hedberg08c79b62012-02-23 22:31:51 +02002925 u8 addr_type, u32 flags, u8 *name,
2926 u8 name_len, u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02002927{
Johan Hedbergb644ba32012-01-17 21:48:47 +02002928 char buf[512];
2929 struct mgmt_ev_device_connected *ev = (void *) buf;
2930 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02002931
Johan Hedbergb644ba32012-01-17 21:48:47 +02002932 bacpy(&ev->addr.bdaddr, bdaddr);
2933 ev->addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02002934
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02002935 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02002936
Johan Hedbergb644ba32012-01-17 21:48:47 +02002937 if (name_len > 0)
2938 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
2939 name, name_len);
2940
2941 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
2942 eir_len = eir_append_data(&ev->eir[eir_len], eir_len,
2943 EIR_CLASS_OF_DEV, dev_class, 3);
2944
2945 put_unaligned_le16(eir_len, &ev->eir_len);
2946
2947 return mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
2948 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02002949}
2950
Johan Hedberg8962ee72011-01-20 12:40:27 +02002951static void disconnect_rsp(struct pending_cmd *cmd, void *data)
2952{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01002953 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002954 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02002955 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002956
Johan Hedberg88c3df12012-02-09 14:27:38 +02002957 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2958 rp.addr.type = cp->addr.type;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002959
Johan Hedbergaee9b212012-02-18 15:07:59 +02002960 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, 0, &rp,
2961 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002962
2963 *sk = cmd->sk;
2964 sock_hold(*sk);
2965
Johan Hedberga664b5b2011-02-19 12:06:02 -03002966 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002967}
2968
Johan Hedberg124f6e32012-02-09 13:50:12 +02002969static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02002970{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002971 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02002972 struct mgmt_cp_unpair_device *cp = cmd->param;
2973 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002974
2975 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02002976 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2977 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002978
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002979 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
2980
Johan Hedbergaee9b212012-02-18 15:07:59 +02002981 cmd_complete(cmd->sk, cmd->index, cmd->opcode, 0, &rp, sizeof(rp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02002982
2983 mgmt_pending_remove(cmd);
2984}
2985
Johan Hedbergafc747a2012-01-15 18:11:07 +02002986int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
2987 u8 link_type, u8 addr_type)
Johan Hedbergf7520542011-01-20 12:34:39 +02002988{
Johan Hedberg4c659c32011-11-07 23:13:39 +02002989 struct mgmt_addr_info ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002990 struct sock *sk = NULL;
2991 int err;
2992
Johan Hedberg744cf192011-11-08 20:40:14 +02002993 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02002994
Johan Hedbergf7520542011-01-20 12:34:39 +02002995 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02002996 ev.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02002997
Johan Hedbergafc747a2012-01-15 18:11:07 +02002998 err = mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev),
2999 sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003000
3001 if (sk)
3002 sock_put(sk);
3003
Johan Hedberg124f6e32012-02-09 13:50:12 +02003004 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003005 hdev);
Johan Hedberga8a1d192011-11-10 15:54:38 +02003006
Johan Hedberg8962ee72011-01-20 12:40:27 +02003007 return err;
3008}
3009
Johan Hedberg88c3df12012-02-09 14:27:38 +02003010int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
3011 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02003012{
Johan Hedberg88c3df12012-02-09 14:27:38 +02003013 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003014 struct pending_cmd *cmd;
3015 int err;
3016
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003017 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003018 if (!cmd)
3019 return -ENOENT;
3020
Johan Hedberg88c3df12012-02-09 14:27:38 +02003021 bacpy(&rp.addr.bdaddr, bdaddr);
3022 rp.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02003023
Johan Hedberg88c3df12012-02-09 14:27:38 +02003024 err = cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
Johan Hedbergaee9b212012-02-18 15:07:59 +02003025 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003026
Johan Hedberga664b5b2011-02-19 12:06:02 -03003027 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003028
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003029 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
3030 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003031 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02003032}
Johan Hedberg17d5c042011-01-22 06:09:08 +02003033
Johan Hedberg48264f02011-11-09 13:58:58 +02003034int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
3035 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02003036{
3037 struct mgmt_ev_connect_failed ev;
3038
Johan Hedberg4c659c32011-11-07 23:13:39 +02003039 bacpy(&ev.addr.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02003040 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003041 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003042
Johan Hedberg744cf192011-11-08 20:40:14 +02003043 return mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003044}
Johan Hedberg980e1a52011-01-22 06:10:07 +02003045
Johan Hedberg744cf192011-11-08 20:40:14 +02003046int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003047{
3048 struct mgmt_ev_pin_code_request ev;
3049
Johan Hedbergd8457692012-02-17 14:24:57 +02003050 bacpy(&ev.addr.bdaddr, bdaddr);
3051 ev.addr.type = MGMT_ADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02003052 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003053
Johan Hedberg744cf192011-11-08 20:40:14 +02003054 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01003055 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003056}
3057
Johan Hedberg744cf192011-11-08 20:40:14 +02003058int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3059 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003060{
3061 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003062 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003063 int err;
3064
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003065 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003066 if (!cmd)
3067 return -ENOENT;
3068
Johan Hedbergd8457692012-02-17 14:24:57 +02003069 bacpy(&rp.addr.bdaddr, bdaddr);
3070 rp.addr.type = MGMT_ADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003071
Johan Hedbergaee9b212012-02-18 15:07:59 +02003072 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
3073 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003074
Johan Hedberga664b5b2011-02-19 12:06:02 -03003075 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003076
3077 return err;
3078}
3079
Johan Hedberg744cf192011-11-08 20:40:14 +02003080int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3081 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003082{
3083 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003084 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003085 int err;
3086
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003087 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003088 if (!cmd)
3089 return -ENOENT;
3090
Johan Hedbergd8457692012-02-17 14:24:57 +02003091 bacpy(&rp.addr.bdaddr, bdaddr);
3092 rp.addr.type = MGMT_ADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003093
Johan Hedbergaee9b212012-02-18 15:07:59 +02003094 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
3095 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003096
Johan Hedberga664b5b2011-02-19 12:06:02 -03003097 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003098
3099 return err;
3100}
Johan Hedberga5c29682011-02-19 12:05:57 -03003101
Johan Hedberg744cf192011-11-08 20:40:14 +02003102int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003103 u8 link_type, u8 addr_type, __le32 value,
3104 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03003105{
3106 struct mgmt_ev_user_confirm_request ev;
3107
Johan Hedberg744cf192011-11-08 20:40:14 +02003108 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03003109
Johan Hedberg272d90d2012-02-09 15:26:12 +02003110 bacpy(&ev.addr.bdaddr, bdaddr);
3111 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07003112 ev.confirm_hint = confirm_hint;
Johan Hedberga5c29682011-02-19 12:05:57 -03003113 put_unaligned_le32(value, &ev.value);
3114
Johan Hedberg744cf192011-11-08 20:40:14 +02003115 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01003116 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03003117}
3118
Johan Hedberg272d90d2012-02-09 15:26:12 +02003119int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
3120 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08003121{
3122 struct mgmt_ev_user_passkey_request ev;
3123
3124 BT_DBG("%s", hdev->name);
3125
Johan Hedberg272d90d2012-02-09 15:26:12 +02003126 bacpy(&ev.addr.bdaddr, bdaddr);
3127 ev.addr.type = link_to_mgmt(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08003128
3129 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
3130 NULL);
3131}
3132
Brian Gix0df4c182011-11-16 13:53:13 -08003133static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003134 u8 link_type, u8 addr_type, u8 status,
3135 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03003136{
3137 struct pending_cmd *cmd;
3138 struct mgmt_rp_user_confirm_reply rp;
3139 int err;
3140
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003141 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03003142 if (!cmd)
3143 return -ENOENT;
3144
Johan Hedberg272d90d2012-02-09 15:26:12 +02003145 bacpy(&rp.addr.bdaddr, bdaddr);
3146 rp.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergaee9b212012-02-18 15:07:59 +02003147 err = cmd_complete(cmd->sk, hdev->id, opcode, mgmt_status(status),
3148 &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03003149
Johan Hedberga664b5b2011-02-19 12:06:02 -03003150 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03003151
3152 return err;
3153}
3154
Johan Hedberg744cf192011-11-08 20:40:14 +02003155int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003156 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003157{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003158 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3159 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003160}
3161
Johan Hedberg272d90d2012-02-09 15:26:12 +02003162int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3163 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003164{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003165 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3166 status, MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003167}
Johan Hedberg2a611692011-02-19 12:06:00 -03003168
Brian Gix604086b2011-11-23 08:28:33 -08003169int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003170 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003171{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003172 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3173 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003174}
3175
Johan Hedberg272d90d2012-02-09 15:26:12 +02003176int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3177 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003178{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003179 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3180 status, MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003181}
3182
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003183int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
3184 u8 addr_type, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03003185{
3186 struct mgmt_ev_auth_failed ev;
3187
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003188 bacpy(&ev.addr.bdaddr, bdaddr);
3189 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003190 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03003191
Johan Hedberg744cf192011-11-08 20:40:14 +02003192 return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03003193}
Johan Hedbergb312b1612011-03-16 14:29:37 +02003194
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003195int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
3196{
3197 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg47990ea2012-02-22 11:58:37 +02003198 bool changed = false;
3199 int err = 0;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003200
3201 if (status) {
3202 u8 mgmt_err = mgmt_status(status);
3203 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
3204 cmd_status_rsp, &mgmt_err);
3205 return 0;
3206 }
3207
Johan Hedberg47990ea2012-02-22 11:58:37 +02003208 if (test_bit(HCI_AUTH, &hdev->flags)) {
3209 if (!test_and_set_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
3210 changed = true;
3211 } else {
3212 if (test_and_clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
3213 changed = true;
3214 }
3215
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003216 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
3217 &match);
3218
Johan Hedberg47990ea2012-02-22 11:58:37 +02003219 if (changed)
3220 err = new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003221
3222 if (match.sk)
3223 sock_put(match.sk);
3224
3225 return err;
3226}
3227
Johan Hedbergcacaf522012-02-21 00:52:42 +02003228static int clear_eir(struct hci_dev *hdev)
3229{
3230 struct hci_cp_write_eir cp;
3231
3232 if (!(hdev->features[6] & LMP_EXT_INQ))
3233 return 0;
3234
Johan Hedbergc80da272012-02-22 15:38:48 +02003235 memset(hdev->eir, 0, sizeof(hdev->eir));
3236
Johan Hedbergcacaf522012-02-21 00:52:42 +02003237 memset(&cp, 0, sizeof(cp));
3238
3239 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
3240}
3241
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003242int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003243{
3244 struct cmd_lookup match = { NULL, hdev };
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003245 bool changed = false;
3246 int err = 0;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003247
3248 if (status) {
3249 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003250
3251 if (enable && test_and_clear_bit(HCI_SSP_ENABLED,
3252 &hdev->dev_flags))
3253 err = new_settings(hdev, NULL);
3254
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003255 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev,
3256 cmd_status_rsp, &mgmt_err);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003257
3258 return err;
3259 }
3260
3261 if (enable) {
3262 if (!test_and_set_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3263 changed = true;
3264 } else {
3265 if (test_and_clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3266 changed = true;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003267 }
3268
3269 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
3270
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003271 if (changed)
3272 err = new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003273
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02003274 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003275 sock_put(match.sk);
3276
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02003277 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3278 update_eir(hdev);
3279 else
3280 clear_eir(hdev);
Johan Hedbergcacaf522012-02-21 00:52:42 +02003281
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003282 return err;
3283}
3284
Johan Hedberg90e70452012-02-23 23:09:40 +02003285static void class_rsp(struct pending_cmd *cmd, void *data)
3286{
3287 struct cmd_lookup *match = data;
3288
3289 cmd_complete(cmd->sk, cmd->index, cmd->opcode, match->mgmt_status,
3290 match->hdev->dev_class, 3);
3291
3292 list_del(&cmd->list);
3293
3294 if (match->sk == NULL) {
3295 match->sk = cmd->sk;
3296 sock_hold(match->sk);
3297 }
3298
3299 mgmt_pending_free(cmd);
3300}
3301
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003302int mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
3303 u8 status)
3304{
Johan Hedberg90e70452012-02-23 23:09:40 +02003305 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
3306 int err = 0;
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003307
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02003308 clear_bit(HCI_PENDING_CLASS, &hdev->dev_flags);
3309
Johan Hedberg90e70452012-02-23 23:09:40 +02003310 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, class_rsp, &match);
3311 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, class_rsp, &match);
3312 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, class_rsp, &match);
3313
3314 if (!status)
3315 err = mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
3316 dev_class, 3, NULL);
3317
3318 if (match.sk)
3319 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003320
3321 return err;
3322}
3323
Johan Hedberg744cf192011-11-08 20:40:14 +02003324int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02003325{
3326 struct pending_cmd *cmd;
3327 struct mgmt_cp_set_local_name ev;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003328 bool changed = false;
3329 int err = 0;
3330
3331 if (memcmp(name, hdev->dev_name, sizeof(hdev->dev_name)) != 0) {
3332 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
3333 changed = true;
3334 }
Johan Hedbergb312b1612011-03-16 14:29:37 +02003335
3336 memset(&ev, 0, sizeof(ev));
3337 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003338 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003339
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003340 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003341 if (!cmd)
3342 goto send_event;
3343
Johan Hedberg7bdaae42012-02-22 21:39:58 +02003344 /* Always assume that either the short or the complete name has
3345 * changed if there was a pending mgmt command */
3346 changed = true;
3347
Johan Hedbergb312b1612011-03-16 14:29:37 +02003348 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02003349 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
Johan Hedbergca69b792011-11-11 18:10:00 +02003350 mgmt_status(status));
Johan Hedbergb312b1612011-03-16 14:29:37 +02003351 goto failed;
3352 }
3353
Johan Hedbergaee9b212012-02-18 15:07:59 +02003354 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0, &ev,
Johan Hedbergb312b1612011-03-16 14:29:37 +02003355 sizeof(ev));
3356 if (err < 0)
3357 goto failed;
3358
3359send_event:
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003360 if (changed)
3361 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev,
3362 sizeof(ev), cmd ? cmd->sk : NULL);
3363
Johan Hedbergf51d5b22012-02-22 18:17:32 +02003364 update_eir(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003365
3366failed:
3367 if (cmd)
3368 mgmt_pending_remove(cmd);
3369 return err;
3370}
Szymon Jancc35938b2011-03-22 13:12:21 +01003371
Johan Hedberg744cf192011-11-08 20:40:14 +02003372int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
3373 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01003374{
3375 struct pending_cmd *cmd;
3376 int err;
3377
Johan Hedberg744cf192011-11-08 20:40:14 +02003378 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01003379
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003380 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003381 if (!cmd)
3382 return -ENOENT;
3383
3384 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02003385 err = cmd_status(cmd->sk, hdev->id,
Johan Hedbergca69b792011-11-11 18:10:00 +02003386 MGMT_OP_READ_LOCAL_OOB_DATA,
3387 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01003388 } else {
3389 struct mgmt_rp_read_local_oob_data rp;
3390
3391 memcpy(rp.hash, hash, sizeof(rp.hash));
3392 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
3393
Johan Hedberg744cf192011-11-08 20:40:14 +02003394 err = cmd_complete(cmd->sk, hdev->id,
3395 MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergaee9b212012-02-18 15:07:59 +02003396 0, &rp, sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01003397 }
3398
3399 mgmt_pending_remove(cmd);
3400
3401 return err;
3402}
Johan Hedberge17acd42011-03-30 23:57:16 +03003403
Johan Hedberg06199cf2012-02-22 16:37:11 +02003404int mgmt_le_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
3405{
3406 struct cmd_lookup match = { NULL, hdev };
3407 bool changed = false;
3408 int err = 0;
3409
3410 if (status) {
3411 u8 mgmt_err = mgmt_status(status);
3412
3413 if (enable && test_and_clear_bit(HCI_LE_ENABLED,
3414 &hdev->dev_flags))
3415 err = new_settings(hdev, NULL);
3416
3417 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev,
3418 cmd_status_rsp, &mgmt_err);
3419
3420 return err;
3421 }
3422
3423 if (enable) {
3424 if (!test_and_set_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3425 changed = true;
3426 } else {
3427 if (test_and_clear_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3428 changed = true;
3429 }
3430
3431 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
3432
3433 if (changed)
3434 err = new_settings(hdev, match.sk);
3435
3436 if (match.sk)
3437 sock_put(match.sk);
3438
3439 return err;
3440}
3441
Johan Hedberg48264f02011-11-09 13:58:58 +02003442int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Johan Hedberg561aafb2012-01-04 13:31:59 +02003443 u8 addr_type, u8 *dev_class, s8 rssi,
Johan Hedberg388fc8f2012-02-23 00:38:59 +02003444 u8 cfm_name, u8 ssp, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03003445{
Johan Hedberge319d2e2012-01-15 19:51:59 +02003446 char buf[512];
3447 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02003448 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03003449
Johan Hedberg1dc06092012-01-15 21:01:23 +02003450 /* Leave 5 bytes for a potential CoD field */
3451 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Andre Guedes7d262f82012-01-10 18:20:49 -03003452 return -EINVAL;
3453
Johan Hedberg1dc06092012-01-15 21:01:23 +02003454 memset(buf, 0, sizeof(buf));
3455
Johan Hedberge319d2e2012-01-15 19:51:59 +02003456 bacpy(&ev->addr.bdaddr, bdaddr);
3457 ev->addr.type = link_to_mgmt(link_type, addr_type);
3458 ev->rssi = rssi;
Johan Hedberg9a395a82012-02-23 00:00:32 +02003459 if (cfm_name)
3460 ev->flags[0] |= MGMT_DEV_FOUND_CONFIRM_NAME;
Johan Hedberg388fc8f2012-02-23 00:38:59 +02003461 if (!ssp)
3462 ev->flags[0] |= MGMT_DEV_FOUND_LEGACY_PAIRING;
Johan Hedberge17acd42011-03-30 23:57:16 +03003463
Johan Hedberg1dc06092012-01-15 21:01:23 +02003464 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02003465 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03003466
Johan Hedberg1dc06092012-01-15 21:01:23 +02003467 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
3468 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
3469 dev_class, 3);
3470
3471 put_unaligned_le16(eir_len, &ev->eir_len);
3472
3473 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03003474
Johan Hedberge319d2e2012-01-15 19:51:59 +02003475 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03003476}
Johan Hedberga88a9652011-03-30 13:18:12 +03003477
Johan Hedbergb644ba32012-01-17 21:48:47 +02003478int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
3479 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03003480{
Johan Hedbergb644ba32012-01-17 21:48:47 +02003481 struct mgmt_ev_device_found *ev;
3482 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
3483 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03003484
Johan Hedbergb644ba32012-01-17 21:48:47 +02003485 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03003486
Johan Hedbergb644ba32012-01-17 21:48:47 +02003487 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03003488
Johan Hedbergb644ba32012-01-17 21:48:47 +02003489 bacpy(&ev->addr.bdaddr, bdaddr);
3490 ev->addr.type = link_to_mgmt(link_type, addr_type);
3491 ev->rssi = rssi;
3492
3493 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
3494 name_len);
3495
3496 put_unaligned_le16(eir_len, &ev->eir_len);
3497
Johan Hedberg053c7e02012-02-04 00:06:00 +02003498 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev,
3499 sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03003500}
Johan Hedberg314b2382011-04-27 10:29:57 -04003501
Andre Guedes7a135102011-11-09 17:14:25 -03003502int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
Johan Hedberg164a6e72011-11-01 17:06:44 +02003503{
3504 struct pending_cmd *cmd;
Johan Hedbergf808e162012-02-19 12:52:07 +02003505 u8 type;
Johan Hedberg164a6e72011-11-01 17:06:44 +02003506 int err;
3507
Andre Guedes203159d2012-02-13 15:41:01 -03003508 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3509
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003510 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003511 if (!cmd)
3512 return -ENOENT;
3513
Johan Hedbergf808e162012-02-19 12:52:07 +02003514 type = hdev->discovery.type;
3515
3516 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
3517 &type, sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02003518 mgmt_pending_remove(cmd);
3519
3520 return err;
3521}
3522
Andre Guedese6d465c2011-11-09 17:14:26 -03003523int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
3524{
3525 struct pending_cmd *cmd;
3526 int err;
3527
3528 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
3529 if (!cmd)
3530 return -ENOENT;
3531
Johan Hedbergd9306502012-02-20 23:25:18 +02003532 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
3533 &hdev->discovery.type,
3534 sizeof(hdev->discovery.type));
Johan Hedberg03811012010-12-08 00:21:06 +02003535 mgmt_pending_remove(cmd);
3536
3537 return err;
3538}
Johan Hedberg314b2382011-04-27 10:29:57 -04003539
Johan Hedberg744cf192011-11-08 20:40:14 +02003540int mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04003541{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02003542 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02003543 struct pending_cmd *cmd;
3544
Andre Guedes343fb142011-11-22 17:14:19 -03003545 BT_DBG("%s discovering %u", hdev->name, discovering);
3546
Johan Hedberg164a6e72011-11-01 17:06:44 +02003547 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003548 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003549 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003550 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003551
3552 if (cmd != NULL) {
Johan Hedbergf808e162012-02-19 12:52:07 +02003553 u8 type = hdev->discovery.type;
3554
Johan Hedbergd9306502012-02-20 23:25:18 +02003555 cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0,
Johan Hedbergf808e162012-02-19 12:52:07 +02003556 &type, sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02003557 mgmt_pending_remove(cmd);
3558 }
3559
Johan Hedbergf963e8e2012-02-20 23:30:44 +02003560 memset(&ev, 0, sizeof(ev));
3561 ev.type = hdev->discovery.type;
3562 ev.discovering = discovering;
3563
3564 return mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04003565}
Antti Julku5e762442011-08-25 16:48:02 +03003566
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003567int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003568{
3569 struct pending_cmd *cmd;
3570 struct mgmt_ev_device_blocked ev;
3571
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003572 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003573
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003574 bacpy(&ev.addr.bdaddr, bdaddr);
3575 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003576
Johan Hedberg744cf192011-11-08 20:40:14 +02003577 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
3578 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003579}
3580
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003581int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003582{
3583 struct pending_cmd *cmd;
3584 struct mgmt_ev_device_unblocked ev;
3585
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003586 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003587
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003588 bacpy(&ev.addr.bdaddr, bdaddr);
3589 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003590
Johan Hedberg744cf192011-11-08 20:40:14 +02003591 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
3592 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003593}
Marcel Holtmannd7b7e792012-02-20 21:47:49 +01003594
3595module_param(enable_hs, bool, 0644);
3596MODULE_PARM_DESC(enable_hs, "Enable High Speed support");
3597
3598module_param(enable_le, bool, 0644);
3599MODULE_PARM_DESC(enable_le, "Enable Low Energy support");