blob: 4b1efedc18c5501d7c6cdcbf679cde686373b243 [file] [log] [blame]
Johan Hedberg03811012010-12-08 00:21:06 +02001/*
2 BlueZ - Bluetooth protocol stack for Linux
Johan Hedbergea585ab2012-02-17 14:50:39 +02003
Johan Hedberg03811012010-12-08 00:21:06 +02004 Copyright (C) 2010 Nokia Corporation
Johan Hedbergea585ab2012-02-17 14:50:39 +02005 Copyright (C) 2011-2012 Intel Corporation
Johan Hedberg03811012010-12-08 00:21:06 +02006
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License version 2 as
9 published by the Free Software Foundation;
10
11 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
12 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
13 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
14 IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
15 CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
16 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19
20 ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
21 COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
22 SOFTWARE IS DISCLAIMED.
23*/
24
25/* Bluetooth HCI Management interface */
26
Johan Hedbergca69b792011-11-11 18:10:00 +020027#include <linux/kernel.h>
Szymon Janc72359752011-02-17 14:16:32 +010028#include <linux/uaccess.h>
Paul Gortmaker3a9a2312011-05-27 09:12:25 -040029#include <linux/module.h>
Johan Hedberg03811012010-12-08 00:21:06 +020030#include <asm/unaligned.h>
31
32#include <net/bluetooth/bluetooth.h>
33#include <net/bluetooth/hci_core.h>
34#include <net/bluetooth/mgmt.h>
Brian Gix5fe57d92011-12-21 16:12:13 -080035#include <net/bluetooth/smp.h>
Johan Hedberg03811012010-12-08 00:21:06 +020036
Marcel Holtmannd7b7e792012-02-20 21:47:49 +010037bool enable_hs;
38bool enable_le;
39
Johan Hedberg2da9c552012-02-17 14:39:28 +020040#define MGMT_VERSION 1
41#define MGMT_REVISION 0
Johan Hedberg02d98122010-12-13 21:07:04 +020042
Johan Hedberge70bb2e2012-02-13 16:59:33 +020043static const u16 mgmt_commands[] = {
44 MGMT_OP_READ_INDEX_LIST,
45 MGMT_OP_READ_INFO,
46 MGMT_OP_SET_POWERED,
47 MGMT_OP_SET_DISCOVERABLE,
48 MGMT_OP_SET_CONNECTABLE,
49 MGMT_OP_SET_FAST_CONNECTABLE,
50 MGMT_OP_SET_PAIRABLE,
51 MGMT_OP_SET_LINK_SECURITY,
52 MGMT_OP_SET_SSP,
53 MGMT_OP_SET_HS,
54 MGMT_OP_SET_LE,
55 MGMT_OP_SET_DEV_CLASS,
56 MGMT_OP_SET_LOCAL_NAME,
57 MGMT_OP_ADD_UUID,
58 MGMT_OP_REMOVE_UUID,
59 MGMT_OP_LOAD_LINK_KEYS,
60 MGMT_OP_LOAD_LONG_TERM_KEYS,
61 MGMT_OP_DISCONNECT,
62 MGMT_OP_GET_CONNECTIONS,
63 MGMT_OP_PIN_CODE_REPLY,
64 MGMT_OP_PIN_CODE_NEG_REPLY,
65 MGMT_OP_SET_IO_CAPABILITY,
66 MGMT_OP_PAIR_DEVICE,
67 MGMT_OP_CANCEL_PAIR_DEVICE,
68 MGMT_OP_UNPAIR_DEVICE,
69 MGMT_OP_USER_CONFIRM_REPLY,
70 MGMT_OP_USER_CONFIRM_NEG_REPLY,
71 MGMT_OP_USER_PASSKEY_REPLY,
72 MGMT_OP_USER_PASSKEY_NEG_REPLY,
73 MGMT_OP_READ_LOCAL_OOB_DATA,
74 MGMT_OP_ADD_REMOTE_OOB_DATA,
75 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
76 MGMT_OP_START_DISCOVERY,
77 MGMT_OP_STOP_DISCOVERY,
78 MGMT_OP_CONFIRM_NAME,
79 MGMT_OP_BLOCK_DEVICE,
80 MGMT_OP_UNBLOCK_DEVICE,
81};
82
83static const u16 mgmt_events[] = {
84 MGMT_EV_CONTROLLER_ERROR,
85 MGMT_EV_INDEX_ADDED,
86 MGMT_EV_INDEX_REMOVED,
87 MGMT_EV_NEW_SETTINGS,
88 MGMT_EV_CLASS_OF_DEV_CHANGED,
89 MGMT_EV_LOCAL_NAME_CHANGED,
90 MGMT_EV_NEW_LINK_KEY,
91 MGMT_EV_NEW_LONG_TERM_KEY,
92 MGMT_EV_DEVICE_CONNECTED,
93 MGMT_EV_DEVICE_DISCONNECTED,
94 MGMT_EV_CONNECT_FAILED,
95 MGMT_EV_PIN_CODE_REQUEST,
96 MGMT_EV_USER_CONFIRM_REQUEST,
97 MGMT_EV_USER_PASSKEY_REQUEST,
98 MGMT_EV_AUTH_FAILED,
99 MGMT_EV_DEVICE_FOUND,
100 MGMT_EV_DISCOVERING,
101 MGMT_EV_DEVICE_BLOCKED,
102 MGMT_EV_DEVICE_UNBLOCKED,
103 MGMT_EV_DEVICE_UNPAIRED,
104};
105
Andre Guedes3fd24152012-02-03 17:48:01 -0300106/*
107 * These LE scan and inquiry parameters were chosen according to LE General
108 * Discovery Procedure specification.
109 */
110#define LE_SCAN_TYPE 0x01
111#define LE_SCAN_WIN 0x12
112#define LE_SCAN_INT 0x12
113#define LE_SCAN_TIMEOUT_LE_ONLY 10240 /* TGAP(gen_disc_scan_min) */
Andre Guedes5e0452c2012-02-17 20:39:38 -0300114#define LE_SCAN_TIMEOUT_BREDR_LE 5120 /* TGAP(100)/2 */
Andre Guedes3fd24152012-02-03 17:48:01 -0300115
Andre Guedese8777522012-02-03 17:48:02 -0300116#define INQUIRY_LEN_BREDR 0x08 /* TGAP(100) */
Andre Guedes5e0452c2012-02-17 20:39:38 -0300117#define INQUIRY_LEN_BREDR_LE 0x04 /* TGAP(100)/2 */
Andre Guedes2519a1f2011-11-07 11:45:24 -0300118
Marcel Holtmann17b02e62012-03-01 14:32:37 -0800119#define CACHE_TIMEOUT msecs_to_jiffies(2 * 1000)
Johan Hedberg7d785252011-12-15 00:47:39 +0200120
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200121#define hdev_is_powered(hdev) (test_bit(HCI_UP, &hdev->flags) && \
122 !test_bit(HCI_AUTO_OFF, &hdev->dev_flags))
123
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200124struct pending_cmd {
125 struct list_head list;
Johan Hedbergfc2f4b12011-11-09 13:58:56 +0200126 u16 opcode;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200127 int index;
Szymon Jancc68fb7f2011-03-22 13:12:19 +0100128 void *param;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200129 struct sock *sk;
Johan Hedberge9a416b2011-02-19 12:05:56 -0300130 void *user_data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200131};
132
Johan Hedbergca69b792011-11-11 18:10:00 +0200133/* HCI to MGMT error code conversion table */
134static u8 mgmt_status_table[] = {
135 MGMT_STATUS_SUCCESS,
136 MGMT_STATUS_UNKNOWN_COMMAND, /* Unknown Command */
137 MGMT_STATUS_NOT_CONNECTED, /* No Connection */
138 MGMT_STATUS_FAILED, /* Hardware Failure */
139 MGMT_STATUS_CONNECT_FAILED, /* Page Timeout */
140 MGMT_STATUS_AUTH_FAILED, /* Authentication Failed */
141 MGMT_STATUS_NOT_PAIRED, /* PIN or Key Missing */
142 MGMT_STATUS_NO_RESOURCES, /* Memory Full */
143 MGMT_STATUS_TIMEOUT, /* Connection Timeout */
144 MGMT_STATUS_NO_RESOURCES, /* Max Number of Connections */
145 MGMT_STATUS_NO_RESOURCES, /* Max Number of SCO Connections */
146 MGMT_STATUS_ALREADY_CONNECTED, /* ACL Connection Exists */
147 MGMT_STATUS_BUSY, /* Command Disallowed */
148 MGMT_STATUS_NO_RESOURCES, /* Rejected Limited Resources */
149 MGMT_STATUS_REJECTED, /* Rejected Security */
150 MGMT_STATUS_REJECTED, /* Rejected Personal */
151 MGMT_STATUS_TIMEOUT, /* Host Timeout */
152 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Feature */
153 MGMT_STATUS_INVALID_PARAMS, /* Invalid Parameters */
154 MGMT_STATUS_DISCONNECTED, /* OE User Ended Connection */
155 MGMT_STATUS_NO_RESOURCES, /* OE Low Resources */
156 MGMT_STATUS_DISCONNECTED, /* OE Power Off */
157 MGMT_STATUS_DISCONNECTED, /* Connection Terminated */
158 MGMT_STATUS_BUSY, /* Repeated Attempts */
159 MGMT_STATUS_REJECTED, /* Pairing Not Allowed */
160 MGMT_STATUS_FAILED, /* Unknown LMP PDU */
161 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Remote Feature */
162 MGMT_STATUS_REJECTED, /* SCO Offset Rejected */
163 MGMT_STATUS_REJECTED, /* SCO Interval Rejected */
164 MGMT_STATUS_REJECTED, /* Air Mode Rejected */
165 MGMT_STATUS_INVALID_PARAMS, /* Invalid LMP Parameters */
166 MGMT_STATUS_FAILED, /* Unspecified Error */
167 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported LMP Parameter Value */
168 MGMT_STATUS_FAILED, /* Role Change Not Allowed */
169 MGMT_STATUS_TIMEOUT, /* LMP Response Timeout */
170 MGMT_STATUS_FAILED, /* LMP Error Transaction Collision */
171 MGMT_STATUS_FAILED, /* LMP PDU Not Allowed */
172 MGMT_STATUS_REJECTED, /* Encryption Mode Not Accepted */
173 MGMT_STATUS_FAILED, /* Unit Link Key Used */
174 MGMT_STATUS_NOT_SUPPORTED, /* QoS Not Supported */
175 MGMT_STATUS_TIMEOUT, /* Instant Passed */
176 MGMT_STATUS_NOT_SUPPORTED, /* Pairing Not Supported */
177 MGMT_STATUS_FAILED, /* Transaction Collision */
178 MGMT_STATUS_INVALID_PARAMS, /* Unacceptable Parameter */
179 MGMT_STATUS_REJECTED, /* QoS Rejected */
180 MGMT_STATUS_NOT_SUPPORTED, /* Classification Not Supported */
181 MGMT_STATUS_REJECTED, /* Insufficient Security */
182 MGMT_STATUS_INVALID_PARAMS, /* Parameter Out Of Range */
183 MGMT_STATUS_BUSY, /* Role Switch Pending */
184 MGMT_STATUS_FAILED, /* Slot Violation */
185 MGMT_STATUS_FAILED, /* Role Switch Failed */
186 MGMT_STATUS_INVALID_PARAMS, /* EIR Too Large */
187 MGMT_STATUS_NOT_SUPPORTED, /* Simple Pairing Not Supported */
188 MGMT_STATUS_BUSY, /* Host Busy Pairing */
189 MGMT_STATUS_REJECTED, /* Rejected, No Suitable Channel */
190 MGMT_STATUS_BUSY, /* Controller Busy */
191 MGMT_STATUS_INVALID_PARAMS, /* Unsuitable Connection Interval */
192 MGMT_STATUS_TIMEOUT, /* Directed Advertising Timeout */
193 MGMT_STATUS_AUTH_FAILED, /* Terminated Due to MIC Failure */
194 MGMT_STATUS_CONNECT_FAILED, /* Connection Establishment Failed */
195 MGMT_STATUS_CONNECT_FAILED, /* MAC Connection Failed */
196};
197
198static u8 mgmt_status(u8 hci_status)
199{
200 if (hci_status < ARRAY_SIZE(mgmt_status_table))
201 return mgmt_status_table[hci_status];
202
203 return MGMT_STATUS_FAILED;
204}
205
Szymon Janc4e51eae2011-02-25 19:05:48 +0100206static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200207{
208 struct sk_buff *skb;
209 struct mgmt_hdr *hdr;
210 struct mgmt_ev_cmd_status *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300211 int err;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200212
Szymon Janc34eb5252011-02-28 14:10:08 +0100213 BT_DBG("sock %p, index %u, cmd %u, status %u", sk, index, cmd, status);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200214
215 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_ATOMIC);
216 if (!skb)
217 return -ENOMEM;
218
219 hdr = (void *) skb_put(skb, sizeof(*hdr));
220
221 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_STATUS);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100222 hdr->index = cpu_to_le16(index);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200223 hdr->len = cpu_to_le16(sizeof(*ev));
224
225 ev = (void *) skb_put(skb, sizeof(*ev));
226 ev->status = status;
227 put_unaligned_le16(cmd, &ev->opcode);
228
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300229 err = sock_queue_rcv_skb(sk, skb);
230 if (err < 0)
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200231 kfree_skb(skb);
232
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300233 return err;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200234}
235
Johan 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 Hedbergf7b64e62010-12-13 21:07:06 +0200377
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200378 if (!(hdev->features[4] & LMP_NO_BREDR)) {
379 settings |= MGMT_SETTING_BREDR;
380 settings |= MGMT_SETTING_LINK_SECURITY;
381 }
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200382
Marcel Holtmannd7b7e792012-02-20 21:47:49 +0100383 if (enable_hs)
384 settings |= MGMT_SETTING_HS;
385
386 if (enable_le) {
387 if (hdev->features[4] & LMP_LE)
388 settings |= MGMT_SETTING_LE;
389 }
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200390
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200391 return settings;
392}
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200393
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200394static u32 get_current_settings(struct hci_dev *hdev)
395{
396 u32 settings = 0;
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200397
Johan Hedbergf1f0eb02012-02-21 17:15:41 +0200398 if (hdev_is_powered(hdev))
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100399 settings |= MGMT_SETTING_POWERED;
400
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200401 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200402 settings |= MGMT_SETTING_CONNECTABLE;
403
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200404 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200405 settings |= MGMT_SETTING_DISCOVERABLE;
406
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200407 if (test_bit(HCI_PAIRABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200408 settings |= MGMT_SETTING_PAIRABLE;
409
410 if (!(hdev->features[4] & LMP_NO_BREDR))
411 settings |= MGMT_SETTING_BREDR;
412
Johan Hedberg06199cf2012-02-22 16:37:11 +0200413 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200414 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200415
Johan Hedberg47990ea2012-02-22 11:58:37 +0200416 if (test_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200417 settings |= MGMT_SETTING_LINK_SECURITY;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200418
Johan Hedberg84bde9d2012-01-25 14:21:06 +0200419 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200420 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200421
Johan Hedberg6d80dfd2012-02-20 23:50:38 +0200422 if (test_bit(HCI_HS_ENABLED, &hdev->dev_flags))
423 settings |= MGMT_SETTING_HS;
424
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200425 return settings;
Johan Hedbergc542a062011-01-26 13:11:03 +0200426}
427
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300428#define PNP_INFO_SVCLASS_ID 0x1200
429
430static u8 bluetooth_base_uuid[] = {
431 0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80,
432 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
433};
434
435static u16 get_uuid16(u8 *uuid128)
436{
437 u32 val;
438 int i;
439
440 for (i = 0; i < 12; i++) {
441 if (bluetooth_base_uuid[i] != uuid128[i])
442 return 0;
443 }
444
445 memcpy(&val, &uuid128[12], 4);
446
447 val = le32_to_cpu(val);
448 if (val > 0xffff)
449 return 0;
450
451 return (u16) val;
452}
453
454static void create_eir(struct hci_dev *hdev, u8 *data)
455{
456 u8 *ptr = data;
457 u16 eir_len = 0;
458 u16 uuid16_list[HCI_MAX_EIR_LENGTH / sizeof(u16)];
459 int i, truncated = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200460 struct bt_uuid *uuid;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300461 size_t name_len;
462
463 name_len = strlen(hdev->dev_name);
464
465 if (name_len > 0) {
466 /* EIR Data type */
467 if (name_len > 48) {
468 name_len = 48;
469 ptr[1] = EIR_NAME_SHORT;
470 } else
471 ptr[1] = EIR_NAME_COMPLETE;
472
473 /* EIR Data length */
474 ptr[0] = name_len + 1;
475
476 memcpy(ptr + 2, hdev->dev_name, name_len);
477
478 eir_len += (name_len + 2);
479 ptr += (name_len + 2);
480 }
481
482 memset(uuid16_list, 0, sizeof(uuid16_list));
483
484 /* Group all UUID16 types */
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200485 list_for_each_entry(uuid, &hdev->uuids, list) {
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300486 u16 uuid16;
487
488 uuid16 = get_uuid16(uuid->uuid);
489 if (uuid16 == 0)
490 return;
491
492 if (uuid16 < 0x1100)
493 continue;
494
495 if (uuid16 == PNP_INFO_SVCLASS_ID)
496 continue;
497
498 /* Stop if not enough space to put next UUID */
499 if (eir_len + 2 + sizeof(u16) > HCI_MAX_EIR_LENGTH) {
500 truncated = 1;
501 break;
502 }
503
504 /* Check for duplicates */
505 for (i = 0; uuid16_list[i] != 0; i++)
506 if (uuid16_list[i] == uuid16)
507 break;
508
509 if (uuid16_list[i] == 0) {
510 uuid16_list[i] = uuid16;
511 eir_len += sizeof(u16);
512 }
513 }
514
515 if (uuid16_list[0] != 0) {
516 u8 *length = ptr;
517
518 /* EIR Data type */
519 ptr[1] = truncated ? EIR_UUID16_SOME : EIR_UUID16_ALL;
520
521 ptr += 2;
522 eir_len += 2;
523
524 for (i = 0; uuid16_list[i] != 0; i++) {
525 *ptr++ = (uuid16_list[i] & 0x00ff);
526 *ptr++ = (uuid16_list[i] & 0xff00) >> 8;
527 }
528
529 /* EIR Data length */
530 *length = (i * sizeof(u16)) + 1;
531 }
532}
533
534static int update_eir(struct hci_dev *hdev)
535{
536 struct hci_cp_write_eir cp;
537
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200538 if (!hdev_is_powered(hdev))
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200539 return 0;
540
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300541 if (!(hdev->features[6] & LMP_EXT_INQ))
542 return 0;
543
Johan Hedberg84bde9d2012-01-25 14:21:06 +0200544 if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300545 return 0;
546
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200547 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300548 return 0;
549
550 memset(&cp, 0, sizeof(cp));
551
552 create_eir(hdev, cp.data);
553
554 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
555 return 0;
556
557 memcpy(hdev->eir, cp.data, sizeof(cp.data));
558
559 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
560}
561
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200562static u8 get_service_classes(struct hci_dev *hdev)
563{
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300564 struct bt_uuid *uuid;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200565 u8 val = 0;
566
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300567 list_for_each_entry(uuid, &hdev->uuids, list)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200568 val |= uuid->svc_hint;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200569
570 return val;
571}
572
573static int update_class(struct hci_dev *hdev)
574{
575 u8 cod[3];
Johan Hedbergc95f0ba2012-02-23 22:54:38 +0200576 int err;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200577
578 BT_DBG("%s", hdev->name);
579
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200580 if (!hdev_is_powered(hdev))
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200581 return 0;
582
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200583 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200584 return 0;
585
586 cod[0] = hdev->minor_class;
587 cod[1] = hdev->major_class;
588 cod[2] = get_service_classes(hdev);
589
590 if (memcmp(cod, hdev->dev_class, 3) == 0)
591 return 0;
592
Johan Hedbergc95f0ba2012-02-23 22:54:38 +0200593 err = hci_send_cmd(hdev, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
594 if (err == 0)
595 set_bit(HCI_PENDING_CLASS, &hdev->dev_flags);
596
597 return err;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200598}
599
Johan Hedberg7d785252011-12-15 00:47:39 +0200600static void service_cache_off(struct work_struct *work)
601{
602 struct hci_dev *hdev = container_of(work, struct hci_dev,
603 service_cache.work);
604
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200605 if (!test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200606 return;
607
608 hci_dev_lock(hdev);
609
610 update_eir(hdev);
611 update_class(hdev);
612
613 hci_dev_unlock(hdev);
614}
615
Johan Hedberg6a919082012-02-28 06:17:26 +0200616static void mgmt_init_hdev(struct sock *sk, struct hci_dev *hdev)
Johan Hedberg7d785252011-12-15 00:47:39 +0200617{
Johan 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 Hedbergf7b64e62010-12-13 21:07:06 +0200847
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300848 hci_dev_lock(hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200849
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200850 if (!hdev_is_powered(hdev) && timeout > 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200851 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +0200852 MGMT_STATUS_NOT_POWERED);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200853 goto failed;
854 }
855
856 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
857 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200858 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +0200859 MGMT_STATUS_BUSY);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200860 goto failed;
861 }
862
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200863 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200864 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
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 Hedbergf7b64e62010-12-13 21:07:06 +0200900 goto failed;
901 }
902
903 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
904 if (!cmd) {
905 err = -ENOMEM;
906 goto failed;
907 }
908
909 scan = SCAN_PAGE;
910
911 if (cp->val)
912 scan |= SCAN_INQUIRY;
913 else
914 cancel_delayed_work(&hdev->discov_off);
915
916 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
917 if (err < 0)
918 mgmt_pending_remove(cmd);
919
Johan Hedberg03811012010-12-08 00:21:06 +0200920 if (cp->val)
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200921 hdev->discov_timeout = timeout;
Johan Hedberg03811012010-12-08 00:21:06 +0200922
923failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300924 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200925 return err;
926}
927
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200928static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
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 Hedberg55ed8ca2011-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 Hedberg55ed8ca2011-01-17 14:41:05 +02001441
Johan Hedberg55ed8ca2011-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 Hedberg55ed8ca2011-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 Hedberg55ed8ca2011-01-17 14:41:05 +02001454 key_count);
1455
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001456 hci_dev_lock(hdev);
Johan Hedberg55ed8ca2011-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 Hedberg55ed8ca2011-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 Hedberg55ed8ca2011-01-17 14:41:05 +02001464 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001465 clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca2011-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 Hedberg55ed8ca2011-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 Hedberg55ed8ca2011-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 Hedberg55ed8ca2011-01-17 14:41:05 +02001477
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001478 return 0;
Johan Hedberg55ed8ca2011-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 Hedberg55ed8ca2011-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 Hedberg55ed8ca2011-01-17 14:41:05 +02001500 struct hci_conn *conn;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001501 int err;
1502
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001503 hci_dev_lock(hdev);
Johan Hedberg55ed8ca2011-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 Hedberg55ed8ca2011-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 Hedberg55ed8ca2011-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 Hedberg55ed8ca2011-01-17 14:41:05 +02001537 }
Johan Hedberg55ed8ca2011-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 Hedberg55ed8ca2011-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 Hedberg55ed8ca2011-01-17 14:41:05 +02001559unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001560 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca2011-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 Hedberg60fc5fb2012-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 Hedberg60fc5fb2012-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 Hedberg60fc5fb2012-02-23 09:52:28 +02001659 i++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001660 }
1661
Johan Hedberg60fc5fb2012-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 Hedberg60fc5fb2012-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 Hedbergbdb6d972012-02-28 06:13:32 +02002107static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
Johan Hedbergb312b1612011-03-16 14:29:37 +02002108 u16 len)
2109{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002110 struct mgmt_cp_set_local_name *mgmt_cp = data;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002111 struct hci_cp_write_local_name hci_cp;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002112 struct pending_cmd *cmd;
2113 int err;
2114
2115 BT_DBG("");
2116
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002117 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002118
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002119 memcpy(hdev->short_name, mgmt_cp->short_name,
2120 sizeof(hdev->short_name));
2121
Johan Hedbergb5235a62012-02-21 14:32:24 +02002122 if (!hdev_is_powered(hdev)) {
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002123 memcpy(hdev->dev_name, mgmt_cp->name, sizeof(hdev->dev_name));
2124
2125 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
2126 data, len);
2127 if (err < 0)
2128 goto failed;
2129
2130 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data, len,
2131 sk);
2132
Johan Hedbergb5235a62012-02-21 14:32:24 +02002133 goto failed;
2134 }
2135
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002136 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002137 if (!cmd) {
2138 err = -ENOMEM;
2139 goto failed;
2140 }
2141
2142 memcpy(hci_cp.name, mgmt_cp->name, sizeof(hci_cp.name));
2143 err = hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(hci_cp),
2144 &hci_cp);
2145 if (err < 0)
2146 mgmt_pending_remove(cmd);
2147
2148failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002149 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002150 return err;
2151}
2152
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002153static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
2154 void *data, u16 data_len)
Szymon Jancc35938b2011-03-22 13:12:21 +01002155{
Szymon Jancc35938b2011-03-22 13:12:21 +01002156 struct pending_cmd *cmd;
2157 int err;
2158
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002159 BT_DBG("%s", hdev->name);
Szymon Jancc35938b2011-03-22 13:12:21 +01002160
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002161 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002162
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002163 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002164 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002165 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002166 goto unlock;
2167 }
2168
2169 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002170 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002171 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002172 goto unlock;
2173 }
2174
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002175 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002176 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002177 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01002178 goto unlock;
2179 }
2180
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002181 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01002182 if (!cmd) {
2183 err = -ENOMEM;
2184 goto unlock;
2185 }
2186
2187 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
2188 if (err < 0)
2189 mgmt_pending_remove(cmd);
2190
2191unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002192 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002193 return err;
2194}
2195
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002196static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
2197 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002198{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002199 struct mgmt_cp_add_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002200 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002201 int err;
2202
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002203 BT_DBG("%s ", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01002204
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002205 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002206
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002207 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002208 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA,
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002209 MGMT_STATUS_NOT_POWERED,
2210 &cp->addr, sizeof(cp->addr));
2211 goto unlock;
2212 }
2213
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002214 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, cp->hash,
Szymon Janc2763eda2011-03-22 13:12:22 +01002215 cp->randomizer);
2216 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002217 status = MGMT_STATUS_FAILED;
Szymon Janc2763eda2011-03-22 13:12:22 +01002218 else
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002219 status = 0;
2220
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002221 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA, status,
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002222 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002223
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002224unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002225 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002226 return err;
2227}
2228
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002229static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002230 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002231{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002232 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002233 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002234 int err;
2235
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002236 BT_DBG("%s", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01002237
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002238 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002239
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002240 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002241 err = cmd_complete(sk, hdev->id,
2242 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2243 MGMT_STATUS_NOT_POWERED,
2244 &cp->addr, sizeof(cp->addr));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002245 goto unlock;
2246 }
2247
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002248 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr);
Szymon Janc2763eda2011-03-22 13:12:22 +01002249 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002250 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01002251 else
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002252 status = 0;
2253
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002254 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2255 status, &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002256
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002257unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002258 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002259 return err;
2260}
2261
Andre Guedes5e0452c2012-02-17 20:39:38 -03002262int mgmt_interleaved_discovery(struct hci_dev *hdev)
2263{
2264 int err;
2265
2266 BT_DBG("%s", hdev->name);
2267
2268 hci_dev_lock(hdev);
2269
2270 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR_LE);
2271 if (err < 0)
2272 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2273
2274 hci_dev_unlock(hdev);
2275
2276 return err;
2277}
2278
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002279static int start_discovery(struct sock *sk, struct hci_dev *hdev,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002280 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002281{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002282 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002283 struct pending_cmd *cmd;
Johan Hedberg14a53662011-04-27 10:29:56 -04002284 int err;
2285
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002286 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04002287
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002288 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002289
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002290 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002291 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Johan Hedbergca69b792011-11-11 18:10:00 +02002292 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02002293 goto failed;
2294 }
2295
Johan Hedbergff9ef572012-01-04 14:23:45 +02002296 if (hdev->discovery.state != DISCOVERY_STOPPED) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002297 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2298 MGMT_STATUS_BUSY);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002299 goto failed;
2300 }
2301
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002302 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002303 if (!cmd) {
2304 err = -ENOMEM;
2305 goto failed;
2306 }
2307
Andre Guedes4aab14e2012-02-17 20:39:36 -03002308 hdev->discovery.type = cp->type;
2309
2310 switch (hdev->discovery.type) {
Andre Guedesf39799f2012-02-17 20:39:35 -03002311 case DISCOV_TYPE_BREDR:
Andre Guedes8b901292012-02-23 18:09:27 -03002312 if (lmp_bredr_capable(hdev))
2313 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
2314 else
2315 err = -ENOTSUPP;
Andre Guedesf39799f2012-02-17 20:39:35 -03002316 break;
2317
2318 case DISCOV_TYPE_LE:
Andre Guedes8b901292012-02-23 18:09:27 -03002319 if (lmp_host_le_capable(hdev))
2320 err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT,
Andre Guedes3fd24152012-02-03 17:48:01 -03002321 LE_SCAN_WIN, LE_SCAN_TIMEOUT_LE_ONLY);
Andre Guedes8b901292012-02-23 18:09:27 -03002322 else
2323 err = -ENOTSUPP;
Andre Guedesf39799f2012-02-17 20:39:35 -03002324 break;
2325
Andre Guedes5e0452c2012-02-17 20:39:38 -03002326 case DISCOV_TYPE_INTERLEAVED:
Andre Guedes426c1892012-02-24 11:41:04 -03002327 if (lmp_host_le_capable(hdev) && lmp_bredr_capable(hdev))
2328 err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT,
2329 LE_SCAN_WIN, LE_SCAN_TIMEOUT_BREDR_LE);
2330 else
2331 err = -ENOTSUPP;
Andre Guedes5e0452c2012-02-17 20:39:38 -03002332 break;
2333
Andre Guedesf39799f2012-02-17 20:39:35 -03002334 default:
Andre Guedes3fd24152012-02-03 17:48:01 -03002335 err = -EINVAL;
Andre Guedesf39799f2012-02-17 20:39:35 -03002336 }
Andre Guedes3fd24152012-02-03 17:48:01 -03002337
Johan Hedberg14a53662011-04-27 10:29:56 -04002338 if (err < 0)
2339 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002340 else
2341 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002342
2343failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002344 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002345 return err;
2346}
2347
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002348static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
2349 u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002350{
Johan Hedbergd9306502012-02-20 23:25:18 +02002351 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002352 struct pending_cmd *cmd;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002353 struct hci_cp_remote_name_req_cancel cp;
2354 struct inquiry_entry *e;
Johan Hedberg14a53662011-04-27 10:29:56 -04002355 int err;
2356
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002357 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04002358
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002359 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002360
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002361 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002362 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Johan Hedbergd9306502012-02-20 23:25:18 +02002363 MGMT_STATUS_REJECTED,
2364 &mgmt_cp->type, sizeof(mgmt_cp->type));
2365 goto unlock;
2366 }
2367
2368 if (hdev->discovery.type != mgmt_cp->type) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002369 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Johan Hedbergd9306502012-02-20 23:25:18 +02002370 MGMT_STATUS_INVALID_PARAMS,
2371 &mgmt_cp->type, sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002372 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02002373 }
2374
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002375 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002376 if (!cmd) {
2377 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002378 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04002379 }
2380
Andre Guedes343f9352012-02-17 20:39:37 -03002381 if (hdev->discovery.state == DISCOVERY_FINDING) {
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002382 err = hci_cancel_inquiry(hdev);
2383 if (err < 0)
2384 mgmt_pending_remove(cmd);
2385 else
2386 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
2387 goto unlock;
2388 }
2389
2390 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY, NAME_PENDING);
2391 if (!e) {
2392 mgmt_pending_remove(cmd);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002393 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY, 0,
Johan Hedbergd9306502012-02-20 23:25:18 +02002394 &mgmt_cp->type, sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002395 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2396 goto unlock;
2397 }
2398
2399 bacpy(&cp.bdaddr, &e->data.bdaddr);
2400 err = hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ_CANCEL,
2401 sizeof(cp), &cp);
Johan Hedberg14a53662011-04-27 10:29:56 -04002402 if (err < 0)
2403 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002404 else
2405 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002406
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002407unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002408 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002409 return err;
2410}
2411
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002412static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
2413 u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02002414{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002415 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002416 struct inquiry_entry *e;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002417 int err;
2418
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002419 BT_DBG("%s", hdev->name);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002420
Johan Hedberg561aafb2012-01-04 13:31:59 +02002421 hci_dev_lock(hdev);
2422
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002423 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002424 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002425 MGMT_STATUS_FAILED);
2426 goto failed;
2427 }
2428
Johan Hedberga198e7b2012-02-17 14:27:06 +02002429 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002430 if (!e) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002431 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
2432 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002433 goto failed;
2434 }
2435
2436 if (cp->name_known) {
2437 e->name_state = NAME_KNOWN;
2438 list_del(&e->list);
2439 } else {
2440 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e202012-01-09 00:53:02 +02002441 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002442 }
2443
2444 err = 0;
2445
2446failed:
2447 hci_dev_unlock(hdev);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002448 return err;
2449}
2450
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002451static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
2452 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002453{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002454 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002455 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03002456 int err;
2457
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002458 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03002459
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002460 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002461
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002462 err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002463 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002464 status = MGMT_STATUS_FAILED;
Antti Julku7fbec222011-06-15 12:01:15 +03002465 else
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002466 status = 0;
2467
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002468 err = cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status,
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002469 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03002470
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002471 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002472
2473 return err;
2474}
2475
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002476static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
2477 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002478{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002479 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002480 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03002481 int err;
2482
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002483 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03002484
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002485 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002486
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002487 err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002488 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002489 status = MGMT_STATUS_INVALID_PARAMS;
Antti Julku7fbec222011-06-15 12:01:15 +03002490 else
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002491 status = 0;
2492
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002493 err = cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status,
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002494 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03002495
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002496 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002497
2498 return err;
2499}
2500
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002501static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
2502 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03002503{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002504 struct mgmt_mode *cp = data;
Antti Julkuf6422ec2011-06-22 13:11:56 +03002505 struct hci_cp_write_page_scan_activity acp;
2506 u8 type;
2507 int err;
2508
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002509 BT_DBG("%s", hdev->name);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002510
Johan Hedberg5400c042012-02-21 16:40:33 +02002511 if (!hdev_is_powered(hdev))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002512 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedberg5400c042012-02-21 16:40:33 +02002513 MGMT_STATUS_NOT_POWERED);
2514
2515 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002516 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
2517 MGMT_STATUS_REJECTED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002518
2519 hci_dev_lock(hdev);
2520
Johan Hedbergf7c68692011-12-15 00:47:36 +02002521 if (cp->val) {
Antti Julkuf6422ec2011-06-22 13:11:56 +03002522 type = PAGE_SCAN_TYPE_INTERLACED;
2523 acp.interval = 0x0024; /* 22.5 msec page scan interval */
2524 } else {
2525 type = PAGE_SCAN_TYPE_STANDARD; /* default */
2526 acp.interval = 0x0800; /* default 1.28 sec page scan */
2527 }
2528
2529 acp.window = 0x0012; /* default 11.25 msec page scan window */
2530
2531 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
2532 sizeof(acp), &acp);
2533 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002534 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
2535 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002536 goto done;
2537 }
2538
2539 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
2540 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002541 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
2542 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002543 goto done;
2544 }
2545
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002546 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE, 0,
Johan Hedbergaee9b212012-02-18 15:07:59 +02002547 NULL, 0);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002548done:
2549 hci_dev_unlock(hdev);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002550 return err;
2551}
2552
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002553static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002554 void *cp_data, u16 len)
2555{
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002556 struct mgmt_cp_load_long_term_keys *cp = cp_data;
2557 u16 key_count, expected_len;
2558 int i;
2559
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002560 key_count = get_unaligned_le16(&cp->key_count);
2561
2562 expected_len = sizeof(*cp) + key_count *
2563 sizeof(struct mgmt_ltk_info);
2564 if (expected_len != len) {
2565 BT_ERR("load_keys: expected %u bytes, got %u bytes",
2566 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002567 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002568 EINVAL);
2569 }
2570
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002571 BT_DBG("%s key_count %u", hdev->name, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002572
2573 hci_dev_lock(hdev);
2574
2575 hci_smp_ltks_clear(hdev);
2576
2577 for (i = 0; i < key_count; i++) {
2578 struct mgmt_ltk_info *key = &cp->keys[i];
2579 u8 type;
2580
2581 if (key->master)
2582 type = HCI_SMP_LTK;
2583 else
2584 type = HCI_SMP_LTK_SLAVE;
2585
2586 hci_add_ltk(hdev, &key->addr.bdaddr, key->addr.type,
2587 type, 0, key->authenticated, key->val,
2588 key->enc_size, key->ediv, key->rand);
2589 }
2590
2591 hci_dev_unlock(hdev);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002592
2593 return 0;
2594}
2595
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002596struct mgmt_handler {
2597 int (*func) (struct sock *sk, struct hci_dev *hdev,
2598 void *data, u16 data_len);
Johan Hedbergbe22b542012-03-01 22:24:41 +02002599 bool var_len;
2600 size_t data_len;
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002601} mgmt_handlers[] = {
2602 { NULL }, /* 0x0000 (no command) */
Johan Hedbergbe22b542012-03-01 22:24:41 +02002603 { read_version, false, MGMT_READ_VERSION_SIZE },
2604 { read_commands, false, MGMT_READ_COMMANDS_SIZE },
2605 { read_index_list, false, MGMT_READ_INDEX_LIST_SIZE },
2606 { read_controller_info, false, MGMT_READ_INFO_SIZE },
2607 { set_powered, false, MGMT_SETTING_SIZE },
2608 { set_discoverable, false, MGMT_SET_DISCOVERABLE_SIZE },
2609 { set_connectable, false, MGMT_SETTING_SIZE },
2610 { set_fast_connectable, false, MGMT_SETTING_SIZE },
2611 { set_pairable, false, MGMT_SETTING_SIZE },
2612 { set_link_security, false, MGMT_SETTING_SIZE },
2613 { set_ssp, false, MGMT_SETTING_SIZE },
2614 { set_hs, false, MGMT_SETTING_SIZE },
2615 { set_le, false, MGMT_SETTING_SIZE },
2616 { set_dev_class, false, MGMT_SET_DEV_CLASS_SIZE },
2617 { set_local_name, false, MGMT_SET_LOCAL_NAME_SIZE },
2618 { add_uuid, false, MGMT_ADD_UUID_SIZE },
2619 { remove_uuid, false, MGMT_REMOVE_UUID_SIZE },
2620 { load_link_keys, true, MGMT_LOAD_LINK_KEYS_SIZE },
2621 { load_long_term_keys, true, MGMT_LOAD_LONG_TERM_KEYS_SIZE },
2622 { disconnect, false, MGMT_DISCONNECT_SIZE },
2623 { get_connections, false, MGMT_GET_CONNECTIONS_SIZE },
2624 { pin_code_reply, false, MGMT_PIN_CODE_REPLY_SIZE },
2625 { pin_code_neg_reply, false, MGMT_PIN_CODE_NEG_REPLY_SIZE },
2626 { set_io_capability, false, MGMT_SET_IO_CAPABILITY_SIZE },
2627 { pair_device, false, MGMT_PAIR_DEVICE_SIZE },
2628 { cancel_pair_device, false, MGMT_CANCEL_PAIR_DEVICE_SIZE },
2629 { unpair_device, false, MGMT_UNPAIR_DEVICE_SIZE },
2630 { user_confirm_reply, false, MGMT_USER_CONFIRM_REPLY_SIZE },
2631 { user_confirm_neg_reply, false, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
2632 { user_passkey_reply, false, MGMT_USER_PASSKEY_REPLY_SIZE },
2633 { user_passkey_neg_reply, false, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
2634 { read_local_oob_data, false, MGMT_READ_LOCAL_OOB_DATA_SIZE },
2635 { add_remote_oob_data, false, MGMT_ADD_REMOTE_OOB_DATA_SIZE },
2636 { remove_remote_oob_data, false, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
2637 { start_discovery, false, MGMT_START_DISCOVERY_SIZE },
2638 { stop_discovery, false, MGMT_STOP_DISCOVERY_SIZE },
2639 { confirm_name, false, MGMT_CONFIRM_NAME_SIZE },
2640 { block_device, false, MGMT_BLOCK_DEVICE_SIZE },
2641 { unblock_device, false, MGMT_UNBLOCK_DEVICE_SIZE },
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002642};
2643
2644
Johan Hedberg03811012010-12-08 00:21:06 +02002645int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
2646{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002647 void *buf;
2648 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02002649 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002650 u16 opcode, index, len;
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002651 struct hci_dev *hdev = NULL;
Johan Hedbergbe22b542012-03-01 22:24:41 +02002652 struct mgmt_handler *handler;
Johan Hedberg03811012010-12-08 00:21:06 +02002653 int err;
2654
2655 BT_DBG("got %zu bytes", msglen);
2656
2657 if (msglen < sizeof(*hdr))
2658 return -EINVAL;
2659
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03002660 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02002661 if (!buf)
2662 return -ENOMEM;
2663
2664 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
2665 err = -EFAULT;
2666 goto done;
2667 }
2668
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002669 hdr = buf;
Johan Hedberg03811012010-12-08 00:21:06 +02002670 opcode = get_unaligned_le16(&hdr->opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002671 index = get_unaligned_le16(&hdr->index);
Johan Hedberg03811012010-12-08 00:21:06 +02002672 len = get_unaligned_le16(&hdr->len);
2673
2674 if (len != msglen - sizeof(*hdr)) {
2675 err = -EINVAL;
2676 goto done;
2677 }
2678
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002679 if (index != MGMT_INDEX_NONE) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002680 hdev = hci_dev_get(index);
2681 if (!hdev) {
2682 err = cmd_status(sk, index, opcode,
Johan Hedberg5f159032012-03-02 03:13:19 +02002683 MGMT_STATUS_INVALID_INDEX);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002684 goto done;
2685 }
2686 }
2687
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002688 if (opcode >= ARRAY_SIZE(mgmt_handlers) ||
2689 mgmt_handlers[opcode].func == NULL) {
Johan Hedberg03811012010-12-08 00:21:06 +02002690 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02002691 err = cmd_status(sk, index, opcode,
2692 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002693 goto done;
Johan Hedberg03811012010-12-08 00:21:06 +02002694 }
2695
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002696 if ((hdev && opcode < MGMT_OP_READ_INFO) ||
2697 (!hdev && opcode >= MGMT_OP_READ_INFO)) {
2698 err = cmd_status(sk, index, opcode,
Johan Hedberg5f159032012-03-02 03:13:19 +02002699 MGMT_STATUS_INVALID_INDEX);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002700 goto done;
2701 }
2702
Johan Hedbergbe22b542012-03-01 22:24:41 +02002703 handler = &mgmt_handlers[opcode];
2704
2705 if ((handler->var_len && len < handler->data_len) ||
2706 (!handler->var_len && len != handler->data_len)) {
2707 err = cmd_status(sk, index, opcode,
2708 MGMT_STATUS_INVALID_PARAMS);
2709 goto done;
2710 }
2711
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002712 if (hdev)
2713 mgmt_init_hdev(sk, hdev);
2714
2715 cp = buf + sizeof(*hdr);
2716
Johan Hedbergbe22b542012-03-01 22:24:41 +02002717 err = handler->func(sk, hdev, cp, len);
Johan Hedberge41d8b42010-12-13 21:07:03 +02002718 if (err < 0)
2719 goto done;
2720
Johan Hedberg03811012010-12-08 00:21:06 +02002721 err = msglen;
2722
2723done:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002724 if (hdev)
2725 hci_dev_put(hdev);
2726
Johan Hedberg03811012010-12-08 00:21:06 +02002727 kfree(buf);
2728 return err;
2729}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002730
Johan Hedbergb24752f2011-11-03 14:40:33 +02002731static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
2732{
2733 u8 *status = data;
2734
2735 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
2736 mgmt_pending_remove(cmd);
2737}
2738
Johan Hedberg744cf192011-11-08 20:40:14 +02002739int mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002740{
Johan Hedberg744cf192011-11-08 20:40:14 +02002741 return mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002742}
2743
Johan Hedberg744cf192011-11-08 20:40:14 +02002744int mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002745{
Johan Hedberg5f159032012-03-02 03:13:19 +02002746 u8 status = MGMT_STATUS_INVALID_INDEX;
Johan Hedbergb24752f2011-11-03 14:40:33 +02002747
Johan Hedberg744cf192011-11-08 20:40:14 +02002748 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002749
Johan Hedberg744cf192011-11-08 20:40:14 +02002750 return mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002751}
2752
Johan Hedberg73f22f62010-12-29 16:00:25 +02002753struct cmd_lookup {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002754 struct sock *sk;
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002755 struct hci_dev *hdev;
Johan Hedberg90e70452012-02-23 23:09:40 +02002756 u8 mgmt_status;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002757};
2758
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002759static void settings_rsp(struct pending_cmd *cmd, void *data)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002760{
Johan Hedberg73f22f62010-12-29 16:00:25 +02002761 struct cmd_lookup *match = data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002762
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002763 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002764
2765 list_del(&cmd->list);
2766
2767 if (match->sk == NULL) {
2768 match->sk = cmd->sk;
2769 sock_hold(match->sk);
2770 }
2771
2772 mgmt_pending_free(cmd);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002773}
Johan Hedberg5add6af2010-12-16 10:00:37 +02002774
Johan Hedberg744cf192011-11-08 20:40:14 +02002775int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg5add6af2010-12-16 10:00:37 +02002776{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002777 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002778 int err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002779
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002780 if (!test_bit(HCI_MGMT, &hdev->dev_flags))
2781 return 0;
2782
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002783 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
Johan Hedberg5add6af2010-12-16 10:00:37 +02002784
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002785 if (powered) {
2786 u8 scan = 0;
2787
2788 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
2789 scan |= SCAN_PAGE;
2790 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
2791 scan |= SCAN_INQUIRY;
2792
2793 if (scan)
2794 hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
Johan Hedberg504c8dc2012-02-23 13:30:41 +02002795
2796 update_class(hdev);
2797 update_eir(hdev);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002798 } else {
Johan Hedbergd4f68522012-03-02 03:07:07 +02002799 u8 status = MGMT_STATUS_NOT_POWERED;
Johan Hedberg744cf192011-11-08 20:40:14 +02002800 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002801 }
2802
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02002803 err = new_settings(hdev, match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002804
2805 if (match.sk)
2806 sock_put(match.sk);
2807
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002808 return err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002809}
Johan Hedberg73f22f62010-12-29 16:00:25 +02002810
Johan Hedberg744cf192011-11-08 20:40:14 +02002811int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg73f22f62010-12-29 16:00:25 +02002812{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002813 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002814 bool changed = false;
2815 int err = 0;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002816
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002817 if (discoverable) {
2818 if (!test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
2819 changed = true;
2820 } else {
2821 if (test_and_clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
2822 changed = true;
2823 }
Johan Hedberg73f22f62010-12-29 16:00:25 +02002824
Johan Hedberged9b5f22012-02-21 20:47:06 +02002825 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp,
2826 &match);
2827
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02002828 if (changed)
2829 err = new_settings(hdev, match.sk);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002830
Johan Hedberg73f22f62010-12-29 16:00:25 +02002831 if (match.sk)
2832 sock_put(match.sk);
2833
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002834 return err;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002835}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002836
Johan Hedberg744cf192011-11-08 20:40:14 +02002837int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002838{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002839 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002840 bool changed = false;
2841 int err = 0;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002842
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002843 if (connectable) {
2844 if (!test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags))
2845 changed = true;
2846 } else {
2847 if (test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags))
2848 changed = true;
2849 }
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002850
Johan Hedberged9b5f22012-02-21 20:47:06 +02002851 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev, settings_rsp,
2852 &match);
2853
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02002854 if (changed)
2855 err = new_settings(hdev, match.sk);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002856
2857 if (match.sk)
2858 sock_put(match.sk);
2859
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002860 return err;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002861}
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002862
Johan Hedberg744cf192011-11-08 20:40:14 +02002863int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002864{
Johan Hedbergca69b792011-11-11 18:10:00 +02002865 u8 mgmt_err = mgmt_status(status);
2866
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002867 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02002868 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Johan Hedbergca69b792011-11-11 18:10:00 +02002869 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002870
2871 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02002872 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Johan Hedbergca69b792011-11-11 18:10:00 +02002873 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002874
2875 return 0;
2876}
2877
Johan Hedberg744cf192011-11-08 20:40:14 +02002878int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
2879 u8 persistent)
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002880{
Johan Hedberg86742e12011-11-07 23:13:38 +02002881 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002882
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002883 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002884
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002885 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02002886 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
2887 ev.key.addr.type = MGMT_ADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002888 ev.key.type = key->type;
2889 memcpy(ev.key.val, key->val, 16);
2890 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002891
Johan Hedberg744cf192011-11-08 20:40:14 +02002892 return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002893}
Johan Hedbergf7520542011-01-20 12:34:39 +02002894
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002895int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
2896{
2897 struct mgmt_ev_new_long_term_key ev;
2898
2899 memset(&ev, 0, sizeof(ev));
2900
2901 ev.store_hint = persistent;
2902 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
2903 ev.key.addr.type = key->bdaddr_type;
2904 ev.key.authenticated = key->authenticated;
2905 ev.key.enc_size = key->enc_size;
2906 ev.key.ediv = key->ediv;
2907
2908 if (key->type == HCI_SMP_LTK)
2909 ev.key.master = 1;
2910
2911 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
2912 memcpy(ev.key.val, key->val, sizeof(key->val));
2913
2914 return mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev,
2915 &ev, sizeof(ev), NULL);
2916}
2917
Johan Hedbergafc747a2012-01-15 18:11:07 +02002918int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Johan Hedberg08c79b62012-02-23 22:31:51 +02002919 u8 addr_type, u32 flags, u8 *name,
2920 u8 name_len, u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02002921{
Johan Hedbergb644ba32012-01-17 21:48:47 +02002922 char buf[512];
2923 struct mgmt_ev_device_connected *ev = (void *) buf;
2924 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02002925
Johan Hedbergb644ba32012-01-17 21:48:47 +02002926 bacpy(&ev->addr.bdaddr, bdaddr);
2927 ev->addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02002928
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02002929 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02002930
Johan Hedbergb644ba32012-01-17 21:48:47 +02002931 if (name_len > 0)
2932 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
2933 name, name_len);
2934
2935 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
2936 eir_len = eir_append_data(&ev->eir[eir_len], eir_len,
2937 EIR_CLASS_OF_DEV, dev_class, 3);
2938
2939 put_unaligned_le16(eir_len, &ev->eir_len);
2940
2941 return mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
2942 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02002943}
2944
Johan Hedberg8962ee72011-01-20 12:40:27 +02002945static void disconnect_rsp(struct pending_cmd *cmd, void *data)
2946{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01002947 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002948 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02002949 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002950
Johan Hedberg88c3df12012-02-09 14:27:38 +02002951 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2952 rp.addr.type = cp->addr.type;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002953
Johan Hedbergaee9b212012-02-18 15:07:59 +02002954 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, 0, &rp,
2955 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002956
2957 *sk = cmd->sk;
2958 sock_hold(*sk);
2959
Johan Hedberga664b5b2011-02-19 12:06:02 -03002960 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002961}
2962
Johan Hedberg124f6e32012-02-09 13:50:12 +02002963static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02002964{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002965 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02002966 struct mgmt_cp_unpair_device *cp = cmd->param;
2967 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002968
2969 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02002970 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2971 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002972
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002973 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
2974
Johan Hedbergaee9b212012-02-18 15:07:59 +02002975 cmd_complete(cmd->sk, cmd->index, cmd->opcode, 0, &rp, sizeof(rp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02002976
2977 mgmt_pending_remove(cmd);
2978}
2979
Johan Hedbergafc747a2012-01-15 18:11:07 +02002980int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
2981 u8 link_type, u8 addr_type)
Johan Hedbergf7520542011-01-20 12:34:39 +02002982{
Johan Hedberg4c659c32011-11-07 23:13:39 +02002983 struct mgmt_addr_info ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002984 struct sock *sk = NULL;
2985 int err;
2986
Johan Hedberg744cf192011-11-08 20:40:14 +02002987 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02002988
Johan Hedbergf7520542011-01-20 12:34:39 +02002989 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02002990 ev.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02002991
Johan Hedbergafc747a2012-01-15 18:11:07 +02002992 err = mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev),
2993 sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002994
2995 if (sk)
2996 sock_put(sk);
2997
Johan Hedberg124f6e32012-02-09 13:50:12 +02002998 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002999 hdev);
Johan Hedberga8a1d192011-11-10 15:54:38 +02003000
Johan Hedberg8962ee72011-01-20 12:40:27 +02003001 return err;
3002}
3003
Johan Hedberg88c3df12012-02-09 14:27:38 +02003004int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
3005 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02003006{
Johan Hedberg88c3df12012-02-09 14:27:38 +02003007 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003008 struct pending_cmd *cmd;
3009 int err;
3010
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003011 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003012 if (!cmd)
3013 return -ENOENT;
3014
Johan Hedberg88c3df12012-02-09 14:27:38 +02003015 bacpy(&rp.addr.bdaddr, bdaddr);
3016 rp.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02003017
Johan Hedberg88c3df12012-02-09 14:27:38 +02003018 err = cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
Johan Hedbergaee9b212012-02-18 15:07:59 +02003019 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003020
Johan Hedberga664b5b2011-02-19 12:06:02 -03003021 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003022
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003023 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
3024 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003025 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02003026}
Johan Hedberg17d5c042011-01-22 06:09:08 +02003027
Johan Hedberg48264f02011-11-09 13:58:58 +02003028int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
3029 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02003030{
3031 struct mgmt_ev_connect_failed ev;
3032
Johan Hedberg4c659c32011-11-07 23:13:39 +02003033 bacpy(&ev.addr.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02003034 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003035 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003036
Johan Hedberg744cf192011-11-08 20:40:14 +02003037 return mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003038}
Johan Hedberg980e1a52011-01-22 06:10:07 +02003039
Johan Hedberg744cf192011-11-08 20:40:14 +02003040int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003041{
3042 struct mgmt_ev_pin_code_request ev;
3043
Johan Hedbergd8457692012-02-17 14:24:57 +02003044 bacpy(&ev.addr.bdaddr, bdaddr);
3045 ev.addr.type = MGMT_ADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02003046 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003047
Johan Hedberg744cf192011-11-08 20:40:14 +02003048 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01003049 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003050}
3051
Johan Hedberg744cf192011-11-08 20:40:14 +02003052int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3053 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003054{
3055 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003056 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003057 int err;
3058
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003059 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003060 if (!cmd)
3061 return -ENOENT;
3062
Johan Hedbergd8457692012-02-17 14:24:57 +02003063 bacpy(&rp.addr.bdaddr, bdaddr);
3064 rp.addr.type = MGMT_ADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003065
Johan Hedbergaee9b212012-02-18 15:07:59 +02003066 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
3067 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003068
Johan Hedberga664b5b2011-02-19 12:06:02 -03003069 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003070
3071 return err;
3072}
3073
Johan Hedberg744cf192011-11-08 20:40:14 +02003074int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3075 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003076{
3077 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003078 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003079 int err;
3080
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003081 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003082 if (!cmd)
3083 return -ENOENT;
3084
Johan Hedbergd8457692012-02-17 14:24:57 +02003085 bacpy(&rp.addr.bdaddr, bdaddr);
3086 rp.addr.type = MGMT_ADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003087
Johan Hedbergaee9b212012-02-18 15:07:59 +02003088 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
3089 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003090
Johan Hedberga664b5b2011-02-19 12:06:02 -03003091 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003092
3093 return err;
3094}
Johan Hedberga5c29682011-02-19 12:05:57 -03003095
Johan Hedberg744cf192011-11-08 20:40:14 +02003096int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003097 u8 link_type, u8 addr_type, __le32 value,
3098 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03003099{
3100 struct mgmt_ev_user_confirm_request ev;
3101
Johan Hedberg744cf192011-11-08 20:40:14 +02003102 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03003103
Johan Hedberg272d90d2012-02-09 15:26:12 +02003104 bacpy(&ev.addr.bdaddr, bdaddr);
3105 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07003106 ev.confirm_hint = confirm_hint;
Johan Hedberga5c29682011-02-19 12:05:57 -03003107 put_unaligned_le32(value, &ev.value);
3108
Johan Hedberg744cf192011-11-08 20:40:14 +02003109 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01003110 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03003111}
3112
Johan Hedberg272d90d2012-02-09 15:26:12 +02003113int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
3114 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08003115{
3116 struct mgmt_ev_user_passkey_request ev;
3117
3118 BT_DBG("%s", hdev->name);
3119
Johan Hedberg272d90d2012-02-09 15:26:12 +02003120 bacpy(&ev.addr.bdaddr, bdaddr);
3121 ev.addr.type = link_to_mgmt(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08003122
3123 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
3124 NULL);
3125}
3126
Brian Gix0df4c182011-11-16 13:53:13 -08003127static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003128 u8 link_type, u8 addr_type, u8 status,
3129 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03003130{
3131 struct pending_cmd *cmd;
3132 struct mgmt_rp_user_confirm_reply rp;
3133 int err;
3134
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003135 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03003136 if (!cmd)
3137 return -ENOENT;
3138
Johan Hedberg272d90d2012-02-09 15:26:12 +02003139 bacpy(&rp.addr.bdaddr, bdaddr);
3140 rp.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergaee9b212012-02-18 15:07:59 +02003141 err = cmd_complete(cmd->sk, hdev->id, opcode, mgmt_status(status),
3142 &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03003143
Johan Hedberga664b5b2011-02-19 12:06:02 -03003144 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03003145
3146 return err;
3147}
3148
Johan Hedberg744cf192011-11-08 20:40:14 +02003149int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003150 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003151{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003152 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3153 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003154}
3155
Johan Hedberg272d90d2012-02-09 15:26:12 +02003156int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3157 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003158{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003159 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3160 status, MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003161}
Johan Hedberg2a611692011-02-19 12:06:00 -03003162
Brian Gix604086b2011-11-23 08:28:33 -08003163int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003164 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003165{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003166 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3167 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003168}
3169
Johan Hedberg272d90d2012-02-09 15:26:12 +02003170int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3171 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003172{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003173 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3174 status, MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003175}
3176
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003177int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
3178 u8 addr_type, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03003179{
3180 struct mgmt_ev_auth_failed ev;
3181
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003182 bacpy(&ev.addr.bdaddr, bdaddr);
3183 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003184 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03003185
Johan Hedberg744cf192011-11-08 20:40:14 +02003186 return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03003187}
Johan Hedbergb312b1612011-03-16 14:29:37 +02003188
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003189int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
3190{
3191 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg47990ea2012-02-22 11:58:37 +02003192 bool changed = false;
3193 int err = 0;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003194
3195 if (status) {
3196 u8 mgmt_err = mgmt_status(status);
3197 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
3198 cmd_status_rsp, &mgmt_err);
3199 return 0;
3200 }
3201
Johan Hedberg47990ea2012-02-22 11:58:37 +02003202 if (test_bit(HCI_AUTH, &hdev->flags)) {
3203 if (!test_and_set_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
3204 changed = true;
3205 } else {
3206 if (test_and_clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
3207 changed = true;
3208 }
3209
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003210 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
3211 &match);
3212
Johan Hedberg47990ea2012-02-22 11:58:37 +02003213 if (changed)
3214 err = new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003215
3216 if (match.sk)
3217 sock_put(match.sk);
3218
3219 return err;
3220}
3221
Johan Hedbergcacaf522012-02-21 00:52:42 +02003222static int clear_eir(struct hci_dev *hdev)
3223{
3224 struct hci_cp_write_eir cp;
3225
3226 if (!(hdev->features[6] & LMP_EXT_INQ))
3227 return 0;
3228
Johan Hedbergc80da272012-02-22 15:38:48 +02003229 memset(hdev->eir, 0, sizeof(hdev->eir));
3230
Johan Hedbergcacaf522012-02-21 00:52:42 +02003231 memset(&cp, 0, sizeof(cp));
3232
3233 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
3234}
3235
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003236int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003237{
3238 struct cmd_lookup match = { NULL, hdev };
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003239 bool changed = false;
3240 int err = 0;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003241
3242 if (status) {
3243 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003244
3245 if (enable && test_and_clear_bit(HCI_SSP_ENABLED,
3246 &hdev->dev_flags))
3247 err = new_settings(hdev, NULL);
3248
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003249 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev,
3250 cmd_status_rsp, &mgmt_err);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003251
3252 return err;
3253 }
3254
3255 if (enable) {
3256 if (!test_and_set_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3257 changed = true;
3258 } else {
3259 if (test_and_clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3260 changed = true;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003261 }
3262
3263 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
3264
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003265 if (changed)
3266 err = new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003267
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02003268 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003269 sock_put(match.sk);
3270
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02003271 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3272 update_eir(hdev);
3273 else
3274 clear_eir(hdev);
Johan Hedbergcacaf522012-02-21 00:52:42 +02003275
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003276 return err;
3277}
3278
Johan Hedberg90e70452012-02-23 23:09:40 +02003279static void class_rsp(struct pending_cmd *cmd, void *data)
3280{
3281 struct cmd_lookup *match = data;
3282
3283 cmd_complete(cmd->sk, cmd->index, cmd->opcode, match->mgmt_status,
3284 match->hdev->dev_class, 3);
3285
3286 list_del(&cmd->list);
3287
3288 if (match->sk == NULL) {
3289 match->sk = cmd->sk;
3290 sock_hold(match->sk);
3291 }
3292
3293 mgmt_pending_free(cmd);
3294}
3295
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003296int mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
3297 u8 status)
3298{
Johan Hedberg90e70452012-02-23 23:09:40 +02003299 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
3300 int err = 0;
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003301
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02003302 clear_bit(HCI_PENDING_CLASS, &hdev->dev_flags);
3303
Johan Hedberg90e70452012-02-23 23:09:40 +02003304 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, class_rsp, &match);
3305 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, class_rsp, &match);
3306 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, class_rsp, &match);
3307
3308 if (!status)
3309 err = mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
3310 dev_class, 3, NULL);
3311
3312 if (match.sk)
3313 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003314
3315 return err;
3316}
3317
Johan Hedberg744cf192011-11-08 20:40:14 +02003318int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02003319{
3320 struct pending_cmd *cmd;
3321 struct mgmt_cp_set_local_name ev;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003322 bool changed = false;
3323 int err = 0;
3324
3325 if (memcmp(name, hdev->dev_name, sizeof(hdev->dev_name)) != 0) {
3326 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
3327 changed = true;
3328 }
Johan Hedbergb312b1612011-03-16 14:29:37 +02003329
3330 memset(&ev, 0, sizeof(ev));
3331 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003332 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003333
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003334 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003335 if (!cmd)
3336 goto send_event;
3337
Johan Hedberg7bdaae42012-02-22 21:39:58 +02003338 /* Always assume that either the short or the complete name has
3339 * changed if there was a pending mgmt command */
3340 changed = true;
3341
Johan Hedbergb312b1612011-03-16 14:29:37 +02003342 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02003343 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
Johan Hedbergca69b792011-11-11 18:10:00 +02003344 mgmt_status(status));
Johan Hedbergb312b1612011-03-16 14:29:37 +02003345 goto failed;
3346 }
3347
Johan Hedbergaee9b212012-02-18 15:07:59 +02003348 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0, &ev,
Johan Hedbergb312b1612011-03-16 14:29:37 +02003349 sizeof(ev));
3350 if (err < 0)
3351 goto failed;
3352
3353send_event:
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003354 if (changed)
3355 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev,
3356 sizeof(ev), cmd ? cmd->sk : NULL);
3357
Johan Hedbergf51d5b22012-02-22 18:17:32 +02003358 update_eir(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003359
3360failed:
3361 if (cmd)
3362 mgmt_pending_remove(cmd);
3363 return err;
3364}
Szymon Jancc35938b2011-03-22 13:12:21 +01003365
Johan Hedberg744cf192011-11-08 20:40:14 +02003366int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
3367 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01003368{
3369 struct pending_cmd *cmd;
3370 int err;
3371
Johan Hedberg744cf192011-11-08 20:40:14 +02003372 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01003373
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003374 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003375 if (!cmd)
3376 return -ENOENT;
3377
3378 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02003379 err = cmd_status(cmd->sk, hdev->id,
Johan Hedbergca69b792011-11-11 18:10:00 +02003380 MGMT_OP_READ_LOCAL_OOB_DATA,
3381 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01003382 } else {
3383 struct mgmt_rp_read_local_oob_data rp;
3384
3385 memcpy(rp.hash, hash, sizeof(rp.hash));
3386 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
3387
Johan Hedberg744cf192011-11-08 20:40:14 +02003388 err = cmd_complete(cmd->sk, hdev->id,
3389 MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergaee9b212012-02-18 15:07:59 +02003390 0, &rp, sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01003391 }
3392
3393 mgmt_pending_remove(cmd);
3394
3395 return err;
3396}
Johan Hedberge17acd42011-03-30 23:57:16 +03003397
Johan Hedberg06199cf2012-02-22 16:37:11 +02003398int mgmt_le_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
3399{
3400 struct cmd_lookup match = { NULL, hdev };
3401 bool changed = false;
3402 int err = 0;
3403
3404 if (status) {
3405 u8 mgmt_err = mgmt_status(status);
3406
3407 if (enable && test_and_clear_bit(HCI_LE_ENABLED,
3408 &hdev->dev_flags))
3409 err = new_settings(hdev, NULL);
3410
3411 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev,
3412 cmd_status_rsp, &mgmt_err);
3413
3414 return err;
3415 }
3416
3417 if (enable) {
3418 if (!test_and_set_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3419 changed = true;
3420 } else {
3421 if (test_and_clear_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3422 changed = true;
3423 }
3424
3425 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
3426
3427 if (changed)
3428 err = new_settings(hdev, match.sk);
3429
3430 if (match.sk)
3431 sock_put(match.sk);
3432
3433 return err;
3434}
3435
Johan Hedberg48264f02011-11-09 13:58:58 +02003436int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Johan Hedberg561aafb2012-01-04 13:31:59 +02003437 u8 addr_type, u8 *dev_class, s8 rssi,
Johan Hedberg388fc8f2012-02-23 00:38:59 +02003438 u8 cfm_name, u8 ssp, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03003439{
Johan Hedberge319d2e2012-01-15 19:51:59 +02003440 char buf[512];
3441 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02003442 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03003443
Johan Hedberg1dc06092012-01-15 21:01:23 +02003444 /* Leave 5 bytes for a potential CoD field */
3445 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Andre Guedes7d262f82012-01-10 18:20:49 -03003446 return -EINVAL;
3447
Johan Hedberg1dc06092012-01-15 21:01:23 +02003448 memset(buf, 0, sizeof(buf));
3449
Johan Hedberge319d2e2012-01-15 19:51:59 +02003450 bacpy(&ev->addr.bdaddr, bdaddr);
3451 ev->addr.type = link_to_mgmt(link_type, addr_type);
3452 ev->rssi = rssi;
Johan Hedberg9a395a82012-02-23 00:00:32 +02003453 if (cfm_name)
3454 ev->flags[0] |= MGMT_DEV_FOUND_CONFIRM_NAME;
Johan Hedberg388fc8f2012-02-23 00:38:59 +02003455 if (!ssp)
3456 ev->flags[0] |= MGMT_DEV_FOUND_LEGACY_PAIRING;
Johan Hedberge17acd42011-03-30 23:57:16 +03003457
Johan Hedberg1dc06092012-01-15 21:01:23 +02003458 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02003459 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03003460
Johan Hedberg1dc06092012-01-15 21:01:23 +02003461 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
3462 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
3463 dev_class, 3);
3464
3465 put_unaligned_le16(eir_len, &ev->eir_len);
3466
3467 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03003468
Johan Hedberge319d2e2012-01-15 19:51:59 +02003469 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03003470}
Johan Hedberga88a9652011-03-30 13:18:12 +03003471
Johan Hedbergb644ba32012-01-17 21:48:47 +02003472int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
3473 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03003474{
Johan Hedbergb644ba32012-01-17 21:48:47 +02003475 struct mgmt_ev_device_found *ev;
3476 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
3477 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03003478
Johan Hedbergb644ba32012-01-17 21:48:47 +02003479 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03003480
Johan Hedbergb644ba32012-01-17 21:48:47 +02003481 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03003482
Johan Hedbergb644ba32012-01-17 21:48:47 +02003483 bacpy(&ev->addr.bdaddr, bdaddr);
3484 ev->addr.type = link_to_mgmt(link_type, addr_type);
3485 ev->rssi = rssi;
3486
3487 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
3488 name_len);
3489
3490 put_unaligned_le16(eir_len, &ev->eir_len);
3491
Johan Hedberg053c7e02012-02-04 00:06:00 +02003492 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev,
3493 sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03003494}
Johan Hedberg314b2382011-04-27 10:29:57 -04003495
Andre Guedes7a135102011-11-09 17:14:25 -03003496int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
Johan Hedberg164a6e72011-11-01 17:06:44 +02003497{
3498 struct pending_cmd *cmd;
Johan Hedbergf808e162012-02-19 12:52:07 +02003499 u8 type;
Johan Hedberg164a6e72011-11-01 17:06:44 +02003500 int err;
3501
Andre Guedes203159d2012-02-13 15:41:01 -03003502 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3503
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003504 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003505 if (!cmd)
3506 return -ENOENT;
3507
Johan Hedbergf808e162012-02-19 12:52:07 +02003508 type = hdev->discovery.type;
3509
3510 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
3511 &type, sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02003512 mgmt_pending_remove(cmd);
3513
3514 return err;
3515}
3516
Andre Guedese6d465c2011-11-09 17:14:26 -03003517int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
3518{
3519 struct pending_cmd *cmd;
3520 int err;
3521
3522 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
3523 if (!cmd)
3524 return -ENOENT;
3525
Johan Hedbergd9306502012-02-20 23:25:18 +02003526 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
3527 &hdev->discovery.type,
3528 sizeof(hdev->discovery.type));
Johan Hedberg03811012010-12-08 00:21:06 +02003529 mgmt_pending_remove(cmd);
3530
3531 return err;
3532}
Johan Hedberg314b2382011-04-27 10:29:57 -04003533
Johan Hedberg744cf192011-11-08 20:40:14 +02003534int mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04003535{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02003536 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02003537 struct pending_cmd *cmd;
3538
Andre Guedes343fb142011-11-22 17:14:19 -03003539 BT_DBG("%s discovering %u", hdev->name, discovering);
3540
Johan Hedberg164a6e72011-11-01 17:06:44 +02003541 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003542 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003543 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003544 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003545
3546 if (cmd != NULL) {
Johan Hedbergf808e162012-02-19 12:52:07 +02003547 u8 type = hdev->discovery.type;
3548
Johan Hedbergd9306502012-02-20 23:25:18 +02003549 cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0,
Johan Hedbergf808e162012-02-19 12:52:07 +02003550 &type, sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02003551 mgmt_pending_remove(cmd);
3552 }
3553
Johan Hedbergf963e8e2012-02-20 23:30:44 +02003554 memset(&ev, 0, sizeof(ev));
3555 ev.type = hdev->discovery.type;
3556 ev.discovering = discovering;
3557
3558 return mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04003559}
Antti Julku5e762442011-08-25 16:48:02 +03003560
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003561int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003562{
3563 struct pending_cmd *cmd;
3564 struct mgmt_ev_device_blocked ev;
3565
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003566 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003567
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003568 bacpy(&ev.addr.bdaddr, bdaddr);
3569 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003570
Johan Hedberg744cf192011-11-08 20:40:14 +02003571 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
3572 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003573}
3574
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003575int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003576{
3577 struct pending_cmd *cmd;
3578 struct mgmt_ev_device_unblocked ev;
3579
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003580 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003581
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003582 bacpy(&ev.addr.bdaddr, bdaddr);
3583 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003584
Johan Hedberg744cf192011-11-08 20:40:14 +02003585 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
3586 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003587}
Marcel Holtmannd7b7e792012-02-20 21:47:49 +01003588
3589module_param(enable_hs, bool, 0644);
3590MODULE_PARM_DESC(enable_hs, "Enable High Speed support");
3591
3592module_param(enable_le, bool, 0644);
3593MODULE_PARM_DESC(enable_le, "Enable Low Energy support");