blob: 9f912dc71baec7c344f2307e609c9917b226be56 [file] [log] [blame]
Johan Hedberg03811012010-12-08 00:21:06 +02001/*
2 BlueZ - Bluetooth protocol stack for Linux
Johan Hedbergea585ab2012-02-17 14:50:39 +02003
Johan Hedberg03811012010-12-08 00:21:06 +02004 Copyright (C) 2010 Nokia Corporation
Johan Hedbergea585ab2012-02-17 14:50:39 +02005 Copyright (C) 2011-2012 Intel Corporation
Johan Hedberg03811012010-12-08 00:21:06 +02006
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License version 2 as
9 published by the Free Software Foundation;
10
11 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
12 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
13 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
14 IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
15 CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
16 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19
20 ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
21 COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
22 SOFTWARE IS DISCLAIMED.
23*/
24
25/* Bluetooth HCI Management interface */
26
Johan Hedbergca69b792011-11-11 18:10:00 +020027#include <linux/kernel.h>
Szymon Janc72359752011-02-17 14:16:32 +010028#include <linux/uaccess.h>
Paul Gortmaker3a9a2312011-05-27 09:12:25 -040029#include <linux/module.h>
Johan Hedberg03811012010-12-08 00:21:06 +020030#include <asm/unaligned.h>
31
32#include <net/bluetooth/bluetooth.h>
33#include <net/bluetooth/hci_core.h>
34#include <net/bluetooth/mgmt.h>
Brian Gix5fe57d92011-12-21 16:12:13 -080035#include <net/bluetooth/smp.h>
Johan Hedberg03811012010-12-08 00:21:06 +020036
Marcel Holtmannd7b7e792012-02-20 21:47:49 +010037bool enable_hs;
38bool enable_le;
39
Johan Hedberg2da9c552012-02-17 14:39:28 +020040#define MGMT_VERSION 1
41#define MGMT_REVISION 0
Johan Hedberg02d98122010-12-13 21:07:04 +020042
Johan Hedberge70bb2e2012-02-13 16:59:33 +020043static const u16 mgmt_commands[] = {
44 MGMT_OP_READ_INDEX_LIST,
45 MGMT_OP_READ_INFO,
46 MGMT_OP_SET_POWERED,
47 MGMT_OP_SET_DISCOVERABLE,
48 MGMT_OP_SET_CONNECTABLE,
49 MGMT_OP_SET_FAST_CONNECTABLE,
50 MGMT_OP_SET_PAIRABLE,
51 MGMT_OP_SET_LINK_SECURITY,
52 MGMT_OP_SET_SSP,
53 MGMT_OP_SET_HS,
54 MGMT_OP_SET_LE,
55 MGMT_OP_SET_DEV_CLASS,
56 MGMT_OP_SET_LOCAL_NAME,
57 MGMT_OP_ADD_UUID,
58 MGMT_OP_REMOVE_UUID,
59 MGMT_OP_LOAD_LINK_KEYS,
60 MGMT_OP_LOAD_LONG_TERM_KEYS,
61 MGMT_OP_DISCONNECT,
62 MGMT_OP_GET_CONNECTIONS,
63 MGMT_OP_PIN_CODE_REPLY,
64 MGMT_OP_PIN_CODE_NEG_REPLY,
65 MGMT_OP_SET_IO_CAPABILITY,
66 MGMT_OP_PAIR_DEVICE,
67 MGMT_OP_CANCEL_PAIR_DEVICE,
68 MGMT_OP_UNPAIR_DEVICE,
69 MGMT_OP_USER_CONFIRM_REPLY,
70 MGMT_OP_USER_CONFIRM_NEG_REPLY,
71 MGMT_OP_USER_PASSKEY_REPLY,
72 MGMT_OP_USER_PASSKEY_NEG_REPLY,
73 MGMT_OP_READ_LOCAL_OOB_DATA,
74 MGMT_OP_ADD_REMOTE_OOB_DATA,
75 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
76 MGMT_OP_START_DISCOVERY,
77 MGMT_OP_STOP_DISCOVERY,
78 MGMT_OP_CONFIRM_NAME,
79 MGMT_OP_BLOCK_DEVICE,
80 MGMT_OP_UNBLOCK_DEVICE,
81};
82
83static const u16 mgmt_events[] = {
84 MGMT_EV_CONTROLLER_ERROR,
85 MGMT_EV_INDEX_ADDED,
86 MGMT_EV_INDEX_REMOVED,
87 MGMT_EV_NEW_SETTINGS,
88 MGMT_EV_CLASS_OF_DEV_CHANGED,
89 MGMT_EV_LOCAL_NAME_CHANGED,
90 MGMT_EV_NEW_LINK_KEY,
91 MGMT_EV_NEW_LONG_TERM_KEY,
92 MGMT_EV_DEVICE_CONNECTED,
93 MGMT_EV_DEVICE_DISCONNECTED,
94 MGMT_EV_CONNECT_FAILED,
95 MGMT_EV_PIN_CODE_REQUEST,
96 MGMT_EV_USER_CONFIRM_REQUEST,
97 MGMT_EV_USER_PASSKEY_REQUEST,
98 MGMT_EV_AUTH_FAILED,
99 MGMT_EV_DEVICE_FOUND,
100 MGMT_EV_DISCOVERING,
101 MGMT_EV_DEVICE_BLOCKED,
102 MGMT_EV_DEVICE_UNBLOCKED,
103 MGMT_EV_DEVICE_UNPAIRED,
104};
105
Andre Guedes3fd24152012-02-03 17:48:01 -0300106/*
107 * These LE scan and inquiry parameters were chosen according to LE General
108 * Discovery Procedure specification.
109 */
110#define LE_SCAN_TYPE 0x01
111#define LE_SCAN_WIN 0x12
112#define LE_SCAN_INT 0x12
113#define LE_SCAN_TIMEOUT_LE_ONLY 10240 /* TGAP(gen_disc_scan_min) */
Andre Guedes5e0452c2012-02-17 20:39:38 -0300114#define LE_SCAN_TIMEOUT_BREDR_LE 5120 /* TGAP(100)/2 */
Andre Guedes3fd24152012-02-03 17:48:01 -0300115
Andre Guedese8777522012-02-03 17:48:02 -0300116#define INQUIRY_LEN_BREDR 0x08 /* TGAP(100) */
Andre Guedes5e0452c2012-02-17 20:39:38 -0300117#define INQUIRY_LEN_BREDR_LE 0x04 /* TGAP(100)/2 */
Andre Guedes2519a1f2011-11-07 11:45:24 -0300118
Johan Hedberg7d785252011-12-15 00:47:39 +0200119#define SERVICE_CACHE_TIMEOUT (5 * 1000)
120
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200121#define hdev_is_powered(hdev) (test_bit(HCI_UP, &hdev->flags) && \
122 !test_bit(HCI_AUTO_OFF, &hdev->dev_flags))
123
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200124struct pending_cmd {
125 struct list_head list;
Johan Hedbergfc2f4b12011-11-09 13:58:56 +0200126 u16 opcode;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200127 int index;
Szymon Jancc68fb7f2011-03-22 13:12:19 +0100128 void *param;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200129 struct sock *sk;
Johan Hedberge9a416b2011-02-19 12:05:56 -0300130 void *user_data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200131};
132
Johan Hedbergca69b792011-11-11 18:10:00 +0200133/* HCI to MGMT error code conversion table */
134static u8 mgmt_status_table[] = {
135 MGMT_STATUS_SUCCESS,
136 MGMT_STATUS_UNKNOWN_COMMAND, /* Unknown Command */
137 MGMT_STATUS_NOT_CONNECTED, /* No Connection */
138 MGMT_STATUS_FAILED, /* Hardware Failure */
139 MGMT_STATUS_CONNECT_FAILED, /* Page Timeout */
140 MGMT_STATUS_AUTH_FAILED, /* Authentication Failed */
141 MGMT_STATUS_NOT_PAIRED, /* PIN or Key Missing */
142 MGMT_STATUS_NO_RESOURCES, /* Memory Full */
143 MGMT_STATUS_TIMEOUT, /* Connection Timeout */
144 MGMT_STATUS_NO_RESOURCES, /* Max Number of Connections */
145 MGMT_STATUS_NO_RESOURCES, /* Max Number of SCO Connections */
146 MGMT_STATUS_ALREADY_CONNECTED, /* ACL Connection Exists */
147 MGMT_STATUS_BUSY, /* Command Disallowed */
148 MGMT_STATUS_NO_RESOURCES, /* Rejected Limited Resources */
149 MGMT_STATUS_REJECTED, /* Rejected Security */
150 MGMT_STATUS_REJECTED, /* Rejected Personal */
151 MGMT_STATUS_TIMEOUT, /* Host Timeout */
152 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Feature */
153 MGMT_STATUS_INVALID_PARAMS, /* Invalid Parameters */
154 MGMT_STATUS_DISCONNECTED, /* OE User Ended Connection */
155 MGMT_STATUS_NO_RESOURCES, /* OE Low Resources */
156 MGMT_STATUS_DISCONNECTED, /* OE Power Off */
157 MGMT_STATUS_DISCONNECTED, /* Connection Terminated */
158 MGMT_STATUS_BUSY, /* Repeated Attempts */
159 MGMT_STATUS_REJECTED, /* Pairing Not Allowed */
160 MGMT_STATUS_FAILED, /* Unknown LMP PDU */
161 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Remote Feature */
162 MGMT_STATUS_REJECTED, /* SCO Offset Rejected */
163 MGMT_STATUS_REJECTED, /* SCO Interval Rejected */
164 MGMT_STATUS_REJECTED, /* Air Mode Rejected */
165 MGMT_STATUS_INVALID_PARAMS, /* Invalid LMP Parameters */
166 MGMT_STATUS_FAILED, /* Unspecified Error */
167 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported LMP Parameter Value */
168 MGMT_STATUS_FAILED, /* Role Change Not Allowed */
169 MGMT_STATUS_TIMEOUT, /* LMP Response Timeout */
170 MGMT_STATUS_FAILED, /* LMP Error Transaction Collision */
171 MGMT_STATUS_FAILED, /* LMP PDU Not Allowed */
172 MGMT_STATUS_REJECTED, /* Encryption Mode Not Accepted */
173 MGMT_STATUS_FAILED, /* Unit Link Key Used */
174 MGMT_STATUS_NOT_SUPPORTED, /* QoS Not Supported */
175 MGMT_STATUS_TIMEOUT, /* Instant Passed */
176 MGMT_STATUS_NOT_SUPPORTED, /* Pairing Not Supported */
177 MGMT_STATUS_FAILED, /* Transaction Collision */
178 MGMT_STATUS_INVALID_PARAMS, /* Unacceptable Parameter */
179 MGMT_STATUS_REJECTED, /* QoS Rejected */
180 MGMT_STATUS_NOT_SUPPORTED, /* Classification Not Supported */
181 MGMT_STATUS_REJECTED, /* Insufficient Security */
182 MGMT_STATUS_INVALID_PARAMS, /* Parameter Out Of Range */
183 MGMT_STATUS_BUSY, /* Role Switch Pending */
184 MGMT_STATUS_FAILED, /* Slot Violation */
185 MGMT_STATUS_FAILED, /* Role Switch Failed */
186 MGMT_STATUS_INVALID_PARAMS, /* EIR Too Large */
187 MGMT_STATUS_NOT_SUPPORTED, /* Simple Pairing Not Supported */
188 MGMT_STATUS_BUSY, /* Host Busy Pairing */
189 MGMT_STATUS_REJECTED, /* Rejected, No Suitable Channel */
190 MGMT_STATUS_BUSY, /* Controller Busy */
191 MGMT_STATUS_INVALID_PARAMS, /* Unsuitable Connection Interval */
192 MGMT_STATUS_TIMEOUT, /* Directed Advertising Timeout */
193 MGMT_STATUS_AUTH_FAILED, /* Terminated Due to MIC Failure */
194 MGMT_STATUS_CONNECT_FAILED, /* Connection Establishment Failed */
195 MGMT_STATUS_CONNECT_FAILED, /* MAC Connection Failed */
196};
197
198static u8 mgmt_status(u8 hci_status)
199{
200 if (hci_status < ARRAY_SIZE(mgmt_status_table))
201 return mgmt_status_table[hci_status];
202
203 return MGMT_STATUS_FAILED;
204}
205
Szymon Janc4e51eae2011-02-25 19:05:48 +0100206static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200207{
208 struct sk_buff *skb;
209 struct mgmt_hdr *hdr;
210 struct mgmt_ev_cmd_status *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300211 int err;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200212
Szymon Janc34eb5252011-02-28 14:10:08 +0100213 BT_DBG("sock %p, index %u, cmd %u, status %u", sk, index, cmd, status);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200214
215 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_ATOMIC);
216 if (!skb)
217 return -ENOMEM;
218
219 hdr = (void *) skb_put(skb, sizeof(*hdr));
220
221 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_STATUS);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100222 hdr->index = cpu_to_le16(index);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200223 hdr->len = cpu_to_le16(sizeof(*ev));
224
225 ev = (void *) skb_put(skb, sizeof(*ev));
226 ev->status = status;
227 put_unaligned_le16(cmd, &ev->opcode);
228
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300229 err = sock_queue_rcv_skb(sk, skb);
230 if (err < 0)
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200231 kfree_skb(skb);
232
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300233 return err;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200234}
235
Johan 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 Hedberga38528f2011-01-22 06:46:43 +0200270static int read_version(struct sock *sk)
271{
272 struct mgmt_rp_read_version rp;
273
274 BT_DBG("sock %p", sk);
275
276 rp.version = MGMT_VERSION;
277 put_unaligned_le16(MGMT_REVISION, &rp.revision);
278
Johan Hedbergaee9b212012-02-18 15:07:59 +0200279 return cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, 0, &rp,
Szymon Janc4e51eae2011-02-25 19:05:48 +0100280 sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200281}
282
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200283static int read_commands(struct sock *sk)
284{
285 struct mgmt_rp_read_commands *rp;
286 u16 num_commands = ARRAY_SIZE(mgmt_commands);
287 u16 num_events = ARRAY_SIZE(mgmt_events);
288 u16 *opcode;
289 size_t rp_size;
290 int i, err;
291
292 BT_DBG("sock %p", sk);
293
294 rp_size = sizeof(*rp) + ((num_commands + num_events) * sizeof(u16));
295
296 rp = kmalloc(rp_size, GFP_KERNEL);
297 if (!rp)
298 return -ENOMEM;
299
300 put_unaligned_le16(num_commands, &rp->num_commands);
301 put_unaligned_le16(num_events, &rp->num_events);
302
303 for (i = 0, opcode = rp->opcodes; i < num_commands; i++, opcode++)
304 put_unaligned_le16(mgmt_commands[i], opcode);
305
306 for (i = 0; i < num_events; i++, opcode++)
307 put_unaligned_le16(mgmt_events[i], opcode);
308
Johan Hedbergaee9b212012-02-18 15:07:59 +0200309 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_COMMANDS, 0, rp,
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200310 rp_size);
311 kfree(rp);
312
313 return err;
314}
315
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200316static int read_index_list(struct sock *sk)
317{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200318 struct mgmt_rp_read_index_list *rp;
319 struct list_head *p;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200320 struct hci_dev *d;
Johan Hedberga38528f2011-01-22 06:46:43 +0200321 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200322 u16 count;
Johan Hedberga38528f2011-01-22 06:46:43 +0200323 int i, err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200324
325 BT_DBG("sock %p", sk);
326
327 read_lock(&hci_dev_list_lock);
328
329 count = 0;
330 list_for_each(p, &hci_dev_list) {
331 count++;
332 }
333
Johan Hedberga38528f2011-01-22 06:46:43 +0200334 rp_len = sizeof(*rp) + (2 * count);
335 rp = kmalloc(rp_len, GFP_ATOMIC);
336 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100337 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200338 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100339 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200340
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200341 put_unaligned_le16(count, &rp->num_controllers);
342
343 i = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200344 list_for_each_entry(d, &hci_dev_list, list) {
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200345 if (test_bit(HCI_SETUP, &d->dev_flags))
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200346 continue;
347
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200348 put_unaligned_le16(d->id, &rp->index[i++]);
349 BT_DBG("Added hci%u", d->id);
350 }
351
352 read_unlock(&hci_dev_list_lock);
353
Johan Hedbergaee9b212012-02-18 15:07:59 +0200354 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST, 0, rp,
Szymon Janc4e51eae2011-02-25 19:05:48 +0100355 rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200356
Johan Hedberga38528f2011-01-22 06:46:43 +0200357 kfree(rp);
358
359 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200360}
361
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200362static u32 get_supported_settings(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +0200363{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200364 u32 settings = 0;
Johan Hedberg03811012010-12-08 00:21:06 +0200365
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200366 settings |= MGMT_SETTING_POWERED;
367 settings |= MGMT_SETTING_CONNECTABLE;
368 settings |= MGMT_SETTING_FAST_CONNECTABLE;
369 settings |= MGMT_SETTING_DISCOVERABLE;
370 settings |= MGMT_SETTING_PAIRABLE;
Johan Hedberg03811012010-12-08 00:21:06 +0200371
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200372 if (hdev->features[6] & LMP_SIMPLE_PAIR)
373 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200374
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200375 if (!(hdev->features[4] & LMP_NO_BREDR)) {
376 settings |= MGMT_SETTING_BREDR;
377 settings |= MGMT_SETTING_LINK_SECURITY;
378 }
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200379
Marcel Holtmannd7b7e792012-02-20 21:47:49 +0100380 if (enable_hs)
381 settings |= MGMT_SETTING_HS;
382
383 if (enable_le) {
384 if (hdev->features[4] & LMP_LE)
385 settings |= MGMT_SETTING_LE;
386 }
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200387
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200388 return settings;
389}
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200390
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200391static u32 get_current_settings(struct hci_dev *hdev)
392{
393 u32 settings = 0;
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200394
Johan Hedbergf1f0eb02012-02-21 17:15:41 +0200395 if (hdev_is_powered(hdev))
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100396 settings |= MGMT_SETTING_POWERED;
397
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200398 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200399 settings |= MGMT_SETTING_CONNECTABLE;
400
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200401 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200402 settings |= MGMT_SETTING_DISCOVERABLE;
403
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200404 if (test_bit(HCI_PAIRABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200405 settings |= MGMT_SETTING_PAIRABLE;
406
407 if (!(hdev->features[4] & LMP_NO_BREDR))
408 settings |= MGMT_SETTING_BREDR;
409
Johan Hedberg06199cf2012-02-22 16:37:11 +0200410 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200411 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200412
Johan Hedberg47990ea2012-02-22 11:58:37 +0200413 if (test_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200414 settings |= MGMT_SETTING_LINK_SECURITY;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200415
Johan Hedberg84bde9d2012-01-25 14:21:06 +0200416 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200417 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200418
Johan Hedberg6d80dfd2012-02-20 23:50:38 +0200419 if (test_bit(HCI_HS_ENABLED, &hdev->dev_flags))
420 settings |= MGMT_SETTING_HS;
421
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200422 return settings;
Johan Hedbergc542a062011-01-26 13:11:03 +0200423}
424
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300425#define PNP_INFO_SVCLASS_ID 0x1200
426
427static u8 bluetooth_base_uuid[] = {
428 0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80,
429 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
430};
431
432static u16 get_uuid16(u8 *uuid128)
433{
434 u32 val;
435 int i;
436
437 for (i = 0; i < 12; i++) {
438 if (bluetooth_base_uuid[i] != uuid128[i])
439 return 0;
440 }
441
442 memcpy(&val, &uuid128[12], 4);
443
444 val = le32_to_cpu(val);
445 if (val > 0xffff)
446 return 0;
447
448 return (u16) val;
449}
450
451static void create_eir(struct hci_dev *hdev, u8 *data)
452{
453 u8 *ptr = data;
454 u16 eir_len = 0;
455 u16 uuid16_list[HCI_MAX_EIR_LENGTH / sizeof(u16)];
456 int i, truncated = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200457 struct bt_uuid *uuid;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300458 size_t name_len;
459
460 name_len = strlen(hdev->dev_name);
461
462 if (name_len > 0) {
463 /* EIR Data type */
464 if (name_len > 48) {
465 name_len = 48;
466 ptr[1] = EIR_NAME_SHORT;
467 } else
468 ptr[1] = EIR_NAME_COMPLETE;
469
470 /* EIR Data length */
471 ptr[0] = name_len + 1;
472
473 memcpy(ptr + 2, hdev->dev_name, name_len);
474
475 eir_len += (name_len + 2);
476 ptr += (name_len + 2);
477 }
478
479 memset(uuid16_list, 0, sizeof(uuid16_list));
480
481 /* Group all UUID16 types */
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200482 list_for_each_entry(uuid, &hdev->uuids, list) {
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300483 u16 uuid16;
484
485 uuid16 = get_uuid16(uuid->uuid);
486 if (uuid16 == 0)
487 return;
488
489 if (uuid16 < 0x1100)
490 continue;
491
492 if (uuid16 == PNP_INFO_SVCLASS_ID)
493 continue;
494
495 /* Stop if not enough space to put next UUID */
496 if (eir_len + 2 + sizeof(u16) > HCI_MAX_EIR_LENGTH) {
497 truncated = 1;
498 break;
499 }
500
501 /* Check for duplicates */
502 for (i = 0; uuid16_list[i] != 0; i++)
503 if (uuid16_list[i] == uuid16)
504 break;
505
506 if (uuid16_list[i] == 0) {
507 uuid16_list[i] = uuid16;
508 eir_len += sizeof(u16);
509 }
510 }
511
512 if (uuid16_list[0] != 0) {
513 u8 *length = ptr;
514
515 /* EIR Data type */
516 ptr[1] = truncated ? EIR_UUID16_SOME : EIR_UUID16_ALL;
517
518 ptr += 2;
519 eir_len += 2;
520
521 for (i = 0; uuid16_list[i] != 0; i++) {
522 *ptr++ = (uuid16_list[i] & 0x00ff);
523 *ptr++ = (uuid16_list[i] & 0xff00) >> 8;
524 }
525
526 /* EIR Data length */
527 *length = (i * sizeof(u16)) + 1;
528 }
529}
530
531static int update_eir(struct hci_dev *hdev)
532{
533 struct hci_cp_write_eir cp;
534
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200535 if (!hdev_is_powered(hdev))
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200536 return 0;
537
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300538 if (!(hdev->features[6] & LMP_EXT_INQ))
539 return 0;
540
Johan Hedberg84bde9d2012-01-25 14:21:06 +0200541 if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300542 return 0;
543
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200544 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300545 return 0;
546
547 memset(&cp, 0, sizeof(cp));
548
549 create_eir(hdev, cp.data);
550
551 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
552 return 0;
553
554 memcpy(hdev->eir, cp.data, sizeof(cp.data));
555
556 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
557}
558
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200559static u8 get_service_classes(struct hci_dev *hdev)
560{
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300561 struct bt_uuid *uuid;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200562 u8 val = 0;
563
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300564 list_for_each_entry(uuid, &hdev->uuids, list)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200565 val |= uuid->svc_hint;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200566
567 return val;
568}
569
570static int update_class(struct hci_dev *hdev)
571{
572 u8 cod[3];
Johan Hedbergc95f0ba2012-02-23 22:54:38 +0200573 int err;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200574
575 BT_DBG("%s", hdev->name);
576
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200577 if (!hdev_is_powered(hdev))
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200578 return 0;
579
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200580 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200581 return 0;
582
583 cod[0] = hdev->minor_class;
584 cod[1] = hdev->major_class;
585 cod[2] = get_service_classes(hdev);
586
587 if (memcmp(cod, hdev->dev_class, 3) == 0)
588 return 0;
589
Johan Hedbergc95f0ba2012-02-23 22:54:38 +0200590 err = hci_send_cmd(hdev, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
591 if (err == 0)
592 set_bit(HCI_PENDING_CLASS, &hdev->dev_flags);
593
594 return err;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200595}
596
Johan Hedberg7d785252011-12-15 00:47:39 +0200597static void service_cache_off(struct work_struct *work)
598{
599 struct hci_dev *hdev = container_of(work, struct hci_dev,
600 service_cache.work);
601
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200602 if (!test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200603 return;
604
605 hci_dev_lock(hdev);
606
607 update_eir(hdev);
608 update_class(hdev);
609
610 hci_dev_unlock(hdev);
611}
612
613static void mgmt_init_hdev(struct hci_dev *hdev)
614{
Johan Hedberg0cbf4ed2012-02-21 17:25:22 +0200615 if (!test_and_set_bit(HCI_MGMT, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +0200616 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
617
Johan Hedberg0cbf4ed2012-02-21 17:25:22 +0200618 /* Non-mgmt controlled devices get this bit set
619 * implicitly so that pairing works for them, however
620 * for mgmt we require user-space to explicitly enable
621 * it
622 */
623 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
624 }
Johan Hedberg7d785252011-12-15 00:47:39 +0200625}
626
Johan Hedberg03811012010-12-08 00:21:06 +0200627static int read_controller_info(struct sock *sk, u16 index)
628{
629 struct mgmt_rp_read_info rp;
630 struct hci_dev *hdev;
631
632 BT_DBG("sock %p hci%u", sk, index);
633
634 hdev = hci_dev_get(index);
635 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200636 return cmd_status(sk, index, MGMT_OP_READ_INFO,
637 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200638
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300639 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200640
Johan Hedberg7d785252011-12-15 00:47:39 +0200641 if (test_and_clear_bit(HCI_PI_MGMT_INIT, &hci_pi(sk)->flags))
642 mgmt_init_hdev(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200643
644 memset(&rp, 0, sizeof(rp));
645
Johan Hedberg03811012010-12-08 00:21:06 +0200646 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200647
648 rp.version = hdev->hci_ver;
649
Johan Hedberg03811012010-12-08 00:21:06 +0200650 put_unaligned_le16(hdev->manufacturer, &rp.manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200651
652 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
653 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
654
655 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedberg03811012010-12-08 00:21:06 +0200656
657 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
Johan Hedberg27fcc362012-02-22 21:46:22 +0200658 memcpy(rp.short_name, hdev->short_name, sizeof(hdev->short_name));
Johan Hedberg03811012010-12-08 00:21:06 +0200659
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300660 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200661 hci_dev_put(hdev);
662
Johan Hedbergaee9b212012-02-18 15:07:59 +0200663 return cmd_complete(sk, index, MGMT_OP_READ_INFO, 0, &rp, sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +0200664}
665
666static void mgmt_pending_free(struct pending_cmd *cmd)
667{
668 sock_put(cmd->sk);
669 kfree(cmd->param);
670 kfree(cmd);
671}
672
673static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
674 struct hci_dev *hdev,
675 void *data, u16 len)
676{
677 struct pending_cmd *cmd;
678
679 cmd = kmalloc(sizeof(*cmd), GFP_ATOMIC);
680 if (!cmd)
681 return NULL;
682
683 cmd->opcode = opcode;
684 cmd->index = hdev->id;
685
686 cmd->param = kmalloc(len, GFP_ATOMIC);
687 if (!cmd->param) {
688 kfree(cmd);
689 return NULL;
690 }
691
692 if (data)
693 memcpy(cmd->param, data, len);
694
695 cmd->sk = sk;
696 sock_hold(sk);
697
698 list_add(&cmd->list, &hdev->mgmt_pending);
699
700 return cmd;
701}
702
703static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
704 void (*cb)(struct pending_cmd *cmd, void *data),
705 void *data)
706{
707 struct list_head *p, *n;
708
709 list_for_each_safe(p, n, &hdev->mgmt_pending) {
710 struct pending_cmd *cmd;
711
712 cmd = list_entry(p, struct pending_cmd, list);
713
714 if (opcode > 0 && cmd->opcode != opcode)
715 continue;
716
717 cb(cmd, data);
718 }
719}
720
721static struct pending_cmd *mgmt_pending_find(u16 opcode, struct hci_dev *hdev)
722{
723 struct pending_cmd *cmd;
724
725 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
726 if (cmd->opcode == opcode)
727 return cmd;
728 }
729
730 return NULL;
731}
732
733static void mgmt_pending_remove(struct pending_cmd *cmd)
734{
735 list_del(&cmd->list);
736 mgmt_pending_free(cmd);
737}
738
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200739static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +0200740{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200741 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +0200742
Johan Hedbergaee9b212012-02-18 15:07:59 +0200743 return cmd_complete(sk, hdev->id, opcode, 0, &settings,
744 sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +0200745}
746
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300747static int set_powered(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200748{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300749 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200750 struct hci_dev *hdev;
751 struct pending_cmd *cmd;
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200752 int err;
Johan Hedberg03811012010-12-08 00:21:06 +0200753
Johan Hedberg03811012010-12-08 00:21:06 +0200754 BT_DBG("request for hci%u", index);
755
756 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200757 return cmd_status(sk, index, MGMT_OP_SET_POWERED,
758 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200759
760 hdev = hci_dev_get(index);
761 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200762 return cmd_status(sk, index, MGMT_OP_SET_POWERED,
763 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200764
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300765 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200766
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100767 if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) {
768 cancel_delayed_work(&hdev->power_off);
769
770 if (cp->val) {
771 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
772 mgmt_powered(hdev, 1);
773 goto failed;
774 }
775 }
776
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200777 if (!!cp->val == hdev_is_powered(hdev)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200778 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200779 goto failed;
780 }
781
782 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200783 err = cmd_status(sk, index, MGMT_OP_SET_POWERED,
784 MGMT_STATUS_BUSY);
Johan Hedberg03811012010-12-08 00:21:06 +0200785 goto failed;
786 }
787
788 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
789 if (!cmd) {
790 err = -ENOMEM;
791 goto failed;
792 }
793
794 if (cp->val)
Gustavo F. Padovan7f971042011-12-18 12:40:32 -0200795 schedule_work(&hdev->power_on);
Johan Hedberg03811012010-12-08 00:21:06 +0200796 else
Gustavo F. Padovan80b7ab32011-12-17 14:52:27 -0200797 schedule_work(&hdev->power_off.work);
Johan Hedberg03811012010-12-08 00:21:06 +0200798
799 err = 0;
800
801failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300802 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200803 hci_dev_put(hdev);
804 return err;
805}
806
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200807static int mgmt_event(u16 event, struct hci_dev *hdev, void *data,
808 u16 data_len, struct sock *skip_sk)
809{
810 struct sk_buff *skb;
811 struct mgmt_hdr *hdr;
812
813 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_ATOMIC);
814 if (!skb)
815 return -ENOMEM;
816
817 hdr = (void *) skb_put(skb, sizeof(*hdr));
818 hdr->opcode = cpu_to_le16(event);
819 if (hdev)
820 hdr->index = cpu_to_le16(hdev->id);
821 else
822 hdr->index = cpu_to_le16(MGMT_INDEX_NONE);
823 hdr->len = cpu_to_le16(data_len);
824
825 if (data)
826 memcpy(skb_put(skb, data_len), data, data_len);
827
Marcel Holtmann97e0bde2012-02-22 13:49:28 +0100828 /* Time stamp */
829 __net_timestamp(skb);
830
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200831 hci_send_to_control(skb, skip_sk);
832 kfree_skb(skb);
833
834 return 0;
835}
836
837static int new_settings(struct hci_dev *hdev, struct sock *skip)
838{
839 __le32 ev;
840
841 ev = cpu_to_le32(get_current_settings(hdev));
842
843 return mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), skip);
844}
845
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300846static int set_discoverable(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200847{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300848 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberge41d8b42010-12-13 21:07:03 +0200849 struct hci_dev *hdev;
Johan Hedberg03811012010-12-08 00:21:06 +0200850 struct pending_cmd *cmd;
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200851 u16 timeout;
Johan Hedberg03811012010-12-08 00:21:06 +0200852 u8 scan;
853 int err;
854
Johan Hedberg03811012010-12-08 00:21:06 +0200855 BT_DBG("request for hci%u", index);
856
857 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200858 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
859 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200860
Marcel Holtmann24c54a92012-02-22 18:06:34 +0100861 timeout = get_unaligned_le16(&cp->timeout);
862 if (!cp->val && timeout > 0)
863 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
864 MGMT_STATUS_INVALID_PARAMS);
865
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200866 hdev = hci_dev_get(index);
867 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200868 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
869 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200870
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300871 hci_dev_lock(hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200872
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200873 if (!hdev_is_powered(hdev) && timeout > 0) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200874 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
875 MGMT_STATUS_NOT_POWERED);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200876 goto failed;
877 }
878
879 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
880 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200881 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
882 MGMT_STATUS_BUSY);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200883 goto failed;
884 }
885
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200886 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) {
887 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
888 MGMT_STATUS_REJECTED);
889 goto failed;
890 }
891
892 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200893 bool changed = false;
894
895 if (!!cp->val != test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
896 change_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
897 changed = true;
898 }
899
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200900 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200901 if (err < 0)
902 goto failed;
903
904 if (changed)
905 err = new_settings(hdev, sk);
906
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200907 goto failed;
908 }
909
910 if (!!cp->val == test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
Marcel Holtmann955638e2012-02-22 18:21:00 +0100911 if (hdev->discov_timeout > 0) {
912 cancel_delayed_work(&hdev->discov_off);
913 hdev->discov_timeout = 0;
914 }
915
916 if (cp->val && timeout > 0) {
917 hdev->discov_timeout = timeout;
918 queue_delayed_work(hdev->workqueue, &hdev->discov_off,
919 msecs_to_jiffies(hdev->discov_timeout * 1000));
920 }
921
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200922 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200923 goto failed;
924 }
925
926 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
927 if (!cmd) {
928 err = -ENOMEM;
929 goto failed;
930 }
931
932 scan = SCAN_PAGE;
933
934 if (cp->val)
935 scan |= SCAN_INQUIRY;
936 else
937 cancel_delayed_work(&hdev->discov_off);
938
939 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
940 if (err < 0)
941 mgmt_pending_remove(cmd);
942
Johan Hedberg03811012010-12-08 00:21:06 +0200943 if (cp->val)
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200944 hdev->discov_timeout = timeout;
Johan Hedberg03811012010-12-08 00:21:06 +0200945
946failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300947 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200948 hci_dev_put(hdev);
949
950 return err;
951}
952
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300953static int set_connectable(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200954{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300955 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200956 struct hci_dev *hdev;
957 struct pending_cmd *cmd;
958 u8 scan;
959 int err;
960
Johan Hedberge41d8b42010-12-13 21:07:03 +0200961 BT_DBG("request for hci%u", index);
962
Johan Hedberg03811012010-12-08 00:21:06 +0200963 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200964 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
965 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200966
967 hdev = hci_dev_get(index);
968 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200969 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
970 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200971
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300972 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200973
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200974 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200975 bool changed = false;
976
977 if (!!cp->val != test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
978 changed = true;
979
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +0200980 if (cp->val) {
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200981 set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +0200982 } else {
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200983 clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
984 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
985 }
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200986
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200987 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200988 if (err < 0)
989 goto failed;
990
991 if (changed)
992 err = new_settings(hdev, sk);
993
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200994 goto failed;
995 }
996
997 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
998 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200999 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
1000 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001001 goto failed;
1002 }
1003
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001004 if (!!cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001005 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001006 goto failed;
1007 }
1008
1009 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
1010 if (!cmd) {
1011 err = -ENOMEM;
1012 goto failed;
1013 }
1014
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001015 if (cp->val) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001016 scan = SCAN_PAGE;
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001017 } else {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001018 scan = 0;
1019
Johan Hedbergdf2c6c52012-02-21 19:15:49 +02001020 if (test_bit(HCI_ISCAN, &hdev->flags) &&
1021 hdev->discov_timeout > 0)
1022 cancel_delayed_work(&hdev->discov_off);
1023 }
1024
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001025 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1026 if (err < 0)
1027 mgmt_pending_remove(cmd);
1028
1029failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001030 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001031 hci_dev_put(hdev);
1032
1033 return err;
1034}
1035
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001036static int set_pairable(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001037{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001038 struct mgmt_mode *cp = data;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001039 struct hci_dev *hdev;
1040 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001041
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001042 BT_DBG("request for hci%u", index);
1043
1044 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001045 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE,
1046 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001047
1048 hdev = hci_dev_get(index);
1049 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001050 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE,
1051 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001052
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001053 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001054
1055 if (cp->val)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001056 set_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001057 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001058 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001059
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001060 err = send_settings_rsp(sk, MGMT_OP_SET_PAIRABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001061 if (err < 0)
1062 goto failed;
1063
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001064 err = new_settings(hdev, sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001065
1066failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001067 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001068 hci_dev_put(hdev);
1069
1070 return err;
1071}
Johan Hedberg72a734e2010-12-30 00:38:22 +02001072
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001073static int set_link_security(struct sock *sk, u16 index, void *data, u16 len)
1074{
1075 struct mgmt_mode *cp = data;
1076 struct pending_cmd *cmd;
1077 struct hci_dev *hdev;
1078 uint8_t val;
1079 int err;
1080
1081 BT_DBG("request for hci%u", index);
1082
1083 if (len != sizeof(*cp))
1084 return cmd_status(sk, index, MGMT_OP_SET_LINK_SECURITY,
1085 MGMT_STATUS_INVALID_PARAMS);
1086
1087 hdev = hci_dev_get(index);
1088 if (!hdev)
1089 return cmd_status(sk, index, MGMT_OP_SET_LINK_SECURITY,
1090 MGMT_STATUS_INVALID_PARAMS);
1091
1092 hci_dev_lock(hdev);
1093
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001094 if (!hdev_is_powered(hdev)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001095 bool changed = false;
1096
1097 if (!!cp->val != test_bit(HCI_LINK_SECURITY,
1098 &hdev->dev_flags)) {
1099 change_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
1100 changed = true;
1101 }
1102
1103 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1104 if (err < 0)
1105 goto failed;
1106
1107 if (changed)
1108 err = new_settings(hdev, sk);
1109
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001110 goto failed;
1111 }
1112
1113 if (mgmt_pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
1114 err = cmd_status(sk, index, MGMT_OP_SET_LINK_SECURITY,
1115 MGMT_STATUS_BUSY);
1116 goto failed;
1117 }
1118
1119 val = !!cp->val;
1120
1121 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1122 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1123 goto failed;
1124 }
1125
1126 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1127 if (!cmd) {
1128 err = -ENOMEM;
1129 goto failed;
1130 }
1131
1132 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1133 if (err < 0) {
1134 mgmt_pending_remove(cmd);
1135 goto failed;
1136 }
1137
1138failed:
1139 hci_dev_unlock(hdev);
1140 hci_dev_put(hdev);
1141
1142 return err;
1143}
1144
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001145static int set_ssp(struct sock *sk, u16 index, void *data, u16 len)
1146{
1147 struct mgmt_mode *cp = data;
1148 struct pending_cmd *cmd;
1149 struct hci_dev *hdev;
1150 uint8_t val;
1151 int err;
1152
1153 BT_DBG("request for hci%u", index);
1154
1155 if (len != sizeof(*cp))
1156 return cmd_status(sk, index, MGMT_OP_SET_SSP,
1157 MGMT_STATUS_INVALID_PARAMS);
1158
1159 hdev = hci_dev_get(index);
1160 if (!hdev)
1161 return cmd_status(sk, index, MGMT_OP_SET_SSP,
1162 MGMT_STATUS_INVALID_PARAMS);
1163
1164 hci_dev_lock(hdev);
1165
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001166 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
1167 err = cmd_status(sk, index, MGMT_OP_SET_SSP,
1168 MGMT_STATUS_NOT_SUPPORTED);
1169 goto failed;
1170 }
1171
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001172 val = !!cp->val;
1173
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001174 if (!hdev_is_powered(hdev)) {
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001175 bool changed = false;
1176
1177 if (val != test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) {
1178 change_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
1179 changed = true;
1180 }
1181
1182 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1183 if (err < 0)
1184 goto failed;
1185
1186 if (changed)
1187 err = new_settings(hdev, sk);
1188
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001189 goto failed;
1190 }
1191
1192 if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev)) {
1193 err = cmd_status(sk, index, MGMT_OP_SET_SSP, MGMT_STATUS_BUSY);
1194 goto failed;
1195 }
1196
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001197 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) == val) {
1198 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1199 goto failed;
1200 }
1201
1202 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1203 if (!cmd) {
1204 err = -ENOMEM;
1205 goto failed;
1206 }
1207
1208 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, sizeof(val), &val);
1209 if (err < 0) {
1210 mgmt_pending_remove(cmd);
1211 goto failed;
1212 }
1213
1214failed:
1215 hci_dev_unlock(hdev);
1216 hci_dev_put(hdev);
1217
1218 return err;
1219}
1220
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001221static int set_hs(struct sock *sk, u16 index, void *data, u16 len)
1222{
1223 struct mgmt_mode *cp = data;
1224 struct hci_dev *hdev;
1225 int err;
1226
1227 BT_DBG("request for hci%u", index);
1228
1229 if (len != sizeof(*cp))
1230 return cmd_status(sk, index, MGMT_OP_SET_HS,
1231 MGMT_STATUS_INVALID_PARAMS);
1232
1233 hdev = hci_dev_get(index);
1234 if (!hdev)
1235 return cmd_status(sk, index, MGMT_OP_SET_HS,
1236 MGMT_STATUS_INVALID_PARAMS);
1237
1238 if (!enable_hs) {
1239 err = cmd_status(sk, index, MGMT_OP_SET_HS,
1240 MGMT_STATUS_NOT_SUPPORTED);
1241 goto failed;
1242 }
1243
1244 if (cp->val)
1245 set_bit(HCI_HS_ENABLED, &hdev->dev_flags);
1246 else
1247 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
1248
1249 err = send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
1250
1251failed:
1252 hci_dev_put(hdev);
1253 return err;
1254}
1255
Johan Hedberg06199cf2012-02-22 16:37:11 +02001256static int set_le(struct sock *sk, u16 index, void *data, u16 len)
1257{
1258 struct mgmt_mode *cp = data;
1259 struct hci_cp_write_le_host_supported hci_cp;
1260 struct pending_cmd *cmd;
1261 struct hci_dev *hdev;
1262 int err;
1263 u8 val;
1264
1265 BT_DBG("request for hci%u", index);
1266
1267 if (len != sizeof(*cp))
1268 return cmd_status(sk, index, MGMT_OP_SET_LE,
1269 MGMT_STATUS_INVALID_PARAMS);
1270
1271 hdev = hci_dev_get(index);
1272 if (!hdev)
1273 return cmd_status(sk, index, MGMT_OP_SET_LE,
1274 MGMT_STATUS_INVALID_PARAMS);
1275
1276 if (!enable_le || !(hdev->features[4] & LMP_LE)) {
1277 err = cmd_status(sk, index, MGMT_OP_SET_LE,
1278 MGMT_STATUS_NOT_SUPPORTED);
1279 goto failed;
1280 }
1281
1282 val = !!cp->val;
1283
1284 if (!hdev_is_powered(hdev)) {
1285 bool changed = false;
1286
1287 if (val != test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
1288 change_bit(HCI_LE_ENABLED, &hdev->dev_flags);
1289 changed = true;
1290 }
1291
1292 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1293 if (err < 0)
1294 goto failed;
1295
1296 if (changed)
1297 err = new_settings(hdev, sk);
1298
1299 goto failed;
1300 }
1301
1302 if (mgmt_pending_find(MGMT_OP_SET_LE, hdev)) {
1303 err = cmd_status(sk, index, MGMT_OP_SET_LE, MGMT_STATUS_BUSY);
1304 goto failed;
1305 }
1306
1307 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
1308 if (!cmd) {
1309 err = -ENOMEM;
1310 goto failed;
1311 }
1312
1313 memset(&hci_cp, 0, sizeof(hci_cp));
1314
1315 if (val) {
1316 hci_cp.le = val;
1317 hci_cp.simul = !!(hdev->features[6] & LMP_SIMUL_LE_BR);
1318 }
1319
1320 err = hci_send_cmd(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED,
1321 sizeof(hci_cp), &hci_cp);
1322 if (err < 0) {
1323 mgmt_pending_remove(cmd);
1324 goto failed;
1325 }
1326
1327failed:
1328 hci_dev_put(hdev);
1329 return err;
1330}
1331
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001332static int add_uuid(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001333{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001334 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001335 struct hci_dev *hdev;
1336 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001337 int err;
1338
Szymon Janc4e51eae2011-02-25 19:05:48 +01001339 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001340
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001341 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001342 return cmd_status(sk, index, MGMT_OP_ADD_UUID,
1343 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001344
Szymon Janc4e51eae2011-02-25 19:05:48 +01001345 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001346 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001347 return cmd_status(sk, index, MGMT_OP_ADD_UUID,
1348 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001349
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001350 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001351
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001352 if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
1353 err = cmd_status(sk, index, MGMT_OP_ADD_UUID,
1354 MGMT_STATUS_BUSY);
1355 goto failed;
1356 }
1357
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001358 uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC);
1359 if (!uuid) {
1360 err = -ENOMEM;
1361 goto failed;
1362 }
1363
1364 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001365 uuid->svc_hint = cp->svc_hint;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001366
1367 list_add(&uuid->list, &hdev->uuids);
1368
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001369 err = update_class(hdev);
1370 if (err < 0)
1371 goto failed;
1372
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001373 err = update_eir(hdev);
1374 if (err < 0)
1375 goto failed;
1376
Johan Hedberg9997a532012-02-23 15:57:46 +02001377 err = cmd_complete(sk, index, MGMT_OP_ADD_UUID, 0, hdev->dev_class, 3);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001378
1379failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001380 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001381 hci_dev_put(hdev);
1382
1383 return err;
1384}
1385
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001386static int remove_uuid(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001387{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001388 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001389 struct list_head *p, *n;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001390 struct hci_dev *hdev;
1391 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 +02001392 int err, found;
1393
Szymon Janc4e51eae2011-02-25 19:05:48 +01001394 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001395
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001396 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001397 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
1398 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001399
Szymon Janc4e51eae2011-02-25 19:05:48 +01001400 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001401 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001402 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
1403 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001404
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001405 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001406
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001407 if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
1408 err = cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
1409 MGMT_STATUS_BUSY);
1410 goto unlock;
1411 }
1412
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001413 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
1414 err = hci_uuids_clear(hdev);
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001415
1416 if (hdev_is_powered(hdev) &&
1417 !test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
1418 schedule_delayed_work(&hdev->service_cache,
1419 msecs_to_jiffies(SERVICE_CACHE_TIMEOUT));
1420
Johan Hedberg9246a862012-02-23 21:33:16 +02001421 goto update_class;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001422 }
1423
1424 found = 0;
1425
1426 list_for_each_safe(p, n, &hdev->uuids) {
1427 struct bt_uuid *match = list_entry(p, struct bt_uuid, list);
1428
1429 if (memcmp(match->uuid, cp->uuid, 16) != 0)
1430 continue;
1431
1432 list_del(&match->list);
1433 found++;
1434 }
1435
1436 if (found == 0) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001437 err = cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
1438 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001439 goto unlock;
1440 }
1441
Johan Hedberg9246a862012-02-23 21:33:16 +02001442update_class:
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001443 err = update_class(hdev);
1444 if (err < 0)
1445 goto unlock;
1446
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001447 err = update_eir(hdev);
1448 if (err < 0)
1449 goto unlock;
1450
Johan Hedberg9997a532012-02-23 15:57:46 +02001451 err = cmd_complete(sk, index, MGMT_OP_REMOVE_UUID, 0,
1452 hdev->dev_class, 3);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001453
1454unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001455 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001456 hci_dev_put(hdev);
1457
1458 return err;
1459}
1460
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001461static int set_dev_class(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001462{
1463 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001464 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001465 int err;
1466
Szymon Janc4e51eae2011-02-25 19:05:48 +01001467 BT_DBG("request for hci%u", index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001468
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001469 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001470 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS,
1471 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001472
Szymon Janc4e51eae2011-02-25 19:05:48 +01001473 hdev = hci_dev_get(index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001474 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001475 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS,
1476 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001477
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001478 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001479
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001480 if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
1481 err = cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS,
1482 MGMT_STATUS_BUSY);
1483 goto unlock;
1484 }
1485
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001486 hdev->major_class = cp->major;
1487 hdev->minor_class = cp->minor;
1488
Johan Hedberg932f5ff2012-02-22 22:11:32 +02001489 if (!hdev_is_powered(hdev)) {
1490 err = cmd_complete(sk, index, MGMT_OP_SET_DEV_CLASS, 0,
1491 hdev->dev_class, 3);
1492 goto unlock;
1493 }
1494
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001495 if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02001496 hci_dev_unlock(hdev);
1497 cancel_delayed_work_sync(&hdev->service_cache);
1498 hci_dev_lock(hdev);
Johan Hedberg14c0b602011-12-15 00:47:37 +02001499 update_eir(hdev);
Johan Hedberg7d785252011-12-15 00:47:39 +02001500 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02001501
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001502 err = update_class(hdev);
1503
1504 if (err == 0)
Johan Hedbergaee9b212012-02-18 15:07:59 +02001505 err = cmd_complete(sk, index, MGMT_OP_SET_DEV_CLASS, 0,
Johan Hedberg8ec37032012-02-22 22:02:50 +02001506 hdev->dev_class, 3);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001507
Johan Hedbergb5235a62012-02-21 14:32:24 +02001508unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001509 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001510 hci_dev_put(hdev);
1511
1512 return err;
1513}
1514
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001515static int load_link_keys(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001516{
1517 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001518 struct mgmt_cp_load_link_keys *cp = data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001519 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001520 int i;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001521
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001522 if (len < sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001523 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1524 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001525
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001526 key_count = get_unaligned_le16(&cp->key_count);
1527
Johan Hedberg86742e12011-11-07 23:13:38 +02001528 expected_len = sizeof(*cp) + key_count *
1529 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001530 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001531 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001532 len, expected_len);
Johan Hedbergca69b792011-11-11 18:10:00 +02001533 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1534 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001535 }
1536
Szymon Janc4e51eae2011-02-25 19:05:48 +01001537 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001538 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001539 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1540 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001541
Szymon Janc4e51eae2011-02-25 19:05:48 +01001542 BT_DBG("hci%u debug_keys %u key_count %u", index, cp->debug_keys,
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001543 key_count);
1544
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001545 hci_dev_lock(hdev);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001546
1547 hci_link_keys_clear(hdev);
1548
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001549 set_bit(HCI_LINK_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001550
1551 if (cp->debug_keys)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001552 set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001553 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001554 clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001555
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001556 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001557 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001558
Johan Hedbergd753fdc2012-02-17 14:06:34 +02001559 hci_add_link_key(hdev, NULL, 0, &key->addr.bdaddr, key->val,
1560 key->type, key->pin_len);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001561 }
1562
Johan Hedbergaee9b212012-02-18 15:07:59 +02001563 cmd_complete(sk, index, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02001564
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001565 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001566 hci_dev_put(hdev);
1567
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001568 return 0;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001569}
1570
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001571static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
1572 u8 addr_type, struct sock *skip_sk)
1573{
1574 struct mgmt_ev_device_unpaired ev;
1575
1576 bacpy(&ev.addr.bdaddr, bdaddr);
1577 ev.addr.type = addr_type;
1578
1579 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
1580 skip_sk);
1581}
1582
Johan Hedberg124f6e32012-02-09 13:50:12 +02001583static int unpair_device(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001584{
1585 struct hci_dev *hdev;
Johan Hedberg124f6e32012-02-09 13:50:12 +02001586 struct mgmt_cp_unpair_device *cp = data;
1587 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001588 struct hci_cp_disconnect dc;
1589 struct pending_cmd *cmd;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001590 struct hci_conn *conn;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001591 int err;
1592
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001593 if (len != sizeof(*cp))
Johan Hedberg124f6e32012-02-09 13:50:12 +02001594 return cmd_status(sk, index, MGMT_OP_UNPAIR_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02001595 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001596
Szymon Janc4e51eae2011-02-25 19:05:48 +01001597 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001598 if (!hdev)
Johan Hedberg124f6e32012-02-09 13:50:12 +02001599 return cmd_status(sk, index, MGMT_OP_UNPAIR_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02001600 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001601
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001602 hci_dev_lock(hdev);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001603
Johan Hedberga8a1d192011-11-10 15:54:38 +02001604 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02001605 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1606 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001607
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001608 if (!hdev_is_powered(hdev)) {
1609 err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE,
1610 MGMT_STATUS_NOT_POWERED,
1611 &rp, sizeof(rp));
1612 goto unlock;
1613 }
1614
Johan Hedberg124f6e32012-02-09 13:50:12 +02001615 if (cp->addr.type == MGMT_ADDR_BREDR)
1616 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
1617 else
1618 err = hci_remove_ltk(hdev, &cp->addr.bdaddr);
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03001619
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001620 if (err < 0) {
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001621 err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE,
1622 MGMT_STATUS_NOT_PAIRED,
1623 &rp, sizeof(rp));
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001624 goto unlock;
1625 }
1626
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001627 if (cp->disconnect) {
1628 if (cp->addr.type == MGMT_ADDR_BREDR)
1629 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
1630 &cp->addr.bdaddr);
1631 else
1632 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
1633 &cp->addr.bdaddr);
1634 } else {
1635 conn = NULL;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001636 }
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001637
Johan Hedberga8a1d192011-11-10 15:54:38 +02001638 if (!conn) {
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001639 err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE, 0,
Johan Hedbergaee9b212012-02-18 15:07:59 +02001640 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001641 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001642 goto unlock;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001643 }
1644
Johan Hedberg124f6e32012-02-09 13:50:12 +02001645 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
1646 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02001647 if (!cmd) {
1648 err = -ENOMEM;
1649 goto unlock;
1650 }
1651
1652 put_unaligned_le16(conn->handle, &dc.handle);
1653 dc.reason = 0x13; /* Remote User Terminated Connection */
1654 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1655 if (err < 0)
1656 mgmt_pending_remove(cmd);
1657
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001658unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001659 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001660 hci_dev_put(hdev);
1661
1662 return err;
1663}
1664
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001665static int disconnect(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02001666{
1667 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001668 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001669 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03001670 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001671 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001672 int err;
1673
1674 BT_DBG("");
1675
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001676 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001677 return cmd_status(sk, index, MGMT_OP_DISCONNECT,
1678 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001679
Szymon Janc4e51eae2011-02-25 19:05:48 +01001680 hdev = hci_dev_get(index);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001681 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001682 return cmd_status(sk, index, MGMT_OP_DISCONNECT,
1683 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001684
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001685 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001686
1687 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001688 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1689 MGMT_STATUS_NOT_POWERED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001690 goto failed;
1691 }
1692
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001693 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001694 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1695 MGMT_STATUS_BUSY);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001696 goto failed;
1697 }
1698
Johan Hedberg88c3df12012-02-09 14:27:38 +02001699 if (cp->addr.type == MGMT_ADDR_BREDR)
1700 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
1701 else
1702 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03001703
Johan Hedberg8962ee72011-01-20 12:40:27 +02001704 if (!conn) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001705 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1706 MGMT_STATUS_NOT_CONNECTED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001707 goto failed;
1708 }
1709
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001710 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001711 if (!cmd) {
1712 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001713 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001714 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001715
1716 put_unaligned_le16(conn->handle, &dc.handle);
1717 dc.reason = 0x13; /* Remote User Terminated Connection */
1718
1719 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1720 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001721 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001722
1723failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001724 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001725 hci_dev_put(hdev);
1726
1727 return err;
1728}
1729
Johan Hedberg48264f02011-11-09 13:58:58 +02001730static u8 link_to_mgmt(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02001731{
1732 switch (link_type) {
1733 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02001734 switch (addr_type) {
1735 case ADDR_LE_DEV_PUBLIC:
1736 return MGMT_ADDR_LE_PUBLIC;
1737 case ADDR_LE_DEV_RANDOM:
1738 return MGMT_ADDR_LE_RANDOM;
1739 default:
1740 return MGMT_ADDR_INVALID;
1741 }
Johan Hedberg4c659c32011-11-07 23:13:39 +02001742 case ACL_LINK:
1743 return MGMT_ADDR_BREDR;
1744 default:
1745 return MGMT_ADDR_INVALID;
1746 }
1747}
1748
Szymon Janc8ce62842011-03-01 16:55:32 +01001749static int get_connections(struct sock *sk, u16 index)
Johan Hedberg2784eb42011-01-21 13:56:35 +02001750{
Johan Hedberg2784eb42011-01-21 13:56:35 +02001751 struct mgmt_rp_get_connections *rp;
1752 struct hci_dev *hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001753 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02001754 size_t rp_len;
Johan Hedberg60fc5fb2012-02-23 09:52:28 +02001755 int err;
1756 u16 i;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001757
1758 BT_DBG("");
1759
Szymon Janc4e51eae2011-02-25 19:05:48 +01001760 hdev = hci_dev_get(index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001761 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001762 return cmd_status(sk, index, MGMT_OP_GET_CONNECTIONS,
1763 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001764
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001765 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001766
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001767 if (!hdev_is_powered(hdev)) {
1768 err = cmd_status(sk, index, MGMT_OP_GET_CONNECTIONS,
1769 MGMT_STATUS_NOT_POWERED);
1770 goto unlock;
1771 }
1772
Johan Hedberg60fc5fb2012-02-23 09:52:28 +02001773 i = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02001774 list_for_each_entry(c, &hdev->conn_hash.list, list) {
1775 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
Johan Hedberg60fc5fb2012-02-23 09:52:28 +02001776 i++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001777 }
1778
Johan Hedberg60fc5fb2012-02-23 09:52:28 +02001779 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberga38528f2011-01-22 06:46:43 +02001780 rp = kmalloc(rp_len, GFP_ATOMIC);
1781 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02001782 err = -ENOMEM;
1783 goto unlock;
1784 }
1785
Johan Hedberg2784eb42011-01-21 13:56:35 +02001786 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001787 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02001788 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
1789 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001790 bacpy(&rp->addr[i].bdaddr, &c->dst);
Johan Hedberg48264f02011-11-09 13:58:58 +02001791 rp->addr[i].type = link_to_mgmt(c->type, c->dst_type);
Johan Hedberg4c659c32011-11-07 23:13:39 +02001792 if (rp->addr[i].type == MGMT_ADDR_INVALID)
1793 continue;
1794 i++;
1795 }
1796
Johan Hedberg60fc5fb2012-02-23 09:52:28 +02001797 put_unaligned_le16(i, &rp->conn_count);
1798
Johan Hedberg4c659c32011-11-07 23:13:39 +02001799 /* Recalculate length in case of filtered SCO connections, etc */
1800 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02001801
Johan Hedbergaee9b212012-02-18 15:07:59 +02001802 err = cmd_complete(sk, index, MGMT_OP_GET_CONNECTIONS, 0, rp, rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001803
Johan Hedberga38528f2011-01-22 06:46:43 +02001804 kfree(rp);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001805
1806unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001807 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001808 hci_dev_put(hdev);
1809 return err;
1810}
1811
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001812static int send_pin_code_neg_reply(struct sock *sk, u16 index,
1813 struct hci_dev *hdev, struct mgmt_cp_pin_code_neg_reply *cp)
1814{
1815 struct pending_cmd *cmd;
1816 int err;
1817
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001818 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001819 sizeof(*cp));
1820 if (!cmd)
1821 return -ENOMEM;
1822
Johan Hedbergd8457692012-02-17 14:24:57 +02001823 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
1824 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001825 if (err < 0)
1826 mgmt_pending_remove(cmd);
1827
1828 return err;
1829}
1830
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001831static int pin_code_reply(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001832{
1833 struct hci_dev *hdev;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001834 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001835 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001836 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03001837 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001838 int err;
1839
1840 BT_DBG("");
1841
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001842 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001843 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1844 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001845
Szymon Janc4e51eae2011-02-25 19:05:48 +01001846 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001847 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001848 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1849 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001850
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001851 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001852
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001853 if (!hdev_is_powered(hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001854 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1855 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001856 goto failed;
1857 }
1858
Johan Hedbergd8457692012-02-17 14:24:57 +02001859 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001860 if (!conn) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001861 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1862 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001863 goto failed;
1864 }
1865
1866 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02001867 struct mgmt_cp_pin_code_neg_reply ncp;
1868
1869 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001870
1871 BT_ERR("PIN code is not 16 bytes long");
1872
1873 err = send_pin_code_neg_reply(sk, index, hdev, &ncp);
1874 if (err >= 0)
1875 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001876 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001877
1878 goto failed;
1879 }
1880
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001881 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data,
1882 len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001883 if (!cmd) {
1884 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001885 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001886 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02001887
Johan Hedbergd8457692012-02-17 14:24:57 +02001888 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001889 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02001890 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02001891
1892 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
1893 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001894 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001895
1896failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001897 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001898 hci_dev_put(hdev);
1899
1900 return err;
1901}
1902
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001903static int pin_code_neg_reply(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001904{
1905 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001906 struct mgmt_cp_pin_code_neg_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001907 int err;
1908
1909 BT_DBG("");
1910
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001911 if (len != sizeof(*cp))
1912 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001913 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001914
Szymon Janc4e51eae2011-02-25 19:05:48 +01001915 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001916 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001917 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001918 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001919
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001920 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001921
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001922 if (!hdev_is_powered(hdev)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001923 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001924 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001925 goto failed;
1926 }
1927
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001928 err = send_pin_code_neg_reply(sk, index, hdev, cp);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001929
1930failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001931 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001932 hci_dev_put(hdev);
1933
1934 return err;
1935}
1936
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001937static int set_io_capability(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001938{
1939 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001940 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001941
1942 BT_DBG("");
1943
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001944 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001945 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY,
1946 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001947
Szymon Janc4e51eae2011-02-25 19:05:48 +01001948 hdev = hci_dev_get(index);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001949 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001950 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY,
1951 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001952
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001953 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001954
1955 hdev->io_capability = cp->io_capability;
1956
1957 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Szymon Jancb8534e02011-03-01 16:55:34 +01001958 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001959
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001960 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001961 hci_dev_put(hdev);
1962
Johan Hedbergaee9b212012-02-18 15:07:59 +02001963 return cmd_complete(sk, index, MGMT_OP_SET_IO_CAPABILITY, 0, NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001964}
1965
Johan Hedberge9a416b2011-02-19 12:05:56 -03001966static inline struct pending_cmd *find_pairing(struct hci_conn *conn)
1967{
1968 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001969 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001970
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001971 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03001972 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
1973 continue;
1974
Johan Hedberge9a416b2011-02-19 12:05:56 -03001975 if (cmd->user_data != conn)
1976 continue;
1977
1978 return cmd;
1979 }
1980
1981 return NULL;
1982}
1983
1984static void pairing_complete(struct pending_cmd *cmd, u8 status)
1985{
1986 struct mgmt_rp_pair_device rp;
1987 struct hci_conn *conn = cmd->user_data;
1988
Johan Hedbergba4e5642011-11-11 00:07:34 +02001989 bacpy(&rp.addr.bdaddr, &conn->dst);
1990 rp.addr.type = link_to_mgmt(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001991
Johan Hedbergaee9b212012-02-18 15:07:59 +02001992 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, status,
1993 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001994
1995 /* So we don't get further callbacks for this connection */
1996 conn->connect_cfm_cb = NULL;
1997 conn->security_cfm_cb = NULL;
1998 conn->disconn_cfm_cb = NULL;
1999
2000 hci_conn_put(conn);
2001
Johan Hedberga664b5b2011-02-19 12:06:02 -03002002 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002003}
2004
2005static void pairing_complete_cb(struct hci_conn *conn, u8 status)
2006{
2007 struct pending_cmd *cmd;
2008
2009 BT_DBG("status %u", status);
2010
Johan Hedberg56e5cb82011-11-08 20:40:16 +02002011 cmd = find_pairing(conn);
2012 if (!cmd)
2013 BT_DBG("Unable to find a pending command");
2014 else
Johan Hedberge2113262012-02-18 15:20:03 +02002015 pairing_complete(cmd, mgmt_status(status));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002016}
2017
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002018static int pair_device(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002019{
2020 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002021 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02002022 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002023 struct pending_cmd *cmd;
2024 u8 sec_level, auth_type;
2025 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002026 int err;
2027
2028 BT_DBG("");
2029
Szymon Jancbdce7ba2011-02-25 19:05:49 +01002030 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02002031 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE,
2032 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01002033
Szymon Janc4e51eae2011-02-25 19:05:48 +01002034 hdev = hci_dev_get(index);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002035 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002036 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE,
2037 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002038
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002039 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002040
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002041 if (!hdev_is_powered(hdev)) {
2042 err = cmd_status(sk, index, MGMT_OP_PAIR_DEVICE,
2043 MGMT_STATUS_NOT_POWERED);
2044 goto unlock;
2045 }
2046
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002047 sec_level = BT_SECURITY_MEDIUM;
2048 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002049 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002050 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03002051 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002052
Johan Hedbergba4e5642011-11-11 00:07:34 +02002053 if (cp->addr.type == MGMT_ADDR_BREDR)
2054 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr, sec_level,
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002055 auth_type);
2056 else
Johan Hedbergba4e5642011-11-11 00:07:34 +02002057 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr, sec_level,
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002058 auth_type);
2059
Johan Hedberg1425acb2011-11-11 00:07:35 +02002060 memset(&rp, 0, sizeof(rp));
2061 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2062 rp.addr.type = cp->addr.type;
2063
Ville Tervo30e76272011-02-22 16:10:53 -03002064 if (IS_ERR(conn)) {
Johan Hedberge2113262012-02-18 15:20:03 +02002065 err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE,
2066 MGMT_STATUS_CONNECT_FAILED,
2067 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002068 goto unlock;
2069 }
2070
2071 if (conn->connect_cfm_cb) {
2072 hci_conn_put(conn);
Johan Hedberge2113262012-02-18 15:20:03 +02002073 err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE,
2074 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002075 goto unlock;
2076 }
2077
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002078 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002079 if (!cmd) {
2080 err = -ENOMEM;
2081 hci_conn_put(conn);
2082 goto unlock;
2083 }
2084
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002085 /* For LE, just connecting isn't a proof that the pairing finished */
Johan Hedbergba4e5642011-11-11 00:07:34 +02002086 if (cp->addr.type == MGMT_ADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002087 conn->connect_cfm_cb = pairing_complete_cb;
2088
Johan Hedberge9a416b2011-02-19 12:05:56 -03002089 conn->security_cfm_cb = pairing_complete_cb;
2090 conn->disconn_cfm_cb = pairing_complete_cb;
2091 conn->io_capability = cp->io_cap;
2092 cmd->user_data = conn;
2093
2094 if (conn->state == BT_CONNECTED &&
2095 hci_conn_security(conn, sec_level, auth_type))
2096 pairing_complete(cmd, 0);
2097
2098 err = 0;
2099
2100unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002101 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002102 hci_dev_put(hdev);
2103
2104 return err;
2105}
2106
Johan Hedberg28424702012-02-02 04:02:29 +02002107static int cancel_pair_device(struct sock *sk, u16 index,
2108 unsigned char *data, u16 len)
2109{
2110 struct mgmt_addr_info *addr = (void *) data;
2111 struct hci_dev *hdev;
2112 struct pending_cmd *cmd;
2113 struct hci_conn *conn;
2114 int err;
2115
2116 BT_DBG("");
2117
2118 if (len != sizeof(*addr))
2119 return cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
2120 MGMT_STATUS_INVALID_PARAMS);
2121
2122 hdev = hci_dev_get(index);
2123 if (!hdev)
2124 return cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
2125 MGMT_STATUS_INVALID_PARAMS);
2126
2127 hci_dev_lock(hdev);
2128
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002129 if (!hdev_is_powered(hdev)) {
2130 err = cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
2131 MGMT_STATUS_NOT_POWERED);
2132 goto unlock;
2133 }
2134
Johan Hedberg28424702012-02-02 04:02:29 +02002135 cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
2136 if (!cmd) {
2137 err = cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
2138 MGMT_STATUS_INVALID_PARAMS);
2139 goto unlock;
2140 }
2141
2142 conn = cmd->user_data;
2143
2144 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
2145 err = cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
2146 MGMT_STATUS_INVALID_PARAMS);
2147 goto unlock;
2148 }
2149
2150 pairing_complete(cmd, MGMT_STATUS_CANCELLED);
2151
Johan Hedbergaee9b212012-02-18 15:07:59 +02002152 err = cmd_complete(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE, 0, addr,
Johan Hedberg28424702012-02-02 04:02:29 +02002153 sizeof(*addr));
2154unlock:
2155 hci_dev_unlock(hdev);
2156 hci_dev_put(hdev);
2157
2158 return err;
2159}
2160
Brian Gix0df4c182011-11-16 13:53:13 -08002161static int user_pairing_resp(struct sock *sk, u16 index, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02002162 u8 type, u16 mgmt_op, u16 hci_op,
2163 __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03002164{
Johan Hedberga5c29682011-02-19 12:05:57 -03002165 struct pending_cmd *cmd;
2166 struct hci_dev *hdev;
Brian Gix0df4c182011-11-16 13:53:13 -08002167 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03002168 int err;
2169
Szymon Janc4e51eae2011-02-25 19:05:48 +01002170 hdev = hci_dev_get(index);
Johan Hedberga5c29682011-02-19 12:05:57 -03002171 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002172 return cmd_status(sk, index, mgmt_op,
2173 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga5c29682011-02-19 12:05:57 -03002174
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002175 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02002176
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002177 if (!hdev_is_powered(hdev)) {
Brian Gix0df4c182011-11-16 13:53:13 -08002178 err = cmd_status(sk, index, mgmt_op, MGMT_STATUS_NOT_POWERED);
2179 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002180 }
2181
Johan Hedberg272d90d2012-02-09 15:26:12 +02002182 if (type == MGMT_ADDR_BREDR)
2183 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, bdaddr);
2184 else
Brian Gix47c15e22011-11-16 13:53:14 -08002185 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, bdaddr);
Brian Gix47c15e22011-11-16 13:53:14 -08002186
Johan Hedberg272d90d2012-02-09 15:26:12 +02002187 if (!conn) {
2188 err = cmd_status(sk, index, mgmt_op,
2189 MGMT_STATUS_NOT_CONNECTED);
2190 goto done;
2191 }
2192
2193 if (type == MGMT_ADDR_LE_PUBLIC || type == MGMT_ADDR_LE_RANDOM) {
Brian Gix47c15e22011-11-16 13:53:14 -08002194 /* Continue with pairing via SMP */
Brian Gix5fe57d92011-12-21 16:12:13 -08002195 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix47c15e22011-11-16 13:53:14 -08002196
Brian Gix5fe57d92011-12-21 16:12:13 -08002197 if (!err)
2198 err = cmd_status(sk, index, mgmt_op,
2199 MGMT_STATUS_SUCCESS);
2200 else
2201 err = cmd_status(sk, index, mgmt_op,
2202 MGMT_STATUS_FAILED);
2203
Brian Gix47c15e22011-11-16 13:53:14 -08002204 goto done;
2205 }
2206
Brian Gix0df4c182011-11-16 13:53:13 -08002207 cmd = mgmt_pending_add(sk, mgmt_op, hdev, bdaddr, sizeof(*bdaddr));
Johan Hedberga5c29682011-02-19 12:05:57 -03002208 if (!cmd) {
2209 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08002210 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002211 }
2212
Brian Gix0df4c182011-11-16 13:53:13 -08002213 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08002214 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
2215 struct hci_cp_user_passkey_reply cp;
2216
2217 bacpy(&cp.bdaddr, bdaddr);
2218 cp.passkey = passkey;
2219 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
2220 } else
2221 err = hci_send_cmd(hdev, hci_op, sizeof(*bdaddr), bdaddr);
2222
Johan Hedberga664b5b2011-02-19 12:06:02 -03002223 if (err < 0)
2224 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002225
Brian Gix0df4c182011-11-16 13:53:13 -08002226done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002227 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002228 hci_dev_put(hdev);
2229
2230 return err;
2231}
2232
Brian Gix0df4c182011-11-16 13:53:13 -08002233static int user_confirm_reply(struct sock *sk, u16 index, void *data, u16 len)
2234{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002235 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002236
2237 BT_DBG("");
2238
2239 if (len != sizeof(*cp))
2240 return cmd_status(sk, index, MGMT_OP_USER_CONFIRM_REPLY,
2241 MGMT_STATUS_INVALID_PARAMS);
2242
Johan Hedberg272d90d2012-02-09 15:26:12 +02002243 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
2244 MGMT_OP_USER_CONFIRM_REPLY,
2245 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002246}
2247
2248static int user_confirm_neg_reply(struct sock *sk, u16 index, void *data,
2249 u16 len)
2250{
Johan Hedbergc9c26592011-12-15 00:47:41 +02002251 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002252
2253 BT_DBG("");
2254
2255 if (len != sizeof(*cp))
2256 return cmd_status(sk, index, MGMT_OP_USER_CONFIRM_NEG_REPLY,
2257 MGMT_STATUS_INVALID_PARAMS);
2258
Johan Hedberg272d90d2012-02-09 15:26:12 +02002259 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
2260 MGMT_OP_USER_CONFIRM_NEG_REPLY,
2261 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002262}
2263
Brian Gix604086b2011-11-23 08:28:33 -08002264static int user_passkey_reply(struct sock *sk, u16 index, void *data, u16 len)
2265{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002266 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002267
2268 BT_DBG("");
2269
2270 if (len != sizeof(*cp))
2271 return cmd_status(sk, index, MGMT_OP_USER_PASSKEY_REPLY,
2272 EINVAL);
2273
Johan Hedberg272d90d2012-02-09 15:26:12 +02002274 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
2275 MGMT_OP_USER_PASSKEY_REPLY,
2276 HCI_OP_USER_PASSKEY_REPLY,
2277 cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08002278}
2279
2280static int user_passkey_neg_reply(struct sock *sk, u16 index, void *data,
2281 u16 len)
2282{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002283 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002284
2285 BT_DBG("");
2286
2287 if (len != sizeof(*cp))
2288 return cmd_status(sk, index, MGMT_OP_USER_PASSKEY_NEG_REPLY,
2289 EINVAL);
2290
Johan Hedberg272d90d2012-02-09 15:26:12 +02002291 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
2292 MGMT_OP_USER_PASSKEY_NEG_REPLY,
2293 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08002294}
2295
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002296static int set_local_name(struct sock *sk, u16 index, void *data,
Johan Hedbergb312b1612011-03-16 14:29:37 +02002297 u16 len)
2298{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002299 struct mgmt_cp_set_local_name *mgmt_cp = data;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002300 struct hci_cp_write_local_name hci_cp;
2301 struct hci_dev *hdev;
2302 struct pending_cmd *cmd;
2303 int err;
2304
2305 BT_DBG("");
2306
2307 if (len != sizeof(*mgmt_cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02002308 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME,
2309 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002310
2311 hdev = hci_dev_get(index);
2312 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002313 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME,
2314 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002315
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002316 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002317
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002318 memcpy(hdev->short_name, mgmt_cp->short_name,
2319 sizeof(hdev->short_name));
2320
Johan Hedbergb5235a62012-02-21 14:32:24 +02002321 if (!hdev_is_powered(hdev)) {
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002322 memcpy(hdev->dev_name, mgmt_cp->name, sizeof(hdev->dev_name));
2323
2324 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
2325 data, len);
2326 if (err < 0)
2327 goto failed;
2328
2329 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data, len,
2330 sk);
2331
Johan Hedbergb5235a62012-02-21 14:32:24 +02002332 goto failed;
2333 }
2334
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002335 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002336 if (!cmd) {
2337 err = -ENOMEM;
2338 goto failed;
2339 }
2340
2341 memcpy(hci_cp.name, mgmt_cp->name, sizeof(hci_cp.name));
2342 err = hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(hci_cp),
2343 &hci_cp);
2344 if (err < 0)
2345 mgmt_pending_remove(cmd);
2346
2347failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002348 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002349 hci_dev_put(hdev);
2350
2351 return err;
2352}
2353
Szymon Jancc35938b2011-03-22 13:12:21 +01002354static int read_local_oob_data(struct sock *sk, u16 index)
2355{
2356 struct hci_dev *hdev;
2357 struct pending_cmd *cmd;
2358 int err;
2359
2360 BT_DBG("hci%u", index);
2361
2362 hdev = hci_dev_get(index);
2363 if (!hdev)
2364 return cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002365 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancc35938b2011-03-22 13:12:21 +01002366
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002367 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002368
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002369 if (!hdev_is_powered(hdev)) {
Szymon Jancc35938b2011-03-22 13:12:21 +01002370 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002371 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002372 goto unlock;
2373 }
2374
2375 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
2376 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002377 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002378 goto unlock;
2379 }
2380
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002381 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02002382 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2383 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01002384 goto unlock;
2385 }
2386
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002387 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01002388 if (!cmd) {
2389 err = -ENOMEM;
2390 goto unlock;
2391 }
2392
2393 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
2394 if (err < 0)
2395 mgmt_pending_remove(cmd);
2396
2397unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002398 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002399 hci_dev_put(hdev);
2400
2401 return err;
2402}
2403
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002404static int add_remote_oob_data(struct sock *sk, u16 index, void *data,
2405 u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002406{
2407 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002408 struct mgmt_cp_add_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002409 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002410 int err;
2411
2412 BT_DBG("hci%u ", index);
2413
2414 if (len != sizeof(*cp))
2415 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002416 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01002417
2418 hdev = hci_dev_get(index);
2419 if (!hdev)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002420 return cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
2421 MGMT_STATUS_INVALID_PARAMS,
2422 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002423
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002424 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002425
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002426 if (!hdev_is_powered(hdev)) {
2427 err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
2428 MGMT_STATUS_NOT_POWERED,
2429 &cp->addr, sizeof(cp->addr));
2430 goto unlock;
2431 }
2432
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002433 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, cp->hash,
Szymon Janc2763eda2011-03-22 13:12:22 +01002434 cp->randomizer);
2435 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002436 status = MGMT_STATUS_FAILED;
Szymon Janc2763eda2011-03-22 13:12:22 +01002437 else
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002438 status = 0;
2439
2440 err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, status,
2441 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002442
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002443unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002444 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002445 hci_dev_put(hdev);
2446
2447 return err;
2448}
2449
2450static int remove_remote_oob_data(struct sock *sk, u16 index,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002451 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002452{
2453 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002454 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002455 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002456 int err;
2457
2458 BT_DBG("hci%u ", index);
2459
2460 if (len != sizeof(*cp))
2461 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002462 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01002463
2464 hdev = hci_dev_get(index);
2465 if (!hdev)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002466 return cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2467 MGMT_STATUS_INVALID_PARAMS,
2468 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002469
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002470 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002471
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002472 if (!hdev_is_powered(hdev)) {
2473 err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2474 MGMT_STATUS_NOT_POWERED,
2475 &cp->addr, sizeof(cp->addr));
2476 goto unlock;
2477 }
2478
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002479 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr);
Szymon Janc2763eda2011-03-22 13:12:22 +01002480 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002481 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01002482 else
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002483 status = 0;
2484
2485 err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA, status,
2486 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002487
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002488unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002489 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002490 hci_dev_put(hdev);
2491
2492 return err;
2493}
2494
Andre Guedes5e0452c2012-02-17 20:39:38 -03002495static int discovery(struct hci_dev *hdev)
2496{
2497 int err;
2498
2499 if (lmp_host_le_capable(hdev)) {
2500 if (lmp_bredr_capable(hdev)) {
2501 err = hci_le_scan(hdev, LE_SCAN_TYPE,
2502 LE_SCAN_INT, LE_SCAN_WIN,
2503 LE_SCAN_TIMEOUT_BREDR_LE);
2504 } else {
2505 hdev->discovery.type = DISCOV_TYPE_LE;
2506 err = hci_le_scan(hdev, LE_SCAN_TYPE,
2507 LE_SCAN_INT, LE_SCAN_WIN,
2508 LE_SCAN_TIMEOUT_LE_ONLY);
2509 }
2510 } else {
2511 hdev->discovery.type = DISCOV_TYPE_BREDR;
2512 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
2513 }
2514
2515 return err;
2516}
2517
2518int mgmt_interleaved_discovery(struct hci_dev *hdev)
2519{
2520 int err;
2521
2522 BT_DBG("%s", hdev->name);
2523
2524 hci_dev_lock(hdev);
2525
2526 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR_LE);
2527 if (err < 0)
2528 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2529
2530 hci_dev_unlock(hdev);
2531
2532 return err;
2533}
2534
Johan Hedberg450dfda2011-11-12 11:58:22 +02002535static int start_discovery(struct sock *sk, u16 index,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002536 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002537{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002538 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002539 struct pending_cmd *cmd;
2540 struct hci_dev *hdev;
2541 int err;
2542
2543 BT_DBG("hci%u", index);
2544
Johan Hedberg450dfda2011-11-12 11:58:22 +02002545 if (len != sizeof(*cp))
2546 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2547 MGMT_STATUS_INVALID_PARAMS);
2548
Johan Hedberg14a53662011-04-27 10:29:56 -04002549 hdev = hci_dev_get(index);
2550 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002551 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2552 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg14a53662011-04-27 10:29:56 -04002553
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002554 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002555
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002556 if (!hdev_is_powered(hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02002557 err = cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2558 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02002559 goto failed;
2560 }
2561
Johan Hedbergff9ef572012-01-04 14:23:45 +02002562 if (hdev->discovery.state != DISCOVERY_STOPPED) {
2563 err = cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2564 MGMT_STATUS_BUSY);
2565 goto failed;
2566 }
2567
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002568 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002569 if (!cmd) {
2570 err = -ENOMEM;
2571 goto failed;
2572 }
2573
Andre Guedes4aab14e2012-02-17 20:39:36 -03002574 hdev->discovery.type = cp->type;
2575
2576 switch (hdev->discovery.type) {
Andre Guedesf39799f2012-02-17 20:39:35 -03002577 case DISCOV_TYPE_BREDR:
Andre Guedes3fd24152012-02-03 17:48:01 -03002578 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
Andre Guedesf39799f2012-02-17 20:39:35 -03002579 break;
2580
2581 case DISCOV_TYPE_LE:
Andre Guedes3fd24152012-02-03 17:48:01 -03002582 err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT,
2583 LE_SCAN_WIN, LE_SCAN_TIMEOUT_LE_ONLY);
Andre Guedesf39799f2012-02-17 20:39:35 -03002584 break;
2585
Andre Guedes5e0452c2012-02-17 20:39:38 -03002586 case DISCOV_TYPE_INTERLEAVED:
2587 err = discovery(hdev);
2588 break;
2589
Andre Guedesf39799f2012-02-17 20:39:35 -03002590 default:
Andre Guedes3fd24152012-02-03 17:48:01 -03002591 err = -EINVAL;
Andre Guedesf39799f2012-02-17 20:39:35 -03002592 }
Andre Guedes3fd24152012-02-03 17:48:01 -03002593
Johan Hedberg14a53662011-04-27 10:29:56 -04002594 if (err < 0)
2595 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002596 else
2597 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002598
2599failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002600 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002601 hci_dev_put(hdev);
2602
2603 return err;
2604}
2605
Johan Hedbergd9306502012-02-20 23:25:18 +02002606static int stop_discovery(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002607{
Johan Hedbergd9306502012-02-20 23:25:18 +02002608 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002609 struct hci_dev *hdev;
2610 struct pending_cmd *cmd;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002611 struct hci_cp_remote_name_req_cancel cp;
2612 struct inquiry_entry *e;
Johan Hedberg14a53662011-04-27 10:29:56 -04002613 int err;
2614
2615 BT_DBG("hci%u", index);
2616
Johan Hedbergd9306502012-02-20 23:25:18 +02002617 if (len != sizeof(*mgmt_cp))
2618 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY,
2619 MGMT_STATUS_INVALID_PARAMS);
2620
Johan Hedberg14a53662011-04-27 10:29:56 -04002621 hdev = hci_dev_get(index);
2622 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002623 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY,
2624 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg14a53662011-04-27 10:29:56 -04002625
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002626 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002627
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002628 if (!hci_discovery_active(hdev)) {
Johan Hedbergd9306502012-02-20 23:25:18 +02002629 err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY,
2630 MGMT_STATUS_REJECTED,
2631 &mgmt_cp->type, sizeof(mgmt_cp->type));
2632 goto unlock;
2633 }
2634
2635 if (hdev->discovery.type != mgmt_cp->type) {
2636 err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY,
2637 MGMT_STATUS_INVALID_PARAMS,
2638 &mgmt_cp->type, sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002639 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02002640 }
2641
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002642 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002643 if (!cmd) {
2644 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002645 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04002646 }
2647
Andre Guedes343f9352012-02-17 20:39:37 -03002648 if (hdev->discovery.state == DISCOVERY_FINDING) {
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002649 err = hci_cancel_inquiry(hdev);
2650 if (err < 0)
2651 mgmt_pending_remove(cmd);
2652 else
2653 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
2654 goto unlock;
2655 }
2656
2657 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY, NAME_PENDING);
2658 if (!e) {
2659 mgmt_pending_remove(cmd);
Johan Hedbergaee9b212012-02-18 15:07:59 +02002660 err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY, 0,
Johan Hedbergd9306502012-02-20 23:25:18 +02002661 &mgmt_cp->type, sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002662 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2663 goto unlock;
2664 }
2665
2666 bacpy(&cp.bdaddr, &e->data.bdaddr);
2667 err = hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ_CANCEL,
2668 sizeof(cp), &cp);
Johan Hedberg14a53662011-04-27 10:29:56 -04002669 if (err < 0)
2670 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002671 else
2672 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002673
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002674unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002675 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002676 hci_dev_put(hdev);
2677
2678 return err;
2679}
2680
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002681static int confirm_name(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02002682{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002683 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002684 struct inquiry_entry *e;
2685 struct hci_dev *hdev;
2686 int err;
2687
2688 BT_DBG("hci%u", index);
2689
2690 if (len != sizeof(*cp))
2691 return cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2692 MGMT_STATUS_INVALID_PARAMS);
2693
2694 hdev = hci_dev_get(index);
2695 if (!hdev)
2696 return cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2697 MGMT_STATUS_INVALID_PARAMS);
2698
2699 hci_dev_lock(hdev);
2700
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002701 if (!hci_discovery_active(hdev)) {
2702 err = cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2703 MGMT_STATUS_FAILED);
2704 goto failed;
2705 }
2706
Johan Hedberga198e7b2012-02-17 14:27:06 +02002707 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002708 if (!e) {
Marcel Holtmanne5f0e152012-02-22 11:59:01 +01002709 err = cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
Johan Hedberg561aafb2012-01-04 13:31:59 +02002710 MGMT_STATUS_INVALID_PARAMS);
2711 goto failed;
2712 }
2713
2714 if (cp->name_known) {
2715 e->name_state = NAME_KNOWN;
2716 list_del(&e->list);
2717 } else {
2718 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e202012-01-09 00:53:02 +02002719 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002720 }
2721
2722 err = 0;
2723
2724failed:
2725 hci_dev_unlock(hdev);
2726
2727 return err;
2728}
2729
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002730static int block_device(struct sock *sk, u16 index, void *data, u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002731{
2732 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002733 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002734 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03002735 int err;
2736
2737 BT_DBG("hci%u", index);
2738
Antti Julku7fbec222011-06-15 12:01:15 +03002739 if (len != sizeof(*cp))
2740 return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002741 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002742
2743 hdev = hci_dev_get(index);
2744 if (!hdev)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002745 return cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE,
2746 MGMT_STATUS_INVALID_PARAMS,
2747 &cp->addr, sizeof(cp->addr));
Antti Julku7fbec222011-06-15 12:01:15 +03002748
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002749 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002750
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002751 err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002752 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002753 status = MGMT_STATUS_FAILED;
Antti Julku7fbec222011-06-15 12:01:15 +03002754 else
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002755 status = 0;
2756
2757 err = cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE, status,
2758 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03002759
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002760 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002761 hci_dev_put(hdev);
2762
2763 return err;
2764}
2765
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002766static int unblock_device(struct sock *sk, u16 index, void *data, u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002767{
2768 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002769 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002770 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03002771 int err;
2772
2773 BT_DBG("hci%u", index);
2774
Antti Julku7fbec222011-06-15 12:01:15 +03002775 if (len != sizeof(*cp))
2776 return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002777 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002778
2779 hdev = hci_dev_get(index);
2780 if (!hdev)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002781 return cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE,
2782 MGMT_STATUS_INVALID_PARAMS,
2783 &cp->addr, sizeof(cp->addr));
Antti Julku7fbec222011-06-15 12:01:15 +03002784
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002785 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002786
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002787 err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002788 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002789 status = MGMT_STATUS_INVALID_PARAMS;
Antti Julku7fbec222011-06-15 12:01:15 +03002790 else
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002791 status = 0;
2792
2793 err = cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE, status,
2794 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03002795
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002796 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002797 hci_dev_put(hdev);
2798
2799 return err;
2800}
2801
Antti Julkuf6422ec2011-06-22 13:11:56 +03002802static int set_fast_connectable(struct sock *sk, u16 index,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002803 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03002804{
2805 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002806 struct mgmt_mode *cp = data;
Antti Julkuf6422ec2011-06-22 13:11:56 +03002807 struct hci_cp_write_page_scan_activity acp;
2808 u8 type;
2809 int err;
2810
2811 BT_DBG("hci%u", index);
2812
2813 if (len != sizeof(*cp))
2814 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002815 MGMT_STATUS_INVALID_PARAMS);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002816
2817 hdev = hci_dev_get(index);
2818 if (!hdev)
2819 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002820 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg5400c042012-02-21 16:40:33 +02002821 if (!hdev_is_powered(hdev))
2822 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
2823 MGMT_STATUS_NOT_POWERED);
2824
2825 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
2826 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
2827 MGMT_STATUS_REJECTED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002828
2829 hci_dev_lock(hdev);
2830
Johan Hedbergf7c68692011-12-15 00:47:36 +02002831 if (cp->val) {
Antti Julkuf6422ec2011-06-22 13:11:56 +03002832 type = PAGE_SCAN_TYPE_INTERLACED;
2833 acp.interval = 0x0024; /* 22.5 msec page scan interval */
2834 } else {
2835 type = PAGE_SCAN_TYPE_STANDARD; /* default */
2836 acp.interval = 0x0800; /* default 1.28 sec page scan */
2837 }
2838
2839 acp.window = 0x0012; /* default 11.25 msec page scan window */
2840
2841 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
2842 sizeof(acp), &acp);
2843 if (err < 0) {
2844 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002845 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002846 goto done;
2847 }
2848
2849 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
2850 if (err < 0) {
2851 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002852 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002853 goto done;
2854 }
2855
Johan Hedbergaee9b212012-02-18 15:07:59 +02002856 err = cmd_complete(sk, index, MGMT_OP_SET_FAST_CONNECTABLE, 0,
2857 NULL, 0);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002858done:
2859 hci_dev_unlock(hdev);
2860 hci_dev_put(hdev);
2861
2862 return err;
2863}
2864
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002865static int load_long_term_keys(struct sock *sk, u16 index,
2866 void *cp_data, u16 len)
2867{
2868 struct hci_dev *hdev;
2869 struct mgmt_cp_load_long_term_keys *cp = cp_data;
2870 u16 key_count, expected_len;
2871 int i;
2872
2873 if (len < sizeof(*cp))
2874 return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS,
2875 EINVAL);
2876
2877 key_count = get_unaligned_le16(&cp->key_count);
2878
2879 expected_len = sizeof(*cp) + key_count *
2880 sizeof(struct mgmt_ltk_info);
2881 if (expected_len != len) {
2882 BT_ERR("load_keys: expected %u bytes, got %u bytes",
2883 len, expected_len);
2884 return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS,
2885 EINVAL);
2886 }
2887
2888 hdev = hci_dev_get(index);
2889 if (!hdev)
2890 return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS,
2891 ENODEV);
2892
2893 BT_DBG("hci%u key_count %u", index, key_count);
2894
2895 hci_dev_lock(hdev);
2896
2897 hci_smp_ltks_clear(hdev);
2898
2899 for (i = 0; i < key_count; i++) {
2900 struct mgmt_ltk_info *key = &cp->keys[i];
2901 u8 type;
2902
2903 if (key->master)
2904 type = HCI_SMP_LTK;
2905 else
2906 type = HCI_SMP_LTK_SLAVE;
2907
2908 hci_add_ltk(hdev, &key->addr.bdaddr, key->addr.type,
2909 type, 0, key->authenticated, key->val,
2910 key->enc_size, key->ediv, key->rand);
2911 }
2912
2913 hci_dev_unlock(hdev);
2914 hci_dev_put(hdev);
2915
2916 return 0;
2917}
2918
Johan Hedberg03811012010-12-08 00:21:06 +02002919int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
2920{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002921 void *buf;
2922 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02002923 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002924 u16 opcode, index, len;
Johan Hedberg03811012010-12-08 00:21:06 +02002925 int err;
2926
2927 BT_DBG("got %zu bytes", msglen);
2928
2929 if (msglen < sizeof(*hdr))
2930 return -EINVAL;
2931
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03002932 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02002933 if (!buf)
2934 return -ENOMEM;
2935
2936 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
2937 err = -EFAULT;
2938 goto done;
2939 }
2940
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002941 hdr = buf;
Johan Hedberg03811012010-12-08 00:21:06 +02002942 opcode = get_unaligned_le16(&hdr->opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002943 index = get_unaligned_le16(&hdr->index);
Johan Hedberg03811012010-12-08 00:21:06 +02002944 len = get_unaligned_le16(&hdr->len);
2945
2946 if (len != msglen - sizeof(*hdr)) {
2947 err = -EINVAL;
2948 goto done;
2949 }
2950
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002951 cp = buf + sizeof(*hdr);
2952
Johan Hedberg03811012010-12-08 00:21:06 +02002953 switch (opcode) {
Johan Hedberg02d98122010-12-13 21:07:04 +02002954 case MGMT_OP_READ_VERSION:
2955 err = read_version(sk);
2956 break;
Johan Hedberge70bb2e2012-02-13 16:59:33 +02002957 case MGMT_OP_READ_COMMANDS:
2958 err = read_commands(sk);
2959 break;
Johan Hedbergfaba42e2010-12-13 21:07:05 +02002960 case MGMT_OP_READ_INDEX_LIST:
2961 err = read_index_list(sk);
2962 break;
Johan Hedbergf7b64e62010-12-13 21:07:06 +02002963 case MGMT_OP_READ_INFO:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002964 err = read_controller_info(sk, index);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02002965 break;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002966 case MGMT_OP_SET_POWERED:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002967 err = set_powered(sk, index, cp, len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002968 break;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002969 case MGMT_OP_SET_DISCOVERABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002970 err = set_discoverable(sk, index, cp, len);
Johan Hedberg73f22f62010-12-29 16:00:25 +02002971 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002972 case MGMT_OP_SET_CONNECTABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002973 err = set_connectable(sk, index, cp, len);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002974 break;
Johan Hedbergf7c68692011-12-15 00:47:36 +02002975 case MGMT_OP_SET_FAST_CONNECTABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002976 err = set_fast_connectable(sk, index, cp, len);
Johan Hedbergf7c68692011-12-15 00:47:36 +02002977 break;
Johan Hedbergc542a062011-01-26 13:11:03 +02002978 case MGMT_OP_SET_PAIRABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002979 err = set_pairable(sk, index, cp, len);
Johan Hedbergc542a062011-01-26 13:11:03 +02002980 break;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02002981 case MGMT_OP_SET_LINK_SECURITY:
2982 err = set_link_security(sk, index, cp, len);
2983 break;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02002984 case MGMT_OP_SET_SSP:
2985 err = set_ssp(sk, index, cp, len);
2986 break;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02002987 case MGMT_OP_SET_HS:
2988 err = set_hs(sk, index, cp, len);
2989 break;
Johan Hedberg06199cf2012-02-22 16:37:11 +02002990 case MGMT_OP_SET_LE:
2991 err = set_le(sk, index, cp, len);
2992 break;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002993 case MGMT_OP_ADD_UUID:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002994 err = add_uuid(sk, index, cp, len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002995 break;
2996 case MGMT_OP_REMOVE_UUID:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002997 err = remove_uuid(sk, index, cp, len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002998 break;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002999 case MGMT_OP_SET_DEV_CLASS:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003000 err = set_dev_class(sk, index, cp, len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02003001 break;
Johan Hedberg86742e12011-11-07 23:13:38 +02003002 case MGMT_OP_LOAD_LINK_KEYS:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003003 err = load_link_keys(sk, index, cp, len);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02003004 break;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003005 case MGMT_OP_DISCONNECT:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003006 err = disconnect(sk, index, cp, len);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003007 break;
Johan Hedberg2784eb42011-01-21 13:56:35 +02003008 case MGMT_OP_GET_CONNECTIONS:
Szymon Janc8ce62842011-03-01 16:55:32 +01003009 err = get_connections(sk, index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02003010 break;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003011 case MGMT_OP_PIN_CODE_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003012 err = pin_code_reply(sk, index, cp, len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003013 break;
3014 case MGMT_OP_PIN_CODE_NEG_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003015 err = pin_code_neg_reply(sk, index, cp, len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003016 break;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02003017 case MGMT_OP_SET_IO_CAPABILITY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003018 err = set_io_capability(sk, index, cp, len);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02003019 break;
Johan Hedberge9a416b2011-02-19 12:05:56 -03003020 case MGMT_OP_PAIR_DEVICE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003021 err = pair_device(sk, index, cp, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03003022 break;
Johan Hedberg28424702012-02-02 04:02:29 +02003023 case MGMT_OP_CANCEL_PAIR_DEVICE:
3024 err = cancel_pair_device(sk, index, buf + sizeof(*hdr), len);
3025 break;
Johan Hedberg124f6e32012-02-09 13:50:12 +02003026 case MGMT_OP_UNPAIR_DEVICE:
3027 err = unpair_device(sk, index, cp, len);
3028 break;
Johan Hedberga5c29682011-02-19 12:05:57 -03003029 case MGMT_OP_USER_CONFIRM_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003030 err = user_confirm_reply(sk, index, cp, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03003031 break;
3032 case MGMT_OP_USER_CONFIRM_NEG_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003033 err = user_confirm_neg_reply(sk, index, cp, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03003034 break;
Brian Gix604086b2011-11-23 08:28:33 -08003035 case MGMT_OP_USER_PASSKEY_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003036 err = user_passkey_reply(sk, index, cp, len);
Brian Gix604086b2011-11-23 08:28:33 -08003037 break;
3038 case MGMT_OP_USER_PASSKEY_NEG_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003039 err = user_passkey_neg_reply(sk, index, cp, len);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02003040 break;
Johan Hedbergb312b1612011-03-16 14:29:37 +02003041 case MGMT_OP_SET_LOCAL_NAME:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003042 err = set_local_name(sk, index, cp, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003043 break;
Szymon Jancc35938b2011-03-22 13:12:21 +01003044 case MGMT_OP_READ_LOCAL_OOB_DATA:
3045 err = read_local_oob_data(sk, index);
3046 break;
Szymon Janc2763eda2011-03-22 13:12:22 +01003047 case MGMT_OP_ADD_REMOTE_OOB_DATA:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003048 err = add_remote_oob_data(sk, index, cp, len);
Szymon Janc2763eda2011-03-22 13:12:22 +01003049 break;
3050 case MGMT_OP_REMOVE_REMOTE_OOB_DATA:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003051 err = remove_remote_oob_data(sk, index, cp, len);
Szymon Janc2763eda2011-03-22 13:12:22 +01003052 break;
Johan Hedberg14a53662011-04-27 10:29:56 -04003053 case MGMT_OP_START_DISCOVERY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003054 err = start_discovery(sk, index, cp, len);
Johan Hedberg14a53662011-04-27 10:29:56 -04003055 break;
3056 case MGMT_OP_STOP_DISCOVERY:
Johan Hedbergd9306502012-02-20 23:25:18 +02003057 err = stop_discovery(sk, index, cp, len);
Johan Hedberg14a53662011-04-27 10:29:56 -04003058 break;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003059 case MGMT_OP_CONFIRM_NAME:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003060 err = confirm_name(sk, index, cp, len);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003061 break;
Antti Julku7fbec222011-06-15 12:01:15 +03003062 case MGMT_OP_BLOCK_DEVICE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003063 err = block_device(sk, index, cp, len);
Antti Julku7fbec222011-06-15 12:01:15 +03003064 break;
3065 case MGMT_OP_UNBLOCK_DEVICE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003066 err = unblock_device(sk, index, cp, len);
Antti Julku7fbec222011-06-15 12:01:15 +03003067 break;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003068 case MGMT_OP_LOAD_LONG_TERM_KEYS:
3069 err = load_long_term_keys(sk, index, cp, len);
3070 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003071 default:
Johan Hedberg72a734e2010-12-30 00:38:22 +02003072 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02003073 err = cmd_status(sk, index, opcode,
3074 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003075 break;
3076 }
Johan Hedberg72a734e2010-12-30 00:38:22 +02003077
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003078 if (err < 0)
Johan Hedberg72a734e2010-12-30 00:38:22 +02003079 goto done;
3080
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003081 err = msglen;
3082
3083done:
3084 kfree(buf);
3085 return err;
3086}
3087
Johan Hedbergb24752f2011-11-03 14:40:33 +02003088static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
3089{
3090 u8 *status = data;
3091
3092 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
3093 mgmt_pending_remove(cmd);
3094}
3095
Johan Hedberg744cf192011-11-08 20:40:14 +02003096int mgmt_index_added(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +02003097{
Johan Hedberg744cf192011-11-08 20:40:14 +02003098 return mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02003099}
3100
Johan Hedberg744cf192011-11-08 20:40:14 +02003101int mgmt_index_removed(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +02003102{
Johan Hedbergb24752f2011-11-03 14:40:33 +02003103 u8 status = ENODEV;
3104
Johan Hedberg744cf192011-11-08 20:40:14 +02003105 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02003106
Johan Hedberg744cf192011-11-08 20:40:14 +02003107 return mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02003108}
3109
3110struct cmd_lookup {
Johan Hedberg03811012010-12-08 00:21:06 +02003111 struct sock *sk;
Johan Hedberg69ab39e2011-12-15 00:47:35 +02003112 struct hci_dev *hdev;
Johan Hedberg03811012010-12-08 00:21:06 +02003113};
3114
Johan Hedberg69ab39e2011-12-15 00:47:35 +02003115static void settings_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberg03811012010-12-08 00:21:06 +02003116{
Johan Hedberg03811012010-12-08 00:21:06 +02003117 struct cmd_lookup *match = data;
3118
Johan Hedberg69ab39e2011-12-15 00:47:35 +02003119 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02003120
3121 list_del(&cmd->list);
3122
3123 if (match->sk == NULL) {
3124 match->sk = cmd->sk;
3125 sock_hold(match->sk);
3126 }
3127
3128 mgmt_pending_free(cmd);
3129}
3130
Johan Hedberg744cf192011-11-08 20:40:14 +02003131int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg03811012010-12-08 00:21:06 +02003132{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02003133 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003134 int err;
Johan Hedberg03811012010-12-08 00:21:06 +02003135
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003136 if (!test_bit(HCI_MGMT, &hdev->dev_flags))
3137 return 0;
3138
Johan Hedberg69ab39e2011-12-15 00:47:35 +02003139 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
Johan Hedberg03811012010-12-08 00:21:06 +02003140
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003141 if (powered) {
3142 u8 scan = 0;
3143
3144 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3145 scan |= SCAN_PAGE;
3146 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3147 scan |= SCAN_INQUIRY;
3148
3149 if (scan)
3150 hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
Johan Hedberg504c8dc2012-02-23 13:30:41 +02003151
3152 update_class(hdev);
3153 update_eir(hdev);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003154 } else {
Johan Hedbergb24752f2011-11-03 14:40:33 +02003155 u8 status = ENETDOWN;
Johan Hedberg744cf192011-11-08 20:40:14 +02003156 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02003157 }
3158
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003159 err = new_settings(hdev, match.sk);
Johan Hedberg03811012010-12-08 00:21:06 +02003160
3161 if (match.sk)
3162 sock_put(match.sk);
3163
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003164 return err;
Johan Hedberg03811012010-12-08 00:21:06 +02003165}
3166
Johan Hedberg744cf192011-11-08 20:40:14 +02003167int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg03811012010-12-08 00:21:06 +02003168{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02003169 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003170 bool changed = false;
3171 int err = 0;
Johan Hedberg03811012010-12-08 00:21:06 +02003172
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003173 if (discoverable) {
3174 if (!test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3175 changed = true;
3176 } else {
3177 if (test_and_clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3178 changed = true;
3179 }
Johan Hedberg03811012010-12-08 00:21:06 +02003180
Johan Hedberged9b5f22012-02-21 20:47:06 +02003181 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp,
3182 &match);
3183
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003184 if (changed)
3185 err = new_settings(hdev, match.sk);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003186
Johan Hedberg03811012010-12-08 00:21:06 +02003187 if (match.sk)
3188 sock_put(match.sk);
3189
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003190 return err;
Johan Hedberg03811012010-12-08 00:21:06 +02003191}
3192
Johan Hedberg744cf192011-11-08 20:40:14 +02003193int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg03811012010-12-08 00:21:06 +02003194{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02003195 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003196 bool changed = false;
3197 int err = 0;
Johan Hedberg03811012010-12-08 00:21:06 +02003198
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003199 if (connectable) {
3200 if (!test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3201 changed = true;
3202 } else {
3203 if (test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3204 changed = true;
3205 }
Johan Hedberg03811012010-12-08 00:21:06 +02003206
Johan Hedberged9b5f22012-02-21 20:47:06 +02003207 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev, settings_rsp,
3208 &match);
3209
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003210 if (changed)
3211 err = new_settings(hdev, match.sk);
Johan Hedberg03811012010-12-08 00:21:06 +02003212
3213 if (match.sk)
3214 sock_put(match.sk);
3215
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003216 return err;
Johan Hedberg03811012010-12-08 00:21:06 +02003217}
3218
Johan Hedberg744cf192011-11-08 20:40:14 +02003219int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003220{
Johan Hedbergca69b792011-11-11 18:10:00 +02003221 u8 mgmt_err = mgmt_status(status);
3222
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003223 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02003224 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Johan Hedbergca69b792011-11-11 18:10:00 +02003225 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003226
3227 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02003228 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Johan Hedbergca69b792011-11-11 18:10:00 +02003229 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003230
3231 return 0;
3232}
3233
Johan Hedberg744cf192011-11-08 20:40:14 +02003234int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
3235 u8 persistent)
Johan Hedberg03811012010-12-08 00:21:06 +02003236{
Johan Hedberg86742e12011-11-07 23:13:38 +02003237 struct mgmt_ev_new_link_key ev;
Johan Hedberg03811012010-12-08 00:21:06 +02003238
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003239 memset(&ev, 0, sizeof(ev));
Johan Hedberg03811012010-12-08 00:21:06 +02003240
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003241 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02003242 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
3243 ev.key.addr.type = MGMT_ADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003244 ev.key.type = key->type;
3245 memcpy(ev.key.val, key->val, 16);
3246 ev.key.pin_len = key->pin_len;
Johan Hedberg03811012010-12-08 00:21:06 +02003247
Johan Hedberg744cf192011-11-08 20:40:14 +02003248 return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02003249}
Johan Hedbergf7520542011-01-20 12:34:39 +02003250
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003251int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
3252{
3253 struct mgmt_ev_new_long_term_key ev;
3254
3255 memset(&ev, 0, sizeof(ev));
3256
3257 ev.store_hint = persistent;
3258 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
3259 ev.key.addr.type = key->bdaddr_type;
3260 ev.key.authenticated = key->authenticated;
3261 ev.key.enc_size = key->enc_size;
3262 ev.key.ediv = key->ediv;
3263
3264 if (key->type == HCI_SMP_LTK)
3265 ev.key.master = 1;
3266
3267 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
3268 memcpy(ev.key.val, key->val, sizeof(key->val));
3269
3270 return mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev,
3271 &ev, sizeof(ev), NULL);
3272}
3273
Johan Hedbergafc747a2012-01-15 18:11:07 +02003274int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Johan Hedberg08c79b62012-02-23 22:31:51 +02003275 u8 addr_type, u32 flags, u8 *name,
3276 u8 name_len, u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02003277{
Johan Hedbergb644ba32012-01-17 21:48:47 +02003278 char buf[512];
3279 struct mgmt_ev_device_connected *ev = (void *) buf;
3280 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02003281
Johan Hedbergb644ba32012-01-17 21:48:47 +02003282 bacpy(&ev->addr.bdaddr, bdaddr);
3283 ev->addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02003284
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02003285 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02003286
Johan Hedbergb644ba32012-01-17 21:48:47 +02003287 if (name_len > 0)
3288 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
3289 name, name_len);
3290
3291 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
3292 eir_len = eir_append_data(&ev->eir[eir_len], eir_len,
3293 EIR_CLASS_OF_DEV, dev_class, 3);
3294
3295 put_unaligned_le16(eir_len, &ev->eir_len);
3296
3297 return mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
3298 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02003299}
3300
Johan Hedberg8962ee72011-01-20 12:40:27 +02003301static void disconnect_rsp(struct pending_cmd *cmd, void *data)
3302{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01003303 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003304 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02003305 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003306
Johan Hedberg88c3df12012-02-09 14:27:38 +02003307 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3308 rp.addr.type = cp->addr.type;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003309
Johan Hedbergaee9b212012-02-18 15:07:59 +02003310 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, 0, &rp,
3311 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003312
3313 *sk = cmd->sk;
3314 sock_hold(*sk);
3315
Johan Hedberga664b5b2011-02-19 12:06:02 -03003316 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003317}
3318
Johan Hedberg124f6e32012-02-09 13:50:12 +02003319static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02003320{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003321 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02003322 struct mgmt_cp_unpair_device *cp = cmd->param;
3323 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02003324
3325 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02003326 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3327 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02003328
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003329 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
3330
Johan Hedbergaee9b212012-02-18 15:07:59 +02003331 cmd_complete(cmd->sk, cmd->index, cmd->opcode, 0, &rp, sizeof(rp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02003332
3333 mgmt_pending_remove(cmd);
3334}
3335
Johan Hedbergafc747a2012-01-15 18:11:07 +02003336int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
3337 u8 link_type, u8 addr_type)
Johan Hedbergf7520542011-01-20 12:34:39 +02003338{
Johan Hedberg4c659c32011-11-07 23:13:39 +02003339 struct mgmt_addr_info ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003340 struct sock *sk = NULL;
3341 int err;
3342
Johan Hedberg744cf192011-11-08 20:40:14 +02003343 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02003344
Johan Hedbergf7520542011-01-20 12:34:39 +02003345 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02003346 ev.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02003347
Johan Hedbergafc747a2012-01-15 18:11:07 +02003348 err = mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev),
3349 sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003350
3351 if (sk)
3352 sock_put(sk);
3353
Johan Hedberg124f6e32012-02-09 13:50:12 +02003354 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003355 hdev);
Johan Hedberga8a1d192011-11-10 15:54:38 +02003356
Johan Hedberg8962ee72011-01-20 12:40:27 +02003357 return err;
3358}
3359
Johan Hedberg88c3df12012-02-09 14:27:38 +02003360int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
3361 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02003362{
Johan Hedberg88c3df12012-02-09 14:27:38 +02003363 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003364 struct pending_cmd *cmd;
3365 int err;
3366
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003367 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003368 if (!cmd)
3369 return -ENOENT;
3370
Johan Hedberg88c3df12012-02-09 14:27:38 +02003371 bacpy(&rp.addr.bdaddr, bdaddr);
3372 rp.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02003373
Johan Hedberg88c3df12012-02-09 14:27:38 +02003374 err = cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
Johan Hedbergaee9b212012-02-18 15:07:59 +02003375 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003376
Johan Hedberga664b5b2011-02-19 12:06:02 -03003377 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003378
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003379 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
3380 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003381 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02003382}
Johan Hedberg17d5c042011-01-22 06:09:08 +02003383
Johan Hedberg48264f02011-11-09 13:58:58 +02003384int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
3385 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02003386{
3387 struct mgmt_ev_connect_failed ev;
3388
Johan Hedberg4c659c32011-11-07 23:13:39 +02003389 bacpy(&ev.addr.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02003390 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003391 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003392
Johan Hedberg744cf192011-11-08 20:40:14 +02003393 return mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003394}
Johan Hedberg980e1a52011-01-22 06:10:07 +02003395
Johan Hedberg744cf192011-11-08 20:40:14 +02003396int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003397{
3398 struct mgmt_ev_pin_code_request ev;
3399
Johan Hedbergd8457692012-02-17 14:24:57 +02003400 bacpy(&ev.addr.bdaddr, bdaddr);
3401 ev.addr.type = MGMT_ADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02003402 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003403
Johan Hedberg744cf192011-11-08 20:40:14 +02003404 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01003405 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003406}
3407
Johan Hedberg744cf192011-11-08 20:40:14 +02003408int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3409 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003410{
3411 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003412 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003413 int err;
3414
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003415 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003416 if (!cmd)
3417 return -ENOENT;
3418
Johan Hedbergd8457692012-02-17 14:24:57 +02003419 bacpy(&rp.addr.bdaddr, bdaddr);
3420 rp.addr.type = MGMT_ADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003421
Johan Hedbergaee9b212012-02-18 15:07:59 +02003422 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
3423 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003424
Johan Hedberga664b5b2011-02-19 12:06:02 -03003425 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003426
3427 return err;
3428}
3429
Johan Hedberg744cf192011-11-08 20:40:14 +02003430int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3431 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003432{
3433 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003434 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003435 int err;
3436
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003437 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003438 if (!cmd)
3439 return -ENOENT;
3440
Johan Hedbergd8457692012-02-17 14:24:57 +02003441 bacpy(&rp.addr.bdaddr, bdaddr);
3442 rp.addr.type = MGMT_ADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003443
Johan Hedbergaee9b212012-02-18 15:07:59 +02003444 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
3445 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003446
Johan Hedberga664b5b2011-02-19 12:06:02 -03003447 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003448
3449 return err;
3450}
Johan Hedberga5c29682011-02-19 12:05:57 -03003451
Johan Hedberg744cf192011-11-08 20:40:14 +02003452int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003453 u8 link_type, u8 addr_type, __le32 value,
3454 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03003455{
3456 struct mgmt_ev_user_confirm_request ev;
3457
Johan Hedberg744cf192011-11-08 20:40:14 +02003458 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03003459
Johan Hedberg272d90d2012-02-09 15:26:12 +02003460 bacpy(&ev.addr.bdaddr, bdaddr);
3461 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07003462 ev.confirm_hint = confirm_hint;
Johan Hedberga5c29682011-02-19 12:05:57 -03003463 put_unaligned_le32(value, &ev.value);
3464
Johan Hedberg744cf192011-11-08 20:40:14 +02003465 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01003466 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03003467}
3468
Johan Hedberg272d90d2012-02-09 15:26:12 +02003469int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
3470 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08003471{
3472 struct mgmt_ev_user_passkey_request ev;
3473
3474 BT_DBG("%s", hdev->name);
3475
Johan Hedberg272d90d2012-02-09 15:26:12 +02003476 bacpy(&ev.addr.bdaddr, bdaddr);
3477 ev.addr.type = link_to_mgmt(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08003478
3479 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
3480 NULL);
3481}
3482
Brian Gix0df4c182011-11-16 13:53:13 -08003483static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003484 u8 link_type, u8 addr_type, u8 status,
3485 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03003486{
3487 struct pending_cmd *cmd;
3488 struct mgmt_rp_user_confirm_reply rp;
3489 int err;
3490
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003491 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03003492 if (!cmd)
3493 return -ENOENT;
3494
Johan Hedberg272d90d2012-02-09 15:26:12 +02003495 bacpy(&rp.addr.bdaddr, bdaddr);
3496 rp.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergaee9b212012-02-18 15:07:59 +02003497 err = cmd_complete(cmd->sk, hdev->id, opcode, mgmt_status(status),
3498 &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03003499
Johan Hedberga664b5b2011-02-19 12:06:02 -03003500 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03003501
3502 return err;
3503}
3504
Johan Hedberg744cf192011-11-08 20:40:14 +02003505int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003506 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003507{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003508 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3509 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003510}
3511
Johan Hedberg272d90d2012-02-09 15:26:12 +02003512int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3513 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003514{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003515 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3516 status, MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003517}
Johan Hedberg2a611692011-02-19 12:06:00 -03003518
Brian Gix604086b2011-11-23 08:28:33 -08003519int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003520 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003521{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003522 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3523 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003524}
3525
Johan Hedberg272d90d2012-02-09 15:26:12 +02003526int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3527 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003528{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003529 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3530 status, MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003531}
3532
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003533int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
3534 u8 addr_type, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03003535{
3536 struct mgmt_ev_auth_failed ev;
3537
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003538 bacpy(&ev.addr.bdaddr, bdaddr);
3539 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003540 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03003541
Johan Hedberg744cf192011-11-08 20:40:14 +02003542 return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03003543}
Johan Hedbergb312b1612011-03-16 14:29:37 +02003544
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003545int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
3546{
3547 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg47990ea2012-02-22 11:58:37 +02003548 bool changed = false;
3549 int err = 0;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003550
3551 if (status) {
3552 u8 mgmt_err = mgmt_status(status);
3553 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
3554 cmd_status_rsp, &mgmt_err);
3555 return 0;
3556 }
3557
Johan Hedberg47990ea2012-02-22 11:58:37 +02003558 if (test_bit(HCI_AUTH, &hdev->flags)) {
3559 if (!test_and_set_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
3560 changed = true;
3561 } else {
3562 if (test_and_clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
3563 changed = true;
3564 }
3565
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003566 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
3567 &match);
3568
Johan Hedberg47990ea2012-02-22 11:58:37 +02003569 if (changed)
3570 err = new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003571
3572 if (match.sk)
3573 sock_put(match.sk);
3574
3575 return err;
3576}
3577
Johan Hedbergcacaf522012-02-21 00:52:42 +02003578static int clear_eir(struct hci_dev *hdev)
3579{
3580 struct hci_cp_write_eir cp;
3581
3582 if (!(hdev->features[6] & LMP_EXT_INQ))
3583 return 0;
3584
Johan Hedbergc80da272012-02-22 15:38:48 +02003585 memset(hdev->eir, 0, sizeof(hdev->eir));
3586
Johan Hedbergcacaf522012-02-21 00:52:42 +02003587 memset(&cp, 0, sizeof(cp));
3588
3589 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
3590}
3591
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003592int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003593{
3594 struct cmd_lookup match = { NULL, hdev };
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003595 bool changed = false;
3596 int err = 0;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003597
3598 if (status) {
3599 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003600
3601 if (enable && test_and_clear_bit(HCI_SSP_ENABLED,
3602 &hdev->dev_flags))
3603 err = new_settings(hdev, NULL);
3604
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003605 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev,
3606 cmd_status_rsp, &mgmt_err);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003607
3608 return err;
3609 }
3610
3611 if (enable) {
3612 if (!test_and_set_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3613 changed = true;
3614 } else {
3615 if (test_and_clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3616 changed = true;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003617 }
3618
3619 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
3620
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003621 if (changed)
3622 err = new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003623
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02003624 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003625 sock_put(match.sk);
3626
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02003627 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3628 update_eir(hdev);
3629 else
3630 clear_eir(hdev);
Johan Hedbergcacaf522012-02-21 00:52:42 +02003631
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003632 return err;
3633}
3634
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003635int mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
3636 u8 status)
3637{
3638 int err;
3639
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02003640 clear_bit(HCI_PENDING_CLASS, &hdev->dev_flags);
3641
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003642 err = mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class, 3, NULL);
3643
3644 return err;
3645}
3646
Johan Hedberg744cf192011-11-08 20:40:14 +02003647int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02003648{
3649 struct pending_cmd *cmd;
3650 struct mgmt_cp_set_local_name ev;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003651 bool changed = false;
3652 int err = 0;
3653
3654 if (memcmp(name, hdev->dev_name, sizeof(hdev->dev_name)) != 0) {
3655 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
3656 changed = true;
3657 }
Johan Hedbergb312b1612011-03-16 14:29:37 +02003658
3659 memset(&ev, 0, sizeof(ev));
3660 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003661 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003662
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003663 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003664 if (!cmd)
3665 goto send_event;
3666
Johan Hedberg7bdaae42012-02-22 21:39:58 +02003667 /* Always assume that either the short or the complete name has
3668 * changed if there was a pending mgmt command */
3669 changed = true;
3670
Johan Hedbergb312b1612011-03-16 14:29:37 +02003671 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02003672 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
Johan Hedbergca69b792011-11-11 18:10:00 +02003673 mgmt_status(status));
Johan Hedbergb312b1612011-03-16 14:29:37 +02003674 goto failed;
3675 }
3676
Johan Hedbergaee9b212012-02-18 15:07:59 +02003677 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0, &ev,
Johan Hedbergb312b1612011-03-16 14:29:37 +02003678 sizeof(ev));
3679 if (err < 0)
3680 goto failed;
3681
3682send_event:
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003683 if (changed)
3684 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev,
3685 sizeof(ev), cmd ? cmd->sk : NULL);
3686
Johan Hedbergf51d5b22012-02-22 18:17:32 +02003687 update_eir(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003688
3689failed:
3690 if (cmd)
3691 mgmt_pending_remove(cmd);
3692 return err;
3693}
Szymon Jancc35938b2011-03-22 13:12:21 +01003694
Johan Hedberg744cf192011-11-08 20:40:14 +02003695int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
3696 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01003697{
3698 struct pending_cmd *cmd;
3699 int err;
3700
Johan Hedberg744cf192011-11-08 20:40:14 +02003701 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01003702
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003703 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003704 if (!cmd)
3705 return -ENOENT;
3706
3707 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02003708 err = cmd_status(cmd->sk, hdev->id,
Johan Hedbergca69b792011-11-11 18:10:00 +02003709 MGMT_OP_READ_LOCAL_OOB_DATA,
3710 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01003711 } else {
3712 struct mgmt_rp_read_local_oob_data rp;
3713
3714 memcpy(rp.hash, hash, sizeof(rp.hash));
3715 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
3716
Johan Hedberg744cf192011-11-08 20:40:14 +02003717 err = cmd_complete(cmd->sk, hdev->id,
3718 MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergaee9b212012-02-18 15:07:59 +02003719 0, &rp, sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01003720 }
3721
3722 mgmt_pending_remove(cmd);
3723
3724 return err;
3725}
Johan Hedberge17acd42011-03-30 23:57:16 +03003726
Johan Hedberg06199cf2012-02-22 16:37:11 +02003727int mgmt_le_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
3728{
3729 struct cmd_lookup match = { NULL, hdev };
3730 bool changed = false;
3731 int err = 0;
3732
3733 if (status) {
3734 u8 mgmt_err = mgmt_status(status);
3735
3736 if (enable && test_and_clear_bit(HCI_LE_ENABLED,
3737 &hdev->dev_flags))
3738 err = new_settings(hdev, NULL);
3739
3740 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev,
3741 cmd_status_rsp, &mgmt_err);
3742
3743 return err;
3744 }
3745
3746 if (enable) {
3747 if (!test_and_set_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3748 changed = true;
3749 } else {
3750 if (test_and_clear_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3751 changed = true;
3752 }
3753
3754 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
3755
3756 if (changed)
3757 err = new_settings(hdev, match.sk);
3758
3759 if (match.sk)
3760 sock_put(match.sk);
3761
3762 return err;
3763}
3764
Johan Hedberg48264f02011-11-09 13:58:58 +02003765int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Johan Hedberg561aafb2012-01-04 13:31:59 +02003766 u8 addr_type, u8 *dev_class, s8 rssi,
Johan Hedberg388fc8f2012-02-23 00:38:59 +02003767 u8 cfm_name, u8 ssp, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03003768{
Johan Hedberge319d2e2012-01-15 19:51:59 +02003769 char buf[512];
3770 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02003771 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03003772
Johan Hedberg1dc06092012-01-15 21:01:23 +02003773 /* Leave 5 bytes for a potential CoD field */
3774 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Andre Guedes7d262f82012-01-10 18:20:49 -03003775 return -EINVAL;
3776
Johan Hedberg1dc06092012-01-15 21:01:23 +02003777 memset(buf, 0, sizeof(buf));
3778
Johan Hedberge319d2e2012-01-15 19:51:59 +02003779 bacpy(&ev->addr.bdaddr, bdaddr);
3780 ev->addr.type = link_to_mgmt(link_type, addr_type);
3781 ev->rssi = rssi;
Johan Hedberg9a395a82012-02-23 00:00:32 +02003782 if (cfm_name)
3783 ev->flags[0] |= MGMT_DEV_FOUND_CONFIRM_NAME;
Johan Hedberg388fc8f2012-02-23 00:38:59 +02003784 if (!ssp)
3785 ev->flags[0] |= MGMT_DEV_FOUND_LEGACY_PAIRING;
Johan Hedberge17acd42011-03-30 23:57:16 +03003786
Johan Hedberg1dc06092012-01-15 21:01:23 +02003787 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02003788 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03003789
Johan Hedberg1dc06092012-01-15 21:01:23 +02003790 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
3791 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
3792 dev_class, 3);
3793
3794 put_unaligned_le16(eir_len, &ev->eir_len);
3795
3796 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03003797
Johan Hedberge319d2e2012-01-15 19:51:59 +02003798 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03003799}
Johan Hedberga88a9652011-03-30 13:18:12 +03003800
Johan Hedbergb644ba32012-01-17 21:48:47 +02003801int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
3802 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03003803{
Johan Hedbergb644ba32012-01-17 21:48:47 +02003804 struct mgmt_ev_device_found *ev;
3805 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
3806 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03003807
Johan Hedbergb644ba32012-01-17 21:48:47 +02003808 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03003809
Johan Hedbergb644ba32012-01-17 21:48:47 +02003810 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03003811
Johan Hedbergb644ba32012-01-17 21:48:47 +02003812 bacpy(&ev->addr.bdaddr, bdaddr);
3813 ev->addr.type = link_to_mgmt(link_type, addr_type);
3814 ev->rssi = rssi;
3815
3816 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
3817 name_len);
3818
3819 put_unaligned_le16(eir_len, &ev->eir_len);
3820
Johan Hedberg053c7e02012-02-04 00:06:00 +02003821 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev,
3822 sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03003823}
Johan Hedberg314b2382011-04-27 10:29:57 -04003824
Andre Guedes7a135102011-11-09 17:14:25 -03003825int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
Johan Hedberg164a6e72011-11-01 17:06:44 +02003826{
3827 struct pending_cmd *cmd;
Johan Hedbergf808e162012-02-19 12:52:07 +02003828 u8 type;
Johan Hedberg164a6e72011-11-01 17:06:44 +02003829 int err;
3830
Andre Guedes203159d2012-02-13 15:41:01 -03003831 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3832
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003833 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003834 if (!cmd)
3835 return -ENOENT;
3836
Johan Hedbergf808e162012-02-19 12:52:07 +02003837 type = hdev->discovery.type;
3838
3839 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
3840 &type, sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02003841 mgmt_pending_remove(cmd);
3842
3843 return err;
3844}
3845
Andre Guedese6d465c2011-11-09 17:14:26 -03003846int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
3847{
3848 struct pending_cmd *cmd;
3849 int err;
3850
3851 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
3852 if (!cmd)
3853 return -ENOENT;
3854
Johan Hedbergd9306502012-02-20 23:25:18 +02003855 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
3856 &hdev->discovery.type,
3857 sizeof(hdev->discovery.type));
Johan Hedberg03811012010-12-08 00:21:06 +02003858 mgmt_pending_remove(cmd);
3859
3860 return err;
3861}
Johan Hedberg314b2382011-04-27 10:29:57 -04003862
Johan Hedberg744cf192011-11-08 20:40:14 +02003863int mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04003864{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02003865 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02003866 struct pending_cmd *cmd;
3867
Andre Guedes343fb142011-11-22 17:14:19 -03003868 BT_DBG("%s discovering %u", hdev->name, discovering);
3869
Johan Hedberg164a6e72011-11-01 17:06:44 +02003870 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003871 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003872 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003873 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003874
3875 if (cmd != NULL) {
Johan Hedbergf808e162012-02-19 12:52:07 +02003876 u8 type = hdev->discovery.type;
3877
Johan Hedbergd9306502012-02-20 23:25:18 +02003878 cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0,
Johan Hedbergf808e162012-02-19 12:52:07 +02003879 &type, sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02003880 mgmt_pending_remove(cmd);
3881 }
3882
Johan Hedbergf963e8e2012-02-20 23:30:44 +02003883 memset(&ev, 0, sizeof(ev));
3884 ev.type = hdev->discovery.type;
3885 ev.discovering = discovering;
3886
3887 return mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04003888}
Antti Julku5e762442011-08-25 16:48:02 +03003889
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003890int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003891{
3892 struct pending_cmd *cmd;
3893 struct mgmt_ev_device_blocked ev;
3894
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003895 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003896
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003897 bacpy(&ev.addr.bdaddr, bdaddr);
3898 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003899
Johan Hedberg744cf192011-11-08 20:40:14 +02003900 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
3901 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003902}
3903
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003904int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003905{
3906 struct pending_cmd *cmd;
3907 struct mgmt_ev_device_unblocked ev;
3908
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003909 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003910
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003911 bacpy(&ev.addr.bdaddr, bdaddr);
3912 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003913
Johan Hedberg744cf192011-11-08 20:40:14 +02003914 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
3915 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003916}
Marcel Holtmannd7b7e792012-02-20 21:47:49 +01003917
3918module_param(enable_hs, bool, 0644);
3919MODULE_PARM_DESC(enable_hs, "Enable High Speed support");
3920
3921module_param(enable_le, bool, 0644);
3922MODULE_PARM_DESC(enable_le, "Enable Low Energy support");