blob: 434df715448e7b837246ef93c7f1214f0b5930de [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
Paul Gortmaker3a9a2312011-05-27 09:12:25 -040027#include <linux/module.h>
Johan Hedberg03811012010-12-08 00:21:06 +020028#include <asm/unaligned.h>
29
30#include <net/bluetooth/bluetooth.h>
31#include <net/bluetooth/hci_core.h>
32#include <net/bluetooth/mgmt.h>
Brian Gix5fe57d92011-12-21 16:12:13 -080033#include <net/bluetooth/smp.h>
Johan Hedberg03811012010-12-08 00:21:06 +020034
Marcel Holtmannd7b7e792012-02-20 21:47:49 +010035bool enable_hs;
Marcel Holtmannd7b7e792012-02-20 21:47:49 +010036
Johan Hedberg2da9c552012-02-17 14:39:28 +020037#define MGMT_VERSION 1
Johan Hedberg38102852013-01-27 08:32:01 -060038#define MGMT_REVISION 3
Johan Hedberg02d98122010-12-13 21:07:04 +020039
Johan Hedberge70bb2e2012-02-13 16:59:33 +020040static const u16 mgmt_commands[] = {
41 MGMT_OP_READ_INDEX_LIST,
42 MGMT_OP_READ_INFO,
43 MGMT_OP_SET_POWERED,
44 MGMT_OP_SET_DISCOVERABLE,
45 MGMT_OP_SET_CONNECTABLE,
46 MGMT_OP_SET_FAST_CONNECTABLE,
47 MGMT_OP_SET_PAIRABLE,
48 MGMT_OP_SET_LINK_SECURITY,
49 MGMT_OP_SET_SSP,
50 MGMT_OP_SET_HS,
51 MGMT_OP_SET_LE,
52 MGMT_OP_SET_DEV_CLASS,
53 MGMT_OP_SET_LOCAL_NAME,
54 MGMT_OP_ADD_UUID,
55 MGMT_OP_REMOVE_UUID,
56 MGMT_OP_LOAD_LINK_KEYS,
57 MGMT_OP_LOAD_LONG_TERM_KEYS,
58 MGMT_OP_DISCONNECT,
59 MGMT_OP_GET_CONNECTIONS,
60 MGMT_OP_PIN_CODE_REPLY,
61 MGMT_OP_PIN_CODE_NEG_REPLY,
62 MGMT_OP_SET_IO_CAPABILITY,
63 MGMT_OP_PAIR_DEVICE,
64 MGMT_OP_CANCEL_PAIR_DEVICE,
65 MGMT_OP_UNPAIR_DEVICE,
66 MGMT_OP_USER_CONFIRM_REPLY,
67 MGMT_OP_USER_CONFIRM_NEG_REPLY,
68 MGMT_OP_USER_PASSKEY_REPLY,
69 MGMT_OP_USER_PASSKEY_NEG_REPLY,
70 MGMT_OP_READ_LOCAL_OOB_DATA,
71 MGMT_OP_ADD_REMOTE_OOB_DATA,
72 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
73 MGMT_OP_START_DISCOVERY,
74 MGMT_OP_STOP_DISCOVERY,
75 MGMT_OP_CONFIRM_NAME,
76 MGMT_OP_BLOCK_DEVICE,
77 MGMT_OP_UNBLOCK_DEVICE,
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -070078 MGMT_OP_SET_DEVICE_ID,
Johan Hedberge70bb2e2012-02-13 16:59:33 +020079};
80
81static const u16 mgmt_events[] = {
82 MGMT_EV_CONTROLLER_ERROR,
83 MGMT_EV_INDEX_ADDED,
84 MGMT_EV_INDEX_REMOVED,
85 MGMT_EV_NEW_SETTINGS,
86 MGMT_EV_CLASS_OF_DEV_CHANGED,
87 MGMT_EV_LOCAL_NAME_CHANGED,
88 MGMT_EV_NEW_LINK_KEY,
89 MGMT_EV_NEW_LONG_TERM_KEY,
90 MGMT_EV_DEVICE_CONNECTED,
91 MGMT_EV_DEVICE_DISCONNECTED,
92 MGMT_EV_CONNECT_FAILED,
93 MGMT_EV_PIN_CODE_REQUEST,
94 MGMT_EV_USER_CONFIRM_REQUEST,
95 MGMT_EV_USER_PASSKEY_REQUEST,
96 MGMT_EV_AUTH_FAILED,
97 MGMT_EV_DEVICE_FOUND,
98 MGMT_EV_DISCOVERING,
99 MGMT_EV_DEVICE_BLOCKED,
100 MGMT_EV_DEVICE_UNBLOCKED,
101 MGMT_EV_DEVICE_UNPAIRED,
Johan Hedberg92a25252012-09-06 18:39:26 +0300102 MGMT_EV_PASSKEY_NOTIFY,
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200103};
104
Andre Guedes3fd24152012-02-03 17:48:01 -0300105/*
106 * These LE scan and inquiry parameters were chosen according to LE General
107 * Discovery Procedure specification.
108 */
Andre Guedes3fd24152012-02-03 17:48:01 -0300109#define LE_SCAN_WIN 0x12
110#define LE_SCAN_INT 0x12
Andre Guedesb6c75152013-04-04 20:20:59 -0300111#define LE_SCAN_TIMEOUT_LE_ONLY msecs_to_jiffies(10240)
112#define LE_SCAN_TIMEOUT_BREDR_LE msecs_to_jiffies(5120)
Andre Guedes3fd24152012-02-03 17:48:01 -0300113
Andre Guedese8777522012-02-03 17:48:02 -0300114#define INQUIRY_LEN_BREDR 0x08 /* TGAP(100) */
Andre Guedes5e0452c2012-02-17 20:39:38 -0300115#define INQUIRY_LEN_BREDR_LE 0x04 /* TGAP(100)/2 */
Andre Guedes2519a1f2011-11-07 11:45:24 -0300116
Marcel Holtmann17b02e62012-03-01 14:32:37 -0800117#define CACHE_TIMEOUT msecs_to_jiffies(2 * 1000)
Johan Hedberg7d785252011-12-15 00:47:39 +0200118
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200119#define hdev_is_powered(hdev) (test_bit(HCI_UP, &hdev->flags) && \
120 !test_bit(HCI_AUTO_OFF, &hdev->dev_flags))
121
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200122struct pending_cmd {
123 struct list_head list;
Johan Hedbergfc2f4b12011-11-09 13:58:56 +0200124 u16 opcode;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200125 int index;
Szymon Jancc68fb7f2011-03-22 13:12:19 +0100126 void *param;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200127 struct sock *sk;
Johan Hedberge9a416b2011-02-19 12:05:56 -0300128 void *user_data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200129};
130
Johan Hedbergca69b792011-11-11 18:10:00 +0200131/* HCI to MGMT error code conversion table */
132static u8 mgmt_status_table[] = {
133 MGMT_STATUS_SUCCESS,
134 MGMT_STATUS_UNKNOWN_COMMAND, /* Unknown Command */
135 MGMT_STATUS_NOT_CONNECTED, /* No Connection */
136 MGMT_STATUS_FAILED, /* Hardware Failure */
137 MGMT_STATUS_CONNECT_FAILED, /* Page Timeout */
138 MGMT_STATUS_AUTH_FAILED, /* Authentication Failed */
139 MGMT_STATUS_NOT_PAIRED, /* PIN or Key Missing */
140 MGMT_STATUS_NO_RESOURCES, /* Memory Full */
141 MGMT_STATUS_TIMEOUT, /* Connection Timeout */
142 MGMT_STATUS_NO_RESOURCES, /* Max Number of Connections */
143 MGMT_STATUS_NO_RESOURCES, /* Max Number of SCO Connections */
144 MGMT_STATUS_ALREADY_CONNECTED, /* ACL Connection Exists */
145 MGMT_STATUS_BUSY, /* Command Disallowed */
146 MGMT_STATUS_NO_RESOURCES, /* Rejected Limited Resources */
147 MGMT_STATUS_REJECTED, /* Rejected Security */
148 MGMT_STATUS_REJECTED, /* Rejected Personal */
149 MGMT_STATUS_TIMEOUT, /* Host Timeout */
150 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Feature */
151 MGMT_STATUS_INVALID_PARAMS, /* Invalid Parameters */
152 MGMT_STATUS_DISCONNECTED, /* OE User Ended Connection */
153 MGMT_STATUS_NO_RESOURCES, /* OE Low Resources */
154 MGMT_STATUS_DISCONNECTED, /* OE Power Off */
155 MGMT_STATUS_DISCONNECTED, /* Connection Terminated */
156 MGMT_STATUS_BUSY, /* Repeated Attempts */
157 MGMT_STATUS_REJECTED, /* Pairing Not Allowed */
158 MGMT_STATUS_FAILED, /* Unknown LMP PDU */
159 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Remote Feature */
160 MGMT_STATUS_REJECTED, /* SCO Offset Rejected */
161 MGMT_STATUS_REJECTED, /* SCO Interval Rejected */
162 MGMT_STATUS_REJECTED, /* Air Mode Rejected */
163 MGMT_STATUS_INVALID_PARAMS, /* Invalid LMP Parameters */
164 MGMT_STATUS_FAILED, /* Unspecified Error */
165 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported LMP Parameter Value */
166 MGMT_STATUS_FAILED, /* Role Change Not Allowed */
167 MGMT_STATUS_TIMEOUT, /* LMP Response Timeout */
168 MGMT_STATUS_FAILED, /* LMP Error Transaction Collision */
169 MGMT_STATUS_FAILED, /* LMP PDU Not Allowed */
170 MGMT_STATUS_REJECTED, /* Encryption Mode Not Accepted */
171 MGMT_STATUS_FAILED, /* Unit Link Key Used */
172 MGMT_STATUS_NOT_SUPPORTED, /* QoS Not Supported */
173 MGMT_STATUS_TIMEOUT, /* Instant Passed */
174 MGMT_STATUS_NOT_SUPPORTED, /* Pairing Not Supported */
175 MGMT_STATUS_FAILED, /* Transaction Collision */
176 MGMT_STATUS_INVALID_PARAMS, /* Unacceptable Parameter */
177 MGMT_STATUS_REJECTED, /* QoS Rejected */
178 MGMT_STATUS_NOT_SUPPORTED, /* Classification Not Supported */
179 MGMT_STATUS_REJECTED, /* Insufficient Security */
180 MGMT_STATUS_INVALID_PARAMS, /* Parameter Out Of Range */
181 MGMT_STATUS_BUSY, /* Role Switch Pending */
182 MGMT_STATUS_FAILED, /* Slot Violation */
183 MGMT_STATUS_FAILED, /* Role Switch Failed */
184 MGMT_STATUS_INVALID_PARAMS, /* EIR Too Large */
185 MGMT_STATUS_NOT_SUPPORTED, /* Simple Pairing Not Supported */
186 MGMT_STATUS_BUSY, /* Host Busy Pairing */
187 MGMT_STATUS_REJECTED, /* Rejected, No Suitable Channel */
188 MGMT_STATUS_BUSY, /* Controller Busy */
189 MGMT_STATUS_INVALID_PARAMS, /* Unsuitable Connection Interval */
190 MGMT_STATUS_TIMEOUT, /* Directed Advertising Timeout */
191 MGMT_STATUS_AUTH_FAILED, /* Terminated Due to MIC Failure */
192 MGMT_STATUS_CONNECT_FAILED, /* Connection Establishment Failed */
193 MGMT_STATUS_CONNECT_FAILED, /* MAC Connection Failed */
194};
195
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +0300196bool mgmt_valid_hdev(struct hci_dev *hdev)
197{
198 return hdev->dev_type == HCI_BREDR;
199}
200
Johan Hedbergca69b792011-11-11 18:10:00 +0200201static u8 mgmt_status(u8 hci_status)
202{
203 if (hci_status < ARRAY_SIZE(mgmt_status_table))
204 return mgmt_status_table[hci_status];
205
206 return MGMT_STATUS_FAILED;
207}
208
Szymon Janc4e51eae2011-02-25 19:05:48 +0100209static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200210{
211 struct sk_buff *skb;
212 struct mgmt_hdr *hdr;
213 struct mgmt_ev_cmd_status *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300214 int err;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200215
Szymon Janc34eb5252011-02-28 14:10:08 +0100216 BT_DBG("sock %p, index %u, cmd %u, status %u", sk, index, cmd, status);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200217
Andre Guedes790eff42012-06-07 19:05:46 -0300218 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_KERNEL);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200219 if (!skb)
220 return -ENOMEM;
221
222 hdr = (void *) skb_put(skb, sizeof(*hdr));
223
Syam Sidhardhan612dfce2012-10-29 22:37:36 +0530224 hdr->opcode = __constant_cpu_to_le16(MGMT_EV_CMD_STATUS);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100225 hdr->index = cpu_to_le16(index);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200226 hdr->len = cpu_to_le16(sizeof(*ev));
227
228 ev = (void *) skb_put(skb, sizeof(*ev));
229 ev->status = status;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200230 ev->opcode = cpu_to_le16(cmd);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200231
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300232 err = sock_queue_rcv_skb(sk, skb);
233 if (err < 0)
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200234 kfree_skb(skb);
235
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300236 return err;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200237}
238
Johan Hedbergaee9b2182012-02-18 15:07:59 +0200239static int cmd_complete(struct sock *sk, u16 index, u16 cmd, u8 status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300240 void *rp, size_t rp_len)
Johan Hedberg02d98122010-12-13 21:07:04 +0200241{
242 struct sk_buff *skb;
243 struct mgmt_hdr *hdr;
244 struct mgmt_ev_cmd_complete *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300245 int err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200246
247 BT_DBG("sock %p", sk);
248
Andre Guedes790eff42012-06-07 19:05:46 -0300249 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + rp_len, GFP_KERNEL);
Johan Hedberg02d98122010-12-13 21:07:04 +0200250 if (!skb)
251 return -ENOMEM;
252
253 hdr = (void *) skb_put(skb, sizeof(*hdr));
Johan Hedberga38528f2011-01-22 06:46:43 +0200254
Syam Sidhardhan612dfce2012-10-29 22:37:36 +0530255 hdr->opcode = __constant_cpu_to_le16(MGMT_EV_CMD_COMPLETE);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100256 hdr->index = cpu_to_le16(index);
Johan Hedberga38528f2011-01-22 06:46:43 +0200257 hdr->len = cpu_to_le16(sizeof(*ev) + rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200258
Johan Hedberga38528f2011-01-22 06:46:43 +0200259 ev = (void *) skb_put(skb, sizeof(*ev) + rp_len);
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200260 ev->opcode = cpu_to_le16(cmd);
Johan Hedbergaee9b2182012-02-18 15:07:59 +0200261 ev->status = status;
Szymon Janc8020c162011-02-28 14:09:50 +0100262
263 if (rp)
264 memcpy(ev->data, rp, rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200265
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300266 err = sock_queue_rcv_skb(sk, skb);
267 if (err < 0)
Johan Hedberg02d98122010-12-13 21:07:04 +0200268 kfree_skb(skb);
269
Marcel Holtmanne5f0e152012-02-22 11:59:01 +0100270 return err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200271}
272
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300273static int read_version(struct sock *sk, struct hci_dev *hdev, void *data,
274 u16 data_len)
Johan Hedberga38528f2011-01-22 06:46:43 +0200275{
276 struct mgmt_rp_read_version rp;
277
278 BT_DBG("sock %p", sk);
279
280 rp.version = MGMT_VERSION;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200281 rp.revision = __constant_cpu_to_le16(MGMT_REVISION);
Johan Hedberga38528f2011-01-22 06:46:43 +0200282
Johan Hedbergaee9b2182012-02-18 15:07:59 +0200283 return cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300284 sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200285}
286
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300287static int read_commands(struct sock *sk, struct hci_dev *hdev, void *data,
288 u16 data_len)
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200289{
290 struct mgmt_rp_read_commands *rp;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200291 const u16 num_commands = ARRAY_SIZE(mgmt_commands);
292 const u16 num_events = ARRAY_SIZE(mgmt_events);
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +0200293 __le16 *opcode;
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200294 size_t rp_size;
295 int i, err;
296
297 BT_DBG("sock %p", sk);
298
299 rp_size = sizeof(*rp) + ((num_commands + num_events) * sizeof(u16));
300
301 rp = kmalloc(rp_size, GFP_KERNEL);
302 if (!rp)
303 return -ENOMEM;
304
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200305 rp->num_commands = __constant_cpu_to_le16(num_commands);
306 rp->num_events = __constant_cpu_to_le16(num_events);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200307
308 for (i = 0, opcode = rp->opcodes; i < num_commands; i++, opcode++)
309 put_unaligned_le16(mgmt_commands[i], opcode);
310
311 for (i = 0; i < num_events; i++, opcode++)
312 put_unaligned_le16(mgmt_events[i], opcode);
313
Johan Hedbergaee9b2182012-02-18 15:07:59 +0200314 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_COMMANDS, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300315 rp_size);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200316 kfree(rp);
317
318 return err;
319}
320
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300321static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data,
322 u16 data_len)
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200323{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200324 struct mgmt_rp_read_index_list *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200325 struct hci_dev *d;
Johan Hedberga38528f2011-01-22 06:46:43 +0200326 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200327 u16 count;
Johan Hedberg476e44c2012-10-19 20:10:46 +0300328 int err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200329
330 BT_DBG("sock %p", sk);
331
332 read_lock(&hci_dev_list_lock);
333
334 count = 0;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +0300335 list_for_each_entry(d, &hci_dev_list, list) {
336 if (!mgmt_valid_hdev(d))
337 continue;
338
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200339 count++;
340 }
341
Johan Hedberga38528f2011-01-22 06:46:43 +0200342 rp_len = sizeof(*rp) + (2 * count);
343 rp = kmalloc(rp_len, GFP_ATOMIC);
344 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100345 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200346 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100347 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200348
Johan Hedberg476e44c2012-10-19 20:10:46 +0300349 count = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200350 list_for_each_entry(d, &hci_dev_list, list) {
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200351 if (test_bit(HCI_SETUP, &d->dev_flags))
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200352 continue;
353
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +0300354 if (!mgmt_valid_hdev(d))
355 continue;
356
Johan Hedberg476e44c2012-10-19 20:10:46 +0300357 rp->index[count++] = cpu_to_le16(d->id);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200358 BT_DBG("Added hci%u", d->id);
359 }
360
Johan Hedberg476e44c2012-10-19 20:10:46 +0300361 rp->num_controllers = cpu_to_le16(count);
362 rp_len = sizeof(*rp) + (2 * count);
363
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200364 read_unlock(&hci_dev_list_lock);
365
Johan Hedbergaee9b2182012-02-18 15:07:59 +0200366 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300367 rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200368
Johan Hedberga38528f2011-01-22 06:46:43 +0200369 kfree(rp);
370
371 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200372}
373
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200374static u32 get_supported_settings(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +0200375{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200376 u32 settings = 0;
Johan Hedberg03811012010-12-08 00:21:06 +0200377
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200378 settings |= MGMT_SETTING_POWERED;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200379 settings |= MGMT_SETTING_PAIRABLE;
Johan Hedberg03811012010-12-08 00:21:06 +0200380
Andre Guedes9a1a1992012-07-24 15:03:48 -0300381 if (lmp_ssp_capable(hdev))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200382 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200383
Andre Guedesed3fa312012-07-24 15:03:46 -0300384 if (lmp_bredr_capable(hdev)) {
Johan Hedberg33c525c2012-10-24 21:11:58 +0300385 settings |= MGMT_SETTING_CONNECTABLE;
Johan Hedberg1a47aee2013-03-15 17:07:06 -0500386 if (hdev->hci_ver >= BLUETOOTH_VER_1_2)
387 settings |= MGMT_SETTING_FAST_CONNECTABLE;
Johan Hedberg33c525c2012-10-24 21:11:58 +0300388 settings |= MGMT_SETTING_DISCOVERABLE;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200389 settings |= MGMT_SETTING_BREDR;
390 settings |= MGMT_SETTING_LINK_SECURITY;
391 }
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200392
Marcel Holtmannd7b7e792012-02-20 21:47:49 +0100393 if (enable_hs)
394 settings |= MGMT_SETTING_HS;
395
Andre Guedesc383ddc2012-07-24 15:03:47 -0300396 if (lmp_le_capable(hdev))
Marcel Holtmann9d428202012-05-03 07:12:31 +0200397 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200398
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200399 return settings;
400}
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200401
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200402static u32 get_current_settings(struct hci_dev *hdev)
403{
404 u32 settings = 0;
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200405
Johan Hedbergf1f0eb02012-02-21 17:15:41 +0200406 if (hdev_is_powered(hdev))
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100407 settings |= MGMT_SETTING_POWERED;
408
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200409 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200410 settings |= MGMT_SETTING_CONNECTABLE;
411
Johan Hedberg1a4d3c42013-03-15 17:07:08 -0500412 if (test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags))
413 settings |= MGMT_SETTING_FAST_CONNECTABLE;
414
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200415 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200416 settings |= MGMT_SETTING_DISCOVERABLE;
417
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200418 if (test_bit(HCI_PAIRABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200419 settings |= MGMT_SETTING_PAIRABLE;
420
Andre Guedesed3fa312012-07-24 15:03:46 -0300421 if (lmp_bredr_capable(hdev))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200422 settings |= MGMT_SETTING_BREDR;
423
Johan Hedberg06199cf2012-02-22 16:37:11 +0200424 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200425 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200426
Johan Hedberg47990ea2012-02-22 11:58:37 +0200427 if (test_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200428 settings |= MGMT_SETTING_LINK_SECURITY;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200429
Johan Hedberg84bde9d2012-01-25 14:21:06 +0200430 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200431 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200432
Johan Hedberg6d80dfd2012-02-20 23:50:38 +0200433 if (test_bit(HCI_HS_ENABLED, &hdev->dev_flags))
434 settings |= MGMT_SETTING_HS;
435
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200436 return settings;
Johan Hedbergc542a062011-01-26 13:11:03 +0200437}
438
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300439#define PNP_INFO_SVCLASS_ID 0x1200
440
Johan Hedberg213202e2013-01-27 00:31:33 +0200441static u8 *create_uuid16_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
442{
443 u8 *ptr = data, *uuids_start = NULL;
444 struct bt_uuid *uuid;
445
446 if (len < 4)
447 return ptr;
448
449 list_for_each_entry(uuid, &hdev->uuids, list) {
450 u16 uuid16;
451
452 if (uuid->size != 16)
453 continue;
454
455 uuid16 = get_unaligned_le16(&uuid->uuid[12]);
456 if (uuid16 < 0x1100)
457 continue;
458
459 if (uuid16 == PNP_INFO_SVCLASS_ID)
460 continue;
461
462 if (!uuids_start) {
463 uuids_start = ptr;
464 uuids_start[0] = 1;
465 uuids_start[1] = EIR_UUID16_ALL;
466 ptr += 2;
467 }
468
469 /* Stop if not enough space to put next UUID */
470 if ((ptr - data) + sizeof(u16) > len) {
471 uuids_start[1] = EIR_UUID16_SOME;
472 break;
473 }
474
475 *ptr++ = (uuid16 & 0x00ff);
476 *ptr++ = (uuid16 & 0xff00) >> 8;
477 uuids_start[0] += sizeof(uuid16);
478 }
479
480 return ptr;
481}
482
Johan Hedbergcdf19632013-01-27 00:31:34 +0200483static u8 *create_uuid32_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
484{
485 u8 *ptr = data, *uuids_start = NULL;
486 struct bt_uuid *uuid;
487
488 if (len < 6)
489 return ptr;
490
491 list_for_each_entry(uuid, &hdev->uuids, list) {
492 if (uuid->size != 32)
493 continue;
494
495 if (!uuids_start) {
496 uuids_start = ptr;
497 uuids_start[0] = 1;
498 uuids_start[1] = EIR_UUID32_ALL;
499 ptr += 2;
500 }
501
502 /* Stop if not enough space to put next UUID */
503 if ((ptr - data) + sizeof(u32) > len) {
504 uuids_start[1] = EIR_UUID32_SOME;
505 break;
506 }
507
508 memcpy(ptr, &uuid->uuid[12], sizeof(u32));
509 ptr += sizeof(u32);
510 uuids_start[0] += sizeof(u32);
511 }
512
513 return ptr;
514}
515
Johan Hedbergc00d5752013-01-27 00:31:35 +0200516static u8 *create_uuid128_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
517{
518 u8 *ptr = data, *uuids_start = NULL;
519 struct bt_uuid *uuid;
520
521 if (len < 18)
522 return ptr;
523
524 list_for_each_entry(uuid, &hdev->uuids, list) {
525 if (uuid->size != 128)
526 continue;
527
528 if (!uuids_start) {
529 uuids_start = ptr;
530 uuids_start[0] = 1;
531 uuids_start[1] = EIR_UUID128_ALL;
532 ptr += 2;
533 }
534
535 /* Stop if not enough space to put next UUID */
536 if ((ptr - data) + 16 > len) {
537 uuids_start[1] = EIR_UUID128_SOME;
538 break;
539 }
540
541 memcpy(ptr, uuid->uuid, 16);
542 ptr += 16;
543 uuids_start[0] += 16;
544 }
545
546 return ptr;
547}
548
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300549static void create_eir(struct hci_dev *hdev, u8 *data)
550{
551 u8 *ptr = data;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300552 size_t name_len;
553
554 name_len = strlen(hdev->dev_name);
555
556 if (name_len > 0) {
557 /* EIR Data type */
558 if (name_len > 48) {
559 name_len = 48;
560 ptr[1] = EIR_NAME_SHORT;
561 } else
562 ptr[1] = EIR_NAME_COMPLETE;
563
564 /* EIR Data length */
565 ptr[0] = name_len + 1;
566
567 memcpy(ptr + 2, hdev->dev_name, name_len);
568
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300569 ptr += (name_len + 2);
570 }
571
Johan Hedbergbbaf4442012-11-08 01:22:59 +0100572 if (hdev->inq_tx_power != HCI_TX_POWER_INVALID) {
Marcel Holtmann91c4e9b2012-03-11 19:27:21 -0700573 ptr[0] = 2;
574 ptr[1] = EIR_TX_POWER;
575 ptr[2] = (u8) hdev->inq_tx_power;
576
Marcel Holtmann91c4e9b2012-03-11 19:27:21 -0700577 ptr += 3;
578 }
579
Marcel Holtmann2b9be132012-03-11 19:32:12 -0700580 if (hdev->devid_source > 0) {
581 ptr[0] = 9;
582 ptr[1] = EIR_DEVICE_ID;
583
584 put_unaligned_le16(hdev->devid_source, ptr + 2);
585 put_unaligned_le16(hdev->devid_vendor, ptr + 4);
586 put_unaligned_le16(hdev->devid_product, ptr + 6);
587 put_unaligned_le16(hdev->devid_version, ptr + 8);
588
Marcel Holtmann2b9be132012-03-11 19:32:12 -0700589 ptr += 10;
590 }
591
Johan Hedberg213202e2013-01-27 00:31:33 +0200592 ptr = create_uuid16_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedbergcdf19632013-01-27 00:31:34 +0200593 ptr = create_uuid32_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedbergc00d5752013-01-27 00:31:35 +0200594 ptr = create_uuid128_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300595}
596
Johan Hedberg890ea892013-03-15 17:06:52 -0500597static void update_eir(struct hci_request *req)
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300598{
Johan Hedberg890ea892013-03-15 17:06:52 -0500599 struct hci_dev *hdev = req->hdev;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300600 struct hci_cp_write_eir cp;
601
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200602 if (!hdev_is_powered(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500603 return;
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200604
Johan Hedberg976eb202012-10-24 21:12:01 +0300605 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500606 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300607
Johan Hedberg84bde9d2012-01-25 14:21:06 +0200608 if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -0500609 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300610
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200611 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -0500612 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300613
614 memset(&cp, 0, sizeof(cp));
615
616 create_eir(hdev, cp.data);
617
618 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
Johan Hedberg890ea892013-03-15 17:06:52 -0500619 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300620
621 memcpy(hdev->eir, cp.data, sizeof(cp.data));
622
Johan Hedberg890ea892013-03-15 17:06:52 -0500623 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300624}
625
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200626static u8 get_service_classes(struct hci_dev *hdev)
627{
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300628 struct bt_uuid *uuid;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200629 u8 val = 0;
630
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300631 list_for_each_entry(uuid, &hdev->uuids, list)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200632 val |= uuid->svc_hint;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200633
634 return val;
635}
636
Johan Hedberg890ea892013-03-15 17:06:52 -0500637static void update_class(struct hci_request *req)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200638{
Johan Hedberg890ea892013-03-15 17:06:52 -0500639 struct hci_dev *hdev = req->hdev;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200640 u8 cod[3];
641
642 BT_DBG("%s", hdev->name);
643
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200644 if (!hdev_is_powered(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500645 return;
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200646
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200647 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -0500648 return;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200649
650 cod[0] = hdev->minor_class;
651 cod[1] = hdev->major_class;
652 cod[2] = get_service_classes(hdev);
653
654 if (memcmp(cod, hdev->dev_class, 3) == 0)
Johan Hedberg890ea892013-03-15 17:06:52 -0500655 return;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200656
Johan Hedberg890ea892013-03-15 17:06:52 -0500657 hci_req_add(req, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200658}
659
Johan Hedberg7d785252011-12-15 00:47:39 +0200660static void service_cache_off(struct work_struct *work)
661{
662 struct hci_dev *hdev = container_of(work, struct hci_dev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300663 service_cache.work);
Johan Hedberg890ea892013-03-15 17:06:52 -0500664 struct hci_request req;
Johan Hedberg7d785252011-12-15 00:47:39 +0200665
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200666 if (!test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200667 return;
668
Johan Hedberg890ea892013-03-15 17:06:52 -0500669 hci_req_init(&req, hdev);
670
Johan Hedberg7d785252011-12-15 00:47:39 +0200671 hci_dev_lock(hdev);
672
Johan Hedberg890ea892013-03-15 17:06:52 -0500673 update_eir(&req);
674 update_class(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +0200675
676 hci_dev_unlock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -0500677
678 hci_req_run(&req, NULL);
Johan Hedberg7d785252011-12-15 00:47:39 +0200679}
680
Johan Hedberg6a919082012-02-28 06:17:26 +0200681static void mgmt_init_hdev(struct sock *sk, struct hci_dev *hdev)
Johan Hedberg7d785252011-12-15 00:47:39 +0200682{
Johan Hedberg4f87da82012-03-02 19:55:56 +0200683 if (test_and_set_bit(HCI_MGMT, &hdev->dev_flags))
Johan Hedberg6a919082012-02-28 06:17:26 +0200684 return;
685
Johan Hedberg4f87da82012-03-02 19:55:56 +0200686 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
Johan Hedberg7d785252011-12-15 00:47:39 +0200687
Johan Hedberg4f87da82012-03-02 19:55:56 +0200688 /* Non-mgmt controlled devices get this bit set
689 * implicitly so that pairing works for them, however
690 * for mgmt we require user-space to explicitly enable
691 * it
692 */
693 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedberg7d785252011-12-15 00:47:39 +0200694}
695
Johan Hedberg0f4e68c2012-02-28 17:18:30 +0200696static int read_controller_info(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300697 void *data, u16 data_len)
Johan Hedberg03811012010-12-08 00:21:06 +0200698{
699 struct mgmt_rp_read_info rp;
Johan Hedberg03811012010-12-08 00:21:06 +0200700
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200701 BT_DBG("sock %p %s", sk, hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200702
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300703 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200704
Johan Hedberg03811012010-12-08 00:21:06 +0200705 memset(&rp, 0, sizeof(rp));
706
Johan Hedberg03811012010-12-08 00:21:06 +0200707 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200708
709 rp.version = hdev->hci_ver;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200710 rp.manufacturer = cpu_to_le16(hdev->manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200711
712 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
713 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
714
715 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedberg03811012010-12-08 00:21:06 +0200716
717 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
Johan Hedberg27fcc362012-02-22 21:46:22 +0200718 memcpy(rp.short_name, hdev->short_name, sizeof(hdev->short_name));
Johan Hedberg03811012010-12-08 00:21:06 +0200719
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300720 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200721
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200722 return cmd_complete(sk, hdev->id, MGMT_OP_READ_INFO, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300723 sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +0200724}
725
726static void mgmt_pending_free(struct pending_cmd *cmd)
727{
728 sock_put(cmd->sk);
729 kfree(cmd->param);
730 kfree(cmd);
731}
732
733static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300734 struct hci_dev *hdev, void *data,
735 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200736{
737 struct pending_cmd *cmd;
738
Andre Guedes12b94562012-06-07 19:05:45 -0300739 cmd = kmalloc(sizeof(*cmd), GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +0200740 if (!cmd)
741 return NULL;
742
743 cmd->opcode = opcode;
744 cmd->index = hdev->id;
745
Andre Guedes12b94562012-06-07 19:05:45 -0300746 cmd->param = kmalloc(len, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +0200747 if (!cmd->param) {
748 kfree(cmd);
749 return NULL;
750 }
751
752 if (data)
753 memcpy(cmd->param, data, len);
754
755 cmd->sk = sk;
756 sock_hold(sk);
757
758 list_add(&cmd->list, &hdev->mgmt_pending);
759
760 return cmd;
761}
762
763static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -0300764 void (*cb)(struct pending_cmd *cmd,
765 void *data),
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300766 void *data)
Johan Hedberg03811012010-12-08 00:21:06 +0200767{
Andre Guedesa3d09352013-02-01 11:21:30 -0300768 struct pending_cmd *cmd, *tmp;
Johan Hedberg03811012010-12-08 00:21:06 +0200769
Andre Guedesa3d09352013-02-01 11:21:30 -0300770 list_for_each_entry_safe(cmd, tmp, &hdev->mgmt_pending, list) {
Johan Hedberg03811012010-12-08 00:21:06 +0200771 if (opcode > 0 && cmd->opcode != opcode)
772 continue;
773
774 cb(cmd, data);
775 }
776}
777
778static struct pending_cmd *mgmt_pending_find(u16 opcode, struct hci_dev *hdev)
779{
780 struct pending_cmd *cmd;
781
782 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
783 if (cmd->opcode == opcode)
784 return cmd;
785 }
786
787 return NULL;
788}
789
790static void mgmt_pending_remove(struct pending_cmd *cmd)
791{
792 list_del(&cmd->list);
793 mgmt_pending_free(cmd);
794}
795
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200796static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +0200797{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200798 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +0200799
Johan Hedbergaee9b2182012-02-18 15:07:59 +0200800 return cmd_complete(sk, hdev->id, opcode, 0, &settings,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300801 sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +0200802}
803
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200804static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300805 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200806{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300807 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200808 struct pending_cmd *cmd;
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200809 int err;
Johan Hedberg03811012010-12-08 00:21:06 +0200810
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200811 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200812
Johan Hedberga7e80f22013-01-09 16:05:19 +0200813 if (cp->val != 0x00 && cp->val != 0x01)
814 return cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
815 MGMT_STATUS_INVALID_PARAMS);
816
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300817 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200818
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100819 if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) {
820 cancel_delayed_work(&hdev->power_off);
821
822 if (cp->val) {
Johan Hedberga1d70452013-01-09 15:29:40 +0200823 mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev,
824 data, len);
825 err = mgmt_powered(hdev, 1);
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100826 goto failed;
827 }
828 }
829
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200830 if (!!cp->val == hdev_is_powered(hdev)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200831 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200832 goto failed;
833 }
834
835 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200836 err = cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300837 MGMT_STATUS_BUSY);
Johan Hedberg03811012010-12-08 00:21:06 +0200838 goto failed;
839 }
840
841 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
842 if (!cmd) {
843 err = -ENOMEM;
844 goto failed;
845 }
846
847 if (cp->val)
Johan Hedberg19202572013-01-14 22:33:51 +0200848 queue_work(hdev->req_workqueue, &hdev->power_on);
Johan Hedberg03811012010-12-08 00:21:06 +0200849 else
Johan Hedberg19202572013-01-14 22:33:51 +0200850 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedberg03811012010-12-08 00:21:06 +0200851
852 err = 0;
853
854failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300855 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200856 return err;
857}
858
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300859static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, u16 data_len,
860 struct sock *skip_sk)
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200861{
862 struct sk_buff *skb;
863 struct mgmt_hdr *hdr;
864
Andre Guedes790eff42012-06-07 19:05:46 -0300865 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_KERNEL);
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200866 if (!skb)
867 return -ENOMEM;
868
869 hdr = (void *) skb_put(skb, sizeof(*hdr));
870 hdr->opcode = cpu_to_le16(event);
871 if (hdev)
872 hdr->index = cpu_to_le16(hdev->id);
873 else
Syam Sidhardhan612dfce2012-10-29 22:37:36 +0530874 hdr->index = __constant_cpu_to_le16(MGMT_INDEX_NONE);
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200875 hdr->len = cpu_to_le16(data_len);
876
877 if (data)
878 memcpy(skb_put(skb, data_len), data, data_len);
879
Marcel Holtmann97e0bde2012-02-22 13:49:28 +0100880 /* Time stamp */
881 __net_timestamp(skb);
882
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200883 hci_send_to_control(skb, skip_sk);
884 kfree_skb(skb);
885
886 return 0;
887}
888
889static int new_settings(struct hci_dev *hdev, struct sock *skip)
890{
891 __le32 ev;
892
893 ev = cpu_to_le32(get_current_settings(hdev));
894
895 return mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), skip);
896}
897
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200898static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300899 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200900{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300901 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200902 struct pending_cmd *cmd;
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200903 u16 timeout;
Johan Hedberg03811012010-12-08 00:21:06 +0200904 u8 scan;
905 int err;
906
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200907 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200908
Johan Hedberg33c525c2012-10-24 21:11:58 +0300909 if (!lmp_bredr_capable(hdev))
910 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
911 MGMT_STATUS_NOT_SUPPORTED);
912
Johan Hedberga7e80f22013-01-09 16:05:19 +0200913 if (cp->val != 0x00 && cp->val != 0x01)
914 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
915 MGMT_STATUS_INVALID_PARAMS);
916
Marcel Holtmann1f350c82012-03-12 20:31:08 -0700917 timeout = __le16_to_cpu(cp->timeout);
Marcel Holtmann24c54a92012-02-22 18:06:34 +0100918 if (!cp->val && timeout > 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200919 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300920 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200921
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300922 hci_dev_lock(hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200923
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200924 if (!hdev_is_powered(hdev) && timeout > 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200925 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300926 MGMT_STATUS_NOT_POWERED);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200927 goto failed;
928 }
929
930 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -0300931 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200932 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300933 MGMT_STATUS_BUSY);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200934 goto failed;
935 }
936
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200937 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200938 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300939 MGMT_STATUS_REJECTED);
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200940 goto failed;
941 }
942
943 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200944 bool changed = false;
945
946 if (!!cp->val != test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
947 change_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
948 changed = true;
949 }
950
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200951 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200952 if (err < 0)
953 goto failed;
954
955 if (changed)
956 err = new_settings(hdev, sk);
957
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200958 goto failed;
959 }
960
961 if (!!cp->val == test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
Marcel Holtmann955638e2012-02-22 18:21:00 +0100962 if (hdev->discov_timeout > 0) {
963 cancel_delayed_work(&hdev->discov_off);
964 hdev->discov_timeout = 0;
965 }
966
967 if (cp->val && timeout > 0) {
968 hdev->discov_timeout = timeout;
969 queue_delayed_work(hdev->workqueue, &hdev->discov_off,
970 msecs_to_jiffies(hdev->discov_timeout * 1000));
971 }
972
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200973 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200974 goto failed;
975 }
976
977 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
978 if (!cmd) {
979 err = -ENOMEM;
980 goto failed;
981 }
982
983 scan = SCAN_PAGE;
984
985 if (cp->val)
986 scan |= SCAN_INQUIRY;
987 else
988 cancel_delayed_work(&hdev->discov_off);
989
990 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
991 if (err < 0)
992 mgmt_pending_remove(cmd);
993
Johan Hedberg03811012010-12-08 00:21:06 +0200994 if (cp->val)
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200995 hdev->discov_timeout = timeout;
Johan Hedberg03811012010-12-08 00:21:06 +0200996
997failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300998 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200999 return err;
1000}
1001
Johan Hedberg406d7802013-03-15 17:07:09 -05001002static void write_fast_connectable(struct hci_request *req, bool enable)
1003{
Johan Hedbergbd98b992013-03-15 17:07:13 -05001004 struct hci_dev *hdev = req->hdev;
Johan Hedberg406d7802013-03-15 17:07:09 -05001005 struct hci_cp_write_page_scan_activity acp;
1006 u8 type;
1007
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05001008 if (hdev->hci_ver < BLUETOOTH_VER_1_2)
1009 return;
1010
Johan Hedberg406d7802013-03-15 17:07:09 -05001011 if (enable) {
1012 type = PAGE_SCAN_TYPE_INTERLACED;
1013
1014 /* 160 msec page scan interval */
1015 acp.interval = __constant_cpu_to_le16(0x0100);
1016 } else {
1017 type = PAGE_SCAN_TYPE_STANDARD; /* default */
1018
1019 /* default 1.28 sec page scan */
1020 acp.interval = __constant_cpu_to_le16(0x0800);
1021 }
1022
1023 acp.window = __constant_cpu_to_le16(0x0012);
1024
Johan Hedbergbd98b992013-03-15 17:07:13 -05001025 if (__cpu_to_le16(hdev->page_scan_interval) != acp.interval ||
1026 __cpu_to_le16(hdev->page_scan_window) != acp.window)
1027 hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
1028 sizeof(acp), &acp);
1029
1030 if (hdev->page_scan_type != type)
1031 hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
Johan Hedberg406d7802013-03-15 17:07:09 -05001032}
1033
Johan Hedberg2b76f452013-03-15 17:07:04 -05001034static void set_connectable_complete(struct hci_dev *hdev, u8 status)
1035{
1036 struct pending_cmd *cmd;
1037
1038 BT_DBG("status 0x%02x", status);
1039
1040 hci_dev_lock(hdev);
1041
1042 cmd = mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
1043 if (!cmd)
1044 goto unlock;
1045
1046 send_settings_rsp(cmd->sk, MGMT_OP_SET_CONNECTABLE, hdev);
1047
1048 mgmt_pending_remove(cmd);
1049
1050unlock:
1051 hci_dev_unlock(hdev);
1052}
1053
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001054static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001055 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +02001056{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001057 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +02001058 struct pending_cmd *cmd;
Johan Hedberg2b76f452013-03-15 17:07:04 -05001059 struct hci_request req;
Johan Hedberg03811012010-12-08 00:21:06 +02001060 u8 scan;
1061 int err;
1062
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001063 BT_DBG("request for %s", hdev->name);
Johan Hedberge41d8b42010-12-13 21:07:03 +02001064
Johan Hedberg33c525c2012-10-24 21:11:58 +03001065 if (!lmp_bredr_capable(hdev))
1066 return cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1067 MGMT_STATUS_NOT_SUPPORTED);
1068
Johan Hedberga7e80f22013-01-09 16:05:19 +02001069 if (cp->val != 0x00 && cp->val != 0x01)
1070 return cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1071 MGMT_STATUS_INVALID_PARAMS);
1072
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001073 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001074
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001075 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001076 bool changed = false;
1077
1078 if (!!cp->val != test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
1079 changed = true;
1080
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001081 if (cp->val) {
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001082 set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001083 } else {
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001084 clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1085 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
1086 }
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001087
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001088 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001089 if (err < 0)
1090 goto failed;
1091
1092 if (changed)
1093 err = new_settings(hdev, sk);
1094
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001095 goto failed;
1096 }
1097
1098 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001099 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001100 err = cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001101 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001102 goto failed;
1103 }
1104
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001105 if (!!cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001106 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001107 goto failed;
1108 }
1109
1110 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
1111 if (!cmd) {
1112 err = -ENOMEM;
1113 goto failed;
1114 }
1115
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001116 if (cp->val) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001117 scan = SCAN_PAGE;
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001118 } else {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001119 scan = 0;
1120
Johan Hedbergdf2c6c52012-02-21 19:15:49 +02001121 if (test_bit(HCI_ISCAN, &hdev->flags) &&
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001122 hdev->discov_timeout > 0)
Johan Hedbergdf2c6c52012-02-21 19:15:49 +02001123 cancel_delayed_work(&hdev->discov_off);
1124 }
1125
Johan Hedberg2b76f452013-03-15 17:07:04 -05001126 hci_req_init(&req, hdev);
1127
1128 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1129
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05001130 /* If we're going from non-connectable to connectable or
1131 * vice-versa when fast connectable is enabled ensure that fast
1132 * connectable gets disabled. write_fast_connectable won't do
1133 * anything if the page scan parameters are already what they
1134 * should be.
1135 */
1136 if (cp->val || test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags))
Johan Hedberge36a3762013-03-15 17:07:10 -05001137 write_fast_connectable(&req, false);
1138
Johan Hedberg2b76f452013-03-15 17:07:04 -05001139 err = hci_req_run(&req, set_connectable_complete);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001140 if (err < 0)
1141 mgmt_pending_remove(cmd);
1142
1143failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001144 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001145 return err;
1146}
1147
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001148static int set_pairable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001149 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001150{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001151 struct mgmt_mode *cp = data;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001152 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001153
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001154 BT_DBG("request for %s", hdev->name);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001155
Johan Hedberga7e80f22013-01-09 16:05:19 +02001156 if (cp->val != 0x00 && cp->val != 0x01)
1157 return cmd_status(sk, hdev->id, MGMT_OP_SET_PAIRABLE,
1158 MGMT_STATUS_INVALID_PARAMS);
1159
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001160 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001161
1162 if (cp->val)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001163 set_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001164 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001165 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001166
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001167 err = send_settings_rsp(sk, MGMT_OP_SET_PAIRABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001168 if (err < 0)
1169 goto failed;
1170
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001171 err = new_settings(hdev, sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001172
1173failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001174 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001175 return err;
1176}
Johan Hedberg72a734e2010-12-30 00:38:22 +02001177
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001178static int set_link_security(struct sock *sk, struct hci_dev *hdev, void *data,
1179 u16 len)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001180{
1181 struct mgmt_mode *cp = data;
1182 struct pending_cmd *cmd;
Johan Hedberg816a11d2012-02-26 13:04:52 +02001183 u8 val;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001184 int err;
1185
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001186 BT_DBG("request for %s", hdev->name);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001187
Johan Hedberg33c525c2012-10-24 21:11:58 +03001188 if (!lmp_bredr_capable(hdev))
1189 return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1190 MGMT_STATUS_NOT_SUPPORTED);
1191
Johan Hedberga7e80f22013-01-09 16:05:19 +02001192 if (cp->val != 0x00 && cp->val != 0x01)
1193 return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1194 MGMT_STATUS_INVALID_PARAMS);
1195
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001196 hci_dev_lock(hdev);
1197
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001198 if (!hdev_is_powered(hdev)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001199 bool changed = false;
1200
1201 if (!!cp->val != test_bit(HCI_LINK_SECURITY,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001202 &hdev->dev_flags)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001203 change_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
1204 changed = true;
1205 }
1206
1207 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1208 if (err < 0)
1209 goto failed;
1210
1211 if (changed)
1212 err = new_settings(hdev, sk);
1213
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001214 goto failed;
1215 }
1216
1217 if (mgmt_pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001218 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001219 MGMT_STATUS_BUSY);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001220 goto failed;
1221 }
1222
1223 val = !!cp->val;
1224
1225 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1226 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1227 goto failed;
1228 }
1229
1230 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1231 if (!cmd) {
1232 err = -ENOMEM;
1233 goto failed;
1234 }
1235
1236 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1237 if (err < 0) {
1238 mgmt_pending_remove(cmd);
1239 goto failed;
1240 }
1241
1242failed:
1243 hci_dev_unlock(hdev);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001244 return err;
1245}
1246
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001247static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001248{
1249 struct mgmt_mode *cp = data;
1250 struct pending_cmd *cmd;
Johan Hedberg816a11d2012-02-26 13:04:52 +02001251 u8 val;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001252 int err;
1253
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001254 BT_DBG("request for %s", hdev->name);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001255
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001256 if (!lmp_ssp_capable(hdev))
1257 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1258 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001259
Johan Hedberga7e80f22013-01-09 16:05:19 +02001260 if (cp->val != 0x00 && cp->val != 0x01)
1261 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1262 MGMT_STATUS_INVALID_PARAMS);
1263
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001264 hci_dev_lock(hdev);
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001265
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001266 val = !!cp->val;
1267
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001268 if (!hdev_is_powered(hdev)) {
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001269 bool changed = false;
1270
1271 if (val != test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) {
1272 change_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
1273 changed = true;
1274 }
1275
1276 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1277 if (err < 0)
1278 goto failed;
1279
1280 if (changed)
1281 err = new_settings(hdev, sk);
1282
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001283 goto failed;
1284 }
1285
1286 if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev)) {
Szymon Jancd97dcb62012-03-16 16:02:56 +01001287 err = cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1288 MGMT_STATUS_BUSY);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001289 goto failed;
1290 }
1291
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001292 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) == val) {
1293 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1294 goto failed;
1295 }
1296
1297 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1298 if (!cmd) {
1299 err = -ENOMEM;
1300 goto failed;
1301 }
1302
1303 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, sizeof(val), &val);
1304 if (err < 0) {
1305 mgmt_pending_remove(cmd);
1306 goto failed;
1307 }
1308
1309failed:
1310 hci_dev_unlock(hdev);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001311 return err;
1312}
1313
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001314static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001315{
1316 struct mgmt_mode *cp = data;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001317
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001318 BT_DBG("request for %s", hdev->name);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001319
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001320 if (!enable_hs)
1321 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001322 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001323
Johan Hedberga7e80f22013-01-09 16:05:19 +02001324 if (cp->val != 0x00 && cp->val != 0x01)
1325 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1326 MGMT_STATUS_INVALID_PARAMS);
1327
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001328 if (cp->val)
1329 set_bit(HCI_HS_ENABLED, &hdev->dev_flags);
1330 else
1331 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
1332
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001333 return send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001334}
1335
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001336static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001337{
1338 struct mgmt_mode *cp = data;
1339 struct hci_cp_write_le_host_supported hci_cp;
1340 struct pending_cmd *cmd;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001341 int err;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001342 u8 val, enabled;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001343
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001344 BT_DBG("request for %s", hdev->name);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001345
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001346 if (!lmp_le_capable(hdev))
1347 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1348 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001349
Johan Hedberga7e80f22013-01-09 16:05:19 +02001350 if (cp->val != 0x00 && cp->val != 0x01)
1351 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1352 MGMT_STATUS_INVALID_PARAMS);
1353
Johan Hedbergc73eee92013-04-19 18:35:21 +03001354 /* LE-only devices do not allow toggling LE on/off */
1355 if (!lmp_bredr_capable(hdev))
1356 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1357 MGMT_STATUS_REJECTED);
1358
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001359 hci_dev_lock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001360
1361 val = !!cp->val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001362 enabled = lmp_host_le_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001363
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001364 if (!hdev_is_powered(hdev) || val == enabled) {
Johan Hedberg06199cf2012-02-22 16:37:11 +02001365 bool changed = false;
1366
1367 if (val != test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
1368 change_bit(HCI_LE_ENABLED, &hdev->dev_flags);
1369 changed = true;
1370 }
1371
1372 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1373 if (err < 0)
Johan Hedberg1de028c2012-02-29 19:55:35 -08001374 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001375
1376 if (changed)
1377 err = new_settings(hdev, sk);
1378
Johan Hedberg1de028c2012-02-29 19:55:35 -08001379 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001380 }
1381
1382 if (mgmt_pending_find(MGMT_OP_SET_LE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001383 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001384 MGMT_STATUS_BUSY);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001385 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001386 }
1387
1388 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
1389 if (!cmd) {
1390 err = -ENOMEM;
Johan Hedberg1de028c2012-02-29 19:55:35 -08001391 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001392 }
1393
1394 memset(&hci_cp, 0, sizeof(hci_cp));
1395
1396 if (val) {
1397 hci_cp.le = val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001398 hci_cp.simul = lmp_le_br_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001399 }
1400
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001401 err = hci_send_cmd(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp),
1402 &hci_cp);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05301403 if (err < 0)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001404 mgmt_pending_remove(cmd);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001405
Johan Hedberg1de028c2012-02-29 19:55:35 -08001406unlock:
1407 hci_dev_unlock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001408 return err;
1409}
1410
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001411/* This is a helper function to test for pending mgmt commands that can
1412 * cause CoD or EIR HCI commands. We can only allow one such pending
1413 * mgmt command at a time since otherwise we cannot easily track what
1414 * the current values are, will be, and based on that calculate if a new
1415 * HCI command needs to be sent and if yes with what value.
1416 */
1417static bool pending_eir_or_class(struct hci_dev *hdev)
1418{
1419 struct pending_cmd *cmd;
1420
1421 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
1422 switch (cmd->opcode) {
1423 case MGMT_OP_ADD_UUID:
1424 case MGMT_OP_REMOVE_UUID:
1425 case MGMT_OP_SET_DEV_CLASS:
1426 case MGMT_OP_SET_POWERED:
1427 return true;
1428 }
1429 }
1430
1431 return false;
1432}
1433
Johan Hedberg83be8ec2013-01-27 00:31:29 +02001434static const u8 bluetooth_base_uuid[] = {
1435 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
1436 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1437};
1438
1439static u8 get_uuid_size(const u8 *uuid)
1440{
1441 u32 val;
1442
1443 if (memcmp(uuid, bluetooth_base_uuid, 12))
1444 return 128;
1445
1446 val = get_unaligned_le32(&uuid[12]);
1447 if (val > 0xffff)
1448 return 32;
1449
1450 return 16;
1451}
1452
Johan Hedberg92da6092013-03-15 17:06:55 -05001453static void mgmt_class_complete(struct hci_dev *hdev, u16 mgmt_op, u8 status)
1454{
1455 struct pending_cmd *cmd;
1456
1457 hci_dev_lock(hdev);
1458
1459 cmd = mgmt_pending_find(mgmt_op, hdev);
1460 if (!cmd)
1461 goto unlock;
1462
1463 cmd_complete(cmd->sk, cmd->index, cmd->opcode, mgmt_status(status),
1464 hdev->dev_class, 3);
1465
1466 mgmt_pending_remove(cmd);
1467
1468unlock:
1469 hci_dev_unlock(hdev);
1470}
1471
1472static void add_uuid_complete(struct hci_dev *hdev, u8 status)
1473{
1474 BT_DBG("status 0x%02x", status);
1475
1476 mgmt_class_complete(hdev, MGMT_OP_ADD_UUID, status);
1477}
1478
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001479static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001480{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001481 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001482 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05001483 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001484 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001485 int err;
1486
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001487 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001488
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001489 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001490
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001491 if (pending_eir_or_class(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001492 err = cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001493 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001494 goto failed;
1495 }
1496
Andre Guedes92c4c202012-06-07 19:05:44 -03001497 uuid = kmalloc(sizeof(*uuid), GFP_KERNEL);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001498 if (!uuid) {
1499 err = -ENOMEM;
1500 goto failed;
1501 }
1502
1503 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001504 uuid->svc_hint = cp->svc_hint;
Johan Hedberg83be8ec2013-01-27 00:31:29 +02001505 uuid->size = get_uuid_size(cp->uuid);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001506
Johan Hedbergde66aa62013-01-27 00:31:27 +02001507 list_add_tail(&uuid->list, &hdev->uuids);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001508
Johan Hedberg890ea892013-03-15 17:06:52 -05001509 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001510
Johan Hedberg890ea892013-03-15 17:06:52 -05001511 update_class(&req);
1512 update_eir(&req);
1513
Johan Hedberg92da6092013-03-15 17:06:55 -05001514 err = hci_req_run(&req, add_uuid_complete);
1515 if (err < 0) {
1516 if (err != -ENODATA)
1517 goto failed;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001518
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001519 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001520 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001521 goto failed;
1522 }
1523
1524 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05001525 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02001526 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05001527 goto failed;
1528 }
1529
1530 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001531
1532failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001533 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001534 return err;
1535}
1536
Johan Hedberg24b78d02012-02-23 23:24:30 +02001537static bool enable_service_cache(struct hci_dev *hdev)
1538{
1539 if (!hdev_is_powered(hdev))
1540 return false;
1541
1542 if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg46818ed2013-01-14 22:33:52 +02001543 queue_delayed_work(hdev->workqueue, &hdev->service_cache,
1544 CACHE_TIMEOUT);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001545 return true;
1546 }
1547
1548 return false;
1549}
1550
Johan Hedberg92da6092013-03-15 17:06:55 -05001551static void remove_uuid_complete(struct hci_dev *hdev, u8 status)
1552{
1553 BT_DBG("status 0x%02x", status);
1554
1555 mgmt_class_complete(hdev, MGMT_OP_REMOVE_UUID, status);
1556}
1557
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001558static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001559 u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001560{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001561 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001562 struct pending_cmd *cmd;
Johan Hedberg056341c2013-01-27 00:31:30 +02001563 struct bt_uuid *match, *tmp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001564 u8 bt_uuid_any[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
Johan Hedberg890ea892013-03-15 17:06:52 -05001565 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001566 int err, found;
1567
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001568 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001569
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001570 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001571
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001572 if (pending_eir_or_class(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001573 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001574 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001575 goto unlock;
1576 }
1577
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001578 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
1579 err = hci_uuids_clear(hdev);
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001580
Johan Hedberg24b78d02012-02-23 23:24:30 +02001581 if (enable_service_cache(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001582 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001583 0, hdev->dev_class, 3);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001584 goto unlock;
1585 }
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001586
Johan Hedberg9246a862012-02-23 21:33:16 +02001587 goto update_class;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001588 }
1589
1590 found = 0;
1591
Johan Hedberg056341c2013-01-27 00:31:30 +02001592 list_for_each_entry_safe(match, tmp, &hdev->uuids, list) {
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001593 if (memcmp(match->uuid, cp->uuid, 16) != 0)
1594 continue;
1595
1596 list_del(&match->list);
Johan Hedberg482049f2012-11-08 10:25:26 +01001597 kfree(match);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001598 found++;
1599 }
1600
1601 if (found == 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001602 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001603 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001604 goto unlock;
1605 }
1606
Johan Hedberg9246a862012-02-23 21:33:16 +02001607update_class:
Johan Hedberg890ea892013-03-15 17:06:52 -05001608 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001609
Johan Hedberg890ea892013-03-15 17:06:52 -05001610 update_class(&req);
1611 update_eir(&req);
1612
Johan Hedberg92da6092013-03-15 17:06:55 -05001613 err = hci_req_run(&req, remove_uuid_complete);
1614 if (err < 0) {
1615 if (err != -ENODATA)
1616 goto unlock;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001617
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001618 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001619 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001620 goto unlock;
1621 }
1622
1623 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05001624 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02001625 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05001626 goto unlock;
1627 }
1628
1629 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001630
1631unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001632 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001633 return err;
1634}
1635
Johan Hedberg92da6092013-03-15 17:06:55 -05001636static void set_class_complete(struct hci_dev *hdev, u8 status)
1637{
1638 BT_DBG("status 0x%02x", status);
1639
1640 mgmt_class_complete(hdev, MGMT_OP_SET_DEV_CLASS, status);
1641}
1642
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001643static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001644 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001645{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001646 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001647 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05001648 struct hci_request req;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001649 int err;
1650
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001651 BT_DBG("request for %s", hdev->name);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001652
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001653 if (!lmp_bredr_capable(hdev))
1654 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
1655 MGMT_STATUS_NOT_SUPPORTED);
1656
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001657 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001658
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001659 if (pending_eir_or_class(hdev)) {
1660 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
1661 MGMT_STATUS_BUSY);
1662 goto unlock;
1663 }
1664
1665 if ((cp->minor & 0x03) != 0 || (cp->major & 0xe0) != 0) {
1666 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
1667 MGMT_STATUS_INVALID_PARAMS);
1668 goto unlock;
1669 }
1670
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001671 hdev->major_class = cp->major;
1672 hdev->minor_class = cp->minor;
1673
Johan Hedberg932f5ff2012-02-22 22:11:32 +02001674 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001675 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001676 hdev->dev_class, 3);
Johan Hedberg932f5ff2012-02-22 22:11:32 +02001677 goto unlock;
1678 }
1679
Johan Hedberg890ea892013-03-15 17:06:52 -05001680 hci_req_init(&req, hdev);
1681
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001682 if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02001683 hci_dev_unlock(hdev);
1684 cancel_delayed_work_sync(&hdev->service_cache);
1685 hci_dev_lock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -05001686 update_eir(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +02001687 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02001688
Johan Hedberg890ea892013-03-15 17:06:52 -05001689 update_class(&req);
1690
Johan Hedberg92da6092013-03-15 17:06:55 -05001691 err = hci_req_run(&req, set_class_complete);
1692 if (err < 0) {
1693 if (err != -ENODATA)
1694 goto unlock;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001695
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001696 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001697 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001698 goto unlock;
1699 }
1700
1701 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05001702 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02001703 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05001704 goto unlock;
1705 }
1706
1707 err = 0;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001708
Johan Hedbergb5235a62012-02-21 14:32:24 +02001709unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001710 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001711 return err;
1712}
1713
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001714static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001715 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001716{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001717 struct mgmt_cp_load_link_keys *cp = data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001718 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001719 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001720
Marcel Holtmann1f350c82012-03-12 20:31:08 -07001721 key_count = __le16_to_cpu(cp->key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001722
Johan Hedberg86742e12011-11-07 23:13:38 +02001723 expected_len = sizeof(*cp) + key_count *
1724 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001725 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001726 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001727 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001728 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001729 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001730 }
1731
Johan Hedberg4ae14302013-01-20 14:27:13 +02001732 if (cp->debug_keys != 0x00 && cp->debug_keys != 0x01)
1733 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
1734 MGMT_STATUS_INVALID_PARAMS);
1735
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001736 BT_DBG("%s debug_keys %u key_count %u", hdev->name, cp->debug_keys,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001737 key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001738
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001739 for (i = 0; i < key_count; i++) {
1740 struct mgmt_link_key_info *key = &cp->keys[i];
1741
1742 if (key->addr.type != BDADDR_BREDR)
1743 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
1744 MGMT_STATUS_INVALID_PARAMS);
1745 }
1746
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001747 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001748
1749 hci_link_keys_clear(hdev);
1750
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001751 set_bit(HCI_LINK_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001752
1753 if (cp->debug_keys)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001754 set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001755 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001756 clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001757
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001758 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001759 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001760
Johan Hedbergd753fdc2012-02-17 14:06:34 +02001761 hci_add_link_key(hdev, NULL, 0, &key->addr.bdaddr, key->val,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001762 key->type, key->pin_len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001763 }
1764
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001765 cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02001766
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001767 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001768
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001769 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001770}
1771
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001772static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001773 u8 addr_type, struct sock *skip_sk)
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001774{
1775 struct mgmt_ev_device_unpaired ev;
1776
1777 bacpy(&ev.addr.bdaddr, bdaddr);
1778 ev.addr.type = addr_type;
1779
1780 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001781 skip_sk);
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001782}
1783
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001784static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001785 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001786{
Johan Hedberg124f6e32012-02-09 13:50:12 +02001787 struct mgmt_cp_unpair_device *cp = data;
1788 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001789 struct hci_cp_disconnect dc;
1790 struct pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001791 struct hci_conn *conn;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001792 int err;
1793
Johan Hedberga8a1d192011-11-10 15:54:38 +02001794 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02001795 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1796 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001797
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001798 if (!bdaddr_type_is_valid(cp->addr.type))
1799 return cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
1800 MGMT_STATUS_INVALID_PARAMS,
1801 &rp, sizeof(rp));
1802
Johan Hedberg118da702013-01-20 14:27:20 +02001803 if (cp->disconnect != 0x00 && cp->disconnect != 0x01)
1804 return cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
1805 MGMT_STATUS_INVALID_PARAMS,
1806 &rp, sizeof(rp));
1807
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001808 hci_dev_lock(hdev);
1809
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001810 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001811 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001812 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001813 goto unlock;
1814 }
1815
Andre Guedes591f47f2012-04-24 21:02:49 -03001816 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg124f6e32012-02-09 13:50:12 +02001817 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
1818 else
1819 err = hci_remove_ltk(hdev, &cp->addr.bdaddr);
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03001820
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001821 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001822 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001823 MGMT_STATUS_NOT_PAIRED, &rp, sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001824 goto unlock;
1825 }
1826
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001827 if (cp->disconnect) {
Andre Guedes591f47f2012-04-24 21:02:49 -03001828 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001829 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001830 &cp->addr.bdaddr);
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001831 else
1832 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001833 &cp->addr.bdaddr);
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001834 } else {
1835 conn = NULL;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001836 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001837
Johan Hedberga8a1d192011-11-10 15:54:38 +02001838 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001839 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001840 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001841 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001842 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001843 }
1844
Johan Hedberg124f6e32012-02-09 13:50:12 +02001845 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001846 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02001847 if (!cmd) {
1848 err = -ENOMEM;
1849 goto unlock;
1850 }
1851
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02001852 dc.handle = cpu_to_le16(conn->handle);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001853 dc.reason = 0x13; /* Remote User Terminated Connection */
1854 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1855 if (err < 0)
1856 mgmt_pending_remove(cmd);
1857
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001858unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001859 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001860 return err;
1861}
1862
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001863static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001864 u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02001865{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001866 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg06a63b12013-01-20 14:27:21 +02001867 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001868 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03001869 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001870 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001871 int err;
1872
1873 BT_DBG("");
1874
Johan Hedberg06a63b12013-01-20 14:27:21 +02001875 memset(&rp, 0, sizeof(rp));
1876 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1877 rp.addr.type = cp->addr.type;
1878
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001879 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg06a63b12013-01-20 14:27:21 +02001880 return cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
1881 MGMT_STATUS_INVALID_PARAMS,
1882 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001883
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001884 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001885
1886 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02001887 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
1888 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02001889 goto failed;
1890 }
1891
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001892 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02001893 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
1894 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02001895 goto failed;
1896 }
1897
Andre Guedes591f47f2012-04-24 21:02:49 -03001898 if (cp->addr.type == BDADDR_BREDR)
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03001899 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
1900 &cp->addr.bdaddr);
Johan Hedberg88c3df12012-02-09 14:27:38 +02001901 else
1902 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03001903
Vishal Agarwalf9607272012-06-13 05:32:43 +05301904 if (!conn || conn->state == BT_OPEN || conn->state == BT_CLOSED) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02001905 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
1906 MGMT_STATUS_NOT_CONNECTED, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02001907 goto failed;
1908 }
1909
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001910 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001911 if (!cmd) {
1912 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001913 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001914 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001915
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02001916 dc.handle = cpu_to_le16(conn->handle);
Andre Guedes3701f942012-06-11 18:41:12 -03001917 dc.reason = HCI_ERROR_REMOTE_USER_TERM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001918
1919 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1920 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001921 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001922
1923failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001924 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001925 return err;
1926}
1927
Andre Guedes57c14772012-04-24 21:02:50 -03001928static u8 link_to_bdaddr(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02001929{
1930 switch (link_type) {
1931 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02001932 switch (addr_type) {
1933 case ADDR_LE_DEV_PUBLIC:
Andre Guedes591f47f2012-04-24 21:02:49 -03001934 return BDADDR_LE_PUBLIC;
Andre Guedes0ed09142012-04-03 08:46:54 -03001935
Johan Hedberg48264f02011-11-09 13:58:58 +02001936 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03001937 /* Fallback to LE Random address type */
Andre Guedes591f47f2012-04-24 21:02:49 -03001938 return BDADDR_LE_RANDOM;
Johan Hedberg48264f02011-11-09 13:58:58 +02001939 }
Andre Guedes0ed09142012-04-03 08:46:54 -03001940
Johan Hedberg4c659c32011-11-07 23:13:39 +02001941 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03001942 /* Fallback to BR/EDR type */
Andre Guedes591f47f2012-04-24 21:02:49 -03001943 return BDADDR_BREDR;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001944 }
1945}
1946
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001947static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data,
1948 u16 data_len)
Johan Hedberg2784eb42011-01-21 13:56:35 +02001949{
Johan Hedberg2784eb42011-01-21 13:56:35 +02001950 struct mgmt_rp_get_connections *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001951 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02001952 size_t rp_len;
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001953 int err;
1954 u16 i;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001955
1956 BT_DBG("");
1957
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001958 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001959
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001960 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001961 err = cmd_status(sk, hdev->id, MGMT_OP_GET_CONNECTIONS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001962 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001963 goto unlock;
1964 }
1965
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001966 i = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02001967 list_for_each_entry(c, &hdev->conn_hash.list, list) {
1968 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001969 i++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001970 }
1971
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001972 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Andre Guedes92c4c202012-06-07 19:05:44 -03001973 rp = kmalloc(rp_len, GFP_KERNEL);
Johan Hedberga38528f2011-01-22 06:46:43 +02001974 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02001975 err = -ENOMEM;
1976 goto unlock;
1977 }
1978
Johan Hedberg2784eb42011-01-21 13:56:35 +02001979 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001980 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02001981 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
1982 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001983 bacpy(&rp->addr[i].bdaddr, &c->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03001984 rp->addr[i].type = link_to_bdaddr(c->type, c->dst_type);
Andre Guedes0ed09142012-04-03 08:46:54 -03001985 if (c->type == SCO_LINK || c->type == ESCO_LINK)
Johan Hedberg4c659c32011-11-07 23:13:39 +02001986 continue;
1987 i++;
1988 }
1989
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02001990 rp->conn_count = cpu_to_le16(i);
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001991
Johan Hedberg4c659c32011-11-07 23:13:39 +02001992 /* Recalculate length in case of filtered SCO connections, etc */
1993 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02001994
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001995 err = cmd_complete(sk, hdev->id, MGMT_OP_GET_CONNECTIONS, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001996 rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001997
Johan Hedberga38528f2011-01-22 06:46:43 +02001998 kfree(rp);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001999
2000unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002001 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002002 return err;
2003}
2004
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002005static int send_pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002006 struct mgmt_cp_pin_code_neg_reply *cp)
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002007{
2008 struct pending_cmd *cmd;
2009 int err;
2010
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002011 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002012 sizeof(*cp));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002013 if (!cmd)
2014 return -ENOMEM;
2015
Johan Hedbergd8457692012-02-17 14:24:57 +02002016 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002017 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002018 if (err < 0)
2019 mgmt_pending_remove(cmd);
2020
2021 return err;
2022}
2023
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002024static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002025 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002026{
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002027 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002028 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002029 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03002030 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002031 int err;
2032
2033 BT_DBG("");
2034
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002035 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002036
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002037 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002038 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002039 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002040 goto failed;
2041 }
2042
Johan Hedbergd8457692012-02-17 14:24:57 +02002043 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002044 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002045 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002046 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002047 goto failed;
2048 }
2049
2050 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02002051 struct mgmt_cp_pin_code_neg_reply ncp;
2052
2053 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002054
2055 BT_ERR("PIN code is not 16 bytes long");
2056
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002057 err = send_pin_code_neg_reply(sk, hdev, &ncp);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002058 if (err >= 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002059 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002060 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002061
2062 goto failed;
2063 }
2064
Gustavo F. Padovan00abfe42012-03-01 00:37:10 -03002065 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002066 if (!cmd) {
2067 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002068 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002069 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02002070
Johan Hedbergd8457692012-02-17 14:24:57 +02002071 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002072 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02002073 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002074
2075 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
2076 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002077 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002078
2079failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002080 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002081 return err;
2082}
2083
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002084static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,
2085 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002086{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002087 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002088
2089 BT_DBG("");
2090
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002091 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002092
2093 hdev->io_capability = cp->io_capability;
2094
2095 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002096 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002097
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002098 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002099
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002100 return cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, 0, NULL,
2101 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002102}
2103
Gustavo Padovan6039aa732012-05-23 04:04:18 -03002104static struct pending_cmd *find_pairing(struct hci_conn *conn)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002105{
2106 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002107 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002108
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002109 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03002110 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
2111 continue;
2112
Johan Hedberge9a416b2011-02-19 12:05:56 -03002113 if (cmd->user_data != conn)
2114 continue;
2115
2116 return cmd;
2117 }
2118
2119 return NULL;
2120}
2121
2122static void pairing_complete(struct pending_cmd *cmd, u8 status)
2123{
2124 struct mgmt_rp_pair_device rp;
2125 struct hci_conn *conn = cmd->user_data;
2126
Johan Hedbergba4e5642011-11-11 00:07:34 +02002127 bacpy(&rp.addr.bdaddr, &conn->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002128 rp.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002129
Johan Hedbergaee9b2182012-02-18 15:07:59 +02002130 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002131 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002132
2133 /* So we don't get further callbacks for this connection */
2134 conn->connect_cfm_cb = NULL;
2135 conn->security_cfm_cb = NULL;
2136 conn->disconn_cfm_cb = NULL;
2137
David Herrmann76a68ba2013-04-06 20:28:37 +02002138 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002139
Johan Hedberga664b5b2011-02-19 12:06:02 -03002140 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002141}
2142
2143static void pairing_complete_cb(struct hci_conn *conn, u8 status)
2144{
2145 struct pending_cmd *cmd;
2146
2147 BT_DBG("status %u", status);
2148
Johan Hedberg56e5cb82011-11-08 20:40:16 +02002149 cmd = find_pairing(conn);
2150 if (!cmd)
2151 BT_DBG("Unable to find a pending command");
2152 else
Johan Hedberge2113262012-02-18 15:20:03 +02002153 pairing_complete(cmd, mgmt_status(status));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002154}
2155
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302156static void le_connect_complete_cb(struct hci_conn *conn, u8 status)
2157{
2158 struct pending_cmd *cmd;
2159
2160 BT_DBG("status %u", status);
2161
2162 if (!status)
2163 return;
2164
2165 cmd = find_pairing(conn);
2166 if (!cmd)
2167 BT_DBG("Unable to find a pending command");
2168 else
2169 pairing_complete(cmd, mgmt_status(status));
2170}
2171
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002172static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002173 u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002174{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002175 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02002176 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002177 struct pending_cmd *cmd;
2178 u8 sec_level, auth_type;
2179 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002180 int err;
2181
2182 BT_DBG("");
2183
Szymon Jancf950a30e2013-01-18 12:48:07 +01002184 memset(&rp, 0, sizeof(rp));
2185 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2186 rp.addr.type = cp->addr.type;
2187
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002188 if (!bdaddr_type_is_valid(cp->addr.type))
2189 return cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2190 MGMT_STATUS_INVALID_PARAMS,
2191 &rp, sizeof(rp));
2192
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002193 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002194
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002195 if (!hdev_is_powered(hdev)) {
Szymon Jancf950a30e2013-01-18 12:48:07 +01002196 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2197 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002198 goto unlock;
2199 }
2200
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002201 sec_level = BT_SECURITY_MEDIUM;
2202 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002203 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002204 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03002205 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002206
Andre Guedes591f47f2012-04-24 21:02:49 -03002207 if (cp->addr.type == BDADDR_BREDR)
Andre Guedesb12f62c2012-04-24 21:02:54 -03002208 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr,
2209 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002210 else
Andre Guedesb12f62c2012-04-24 21:02:54 -03002211 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr,
2212 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002213
Ville Tervo30e76272011-02-22 16:10:53 -03002214 if (IS_ERR(conn)) {
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002215 int status;
2216
2217 if (PTR_ERR(conn) == -EBUSY)
2218 status = MGMT_STATUS_BUSY;
2219 else
2220 status = MGMT_STATUS_CONNECT_FAILED;
2221
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002222 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002223 status, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002224 sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002225 goto unlock;
2226 }
2227
2228 if (conn->connect_cfm_cb) {
David Herrmann76a68ba2013-04-06 20:28:37 +02002229 hci_conn_drop(conn);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002230 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002231 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002232 goto unlock;
2233 }
2234
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002235 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002236 if (!cmd) {
2237 err = -ENOMEM;
David Herrmann76a68ba2013-04-06 20:28:37 +02002238 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002239 goto unlock;
2240 }
2241
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002242 /* For LE, just connecting isn't a proof that the pairing finished */
Andre Guedes591f47f2012-04-24 21:02:49 -03002243 if (cp->addr.type == BDADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002244 conn->connect_cfm_cb = pairing_complete_cb;
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302245 else
2246 conn->connect_cfm_cb = le_connect_complete_cb;
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002247
Johan Hedberge9a416b2011-02-19 12:05:56 -03002248 conn->security_cfm_cb = pairing_complete_cb;
2249 conn->disconn_cfm_cb = pairing_complete_cb;
2250 conn->io_capability = cp->io_cap;
2251 cmd->user_data = conn;
2252
2253 if (conn->state == BT_CONNECTED &&
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002254 hci_conn_security(conn, sec_level, auth_type))
Johan Hedberge9a416b2011-02-19 12:05:56 -03002255 pairing_complete(cmd, 0);
2256
2257 err = 0;
2258
2259unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002260 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002261 return err;
2262}
2263
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002264static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
2265 u16 len)
Johan Hedberg28424702012-02-02 04:02:29 +02002266{
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002267 struct mgmt_addr_info *addr = data;
Johan Hedberg28424702012-02-02 04:02:29 +02002268 struct pending_cmd *cmd;
2269 struct hci_conn *conn;
2270 int err;
2271
2272 BT_DBG("");
2273
Johan Hedberg28424702012-02-02 04:02:29 +02002274 hci_dev_lock(hdev);
2275
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002276 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002277 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002278 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002279 goto unlock;
2280 }
2281
Johan Hedberg28424702012-02-02 04:02:29 +02002282 cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
2283 if (!cmd) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002284 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002285 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002286 goto unlock;
2287 }
2288
2289 conn = cmd->user_data;
2290
2291 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002292 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002293 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002294 goto unlock;
2295 }
2296
2297 pairing_complete(cmd, MGMT_STATUS_CANCELLED);
2298
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002299 err = cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002300 addr, sizeof(*addr));
Johan Hedberg28424702012-02-02 04:02:29 +02002301unlock:
2302 hci_dev_unlock(hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02002303 return err;
2304}
2305
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002306static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
Johan Hedberg1707c602013-03-15 17:07:15 -05002307 struct mgmt_addr_info *addr, u16 mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002308 u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03002309{
Johan Hedberga5c29682011-02-19 12:05:57 -03002310 struct pending_cmd *cmd;
Brian Gix0df4c182011-11-16 13:53:13 -08002311 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03002312 int err;
2313
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002314 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02002315
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002316 if (!hdev_is_powered(hdev)) {
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002317 err = cmd_complete(sk, hdev->id, mgmt_op,
2318 MGMT_STATUS_NOT_POWERED, addr,
2319 sizeof(*addr));
Brian Gix0df4c182011-11-16 13:53:13 -08002320 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002321 }
2322
Johan Hedberg1707c602013-03-15 17:07:15 -05002323 if (addr->type == BDADDR_BREDR)
2324 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &addr->bdaddr);
Johan Hedberg272d90d2012-02-09 15:26:12 +02002325 else
Johan Hedberg1707c602013-03-15 17:07:15 -05002326 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &addr->bdaddr);
Brian Gix47c15e22011-11-16 13:53:14 -08002327
Johan Hedberg272d90d2012-02-09 15:26:12 +02002328 if (!conn) {
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002329 err = cmd_complete(sk, hdev->id, mgmt_op,
2330 MGMT_STATUS_NOT_CONNECTED, addr,
2331 sizeof(*addr));
Johan Hedberg272d90d2012-02-09 15:26:12 +02002332 goto done;
2333 }
2334
Johan Hedberg1707c602013-03-15 17:07:15 -05002335 if (addr->type == BDADDR_LE_PUBLIC || addr->type == BDADDR_LE_RANDOM) {
Brian Gix47c15e22011-11-16 13:53:14 -08002336 /* Continue with pairing via SMP */
Brian Gix5fe57d92011-12-21 16:12:13 -08002337 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix47c15e22011-11-16 13:53:14 -08002338
Brian Gix5fe57d92011-12-21 16:12:13 -08002339 if (!err)
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002340 err = cmd_complete(sk, hdev->id, mgmt_op,
2341 MGMT_STATUS_SUCCESS, addr,
2342 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08002343 else
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002344 err = cmd_complete(sk, hdev->id, mgmt_op,
2345 MGMT_STATUS_FAILED, addr,
2346 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08002347
Brian Gix47c15e22011-11-16 13:53:14 -08002348 goto done;
2349 }
2350
Johan Hedberg1707c602013-03-15 17:07:15 -05002351 cmd = mgmt_pending_add(sk, mgmt_op, hdev, addr, sizeof(*addr));
Johan Hedberga5c29682011-02-19 12:05:57 -03002352 if (!cmd) {
2353 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08002354 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002355 }
2356
Brian Gix0df4c182011-11-16 13:53:13 -08002357 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08002358 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
2359 struct hci_cp_user_passkey_reply cp;
2360
Johan Hedberg1707c602013-03-15 17:07:15 -05002361 bacpy(&cp.bdaddr, &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002362 cp.passkey = passkey;
2363 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
2364 } else
Johan Hedberg1707c602013-03-15 17:07:15 -05002365 err = hci_send_cmd(hdev, hci_op, sizeof(addr->bdaddr),
2366 &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002367
Johan Hedberga664b5b2011-02-19 12:06:02 -03002368 if (err < 0)
2369 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002370
Brian Gix0df4c182011-11-16 13:53:13 -08002371done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002372 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002373 return err;
2374}
2375
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302376static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
2377 void *data, u16 len)
2378{
2379 struct mgmt_cp_pin_code_neg_reply *cp = data;
2380
2381 BT_DBG("");
2382
Johan Hedberg1707c602013-03-15 17:07:15 -05002383 return user_pairing_resp(sk, hdev, &cp->addr,
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302384 MGMT_OP_PIN_CODE_NEG_REPLY,
2385 HCI_OP_PIN_CODE_NEG_REPLY, 0);
2386}
2387
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002388static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2389 u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002390{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002391 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002392
2393 BT_DBG("");
2394
2395 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002396 return cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002397 MGMT_STATUS_INVALID_PARAMS);
Brian Gix0df4c182011-11-16 13:53:13 -08002398
Johan Hedberg1707c602013-03-15 17:07:15 -05002399 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002400 MGMT_OP_USER_CONFIRM_REPLY,
2401 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002402}
2403
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002404static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002405 void *data, u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002406{
Johan Hedbergc9c26592011-12-15 00:47:41 +02002407 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002408
2409 BT_DBG("");
2410
Johan Hedberg1707c602013-03-15 17:07:15 -05002411 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002412 MGMT_OP_USER_CONFIRM_NEG_REPLY,
2413 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002414}
2415
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002416static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2417 u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002418{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002419 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002420
2421 BT_DBG("");
2422
Johan Hedberg1707c602013-03-15 17:07:15 -05002423 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002424 MGMT_OP_USER_PASSKEY_REPLY,
2425 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08002426}
2427
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002428static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002429 void *data, u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002430{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002431 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002432
2433 BT_DBG("");
2434
Johan Hedberg1707c602013-03-15 17:07:15 -05002435 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002436 MGMT_OP_USER_PASSKEY_NEG_REPLY,
2437 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08002438}
2439
Johan Hedberg13928972013-03-15 17:07:00 -05002440static void update_name(struct hci_request *req)
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002441{
Johan Hedberg13928972013-03-15 17:07:00 -05002442 struct hci_dev *hdev = req->hdev;
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002443 struct hci_cp_write_local_name cp;
2444
Johan Hedberg13928972013-03-15 17:07:00 -05002445 memcpy(cp.name, hdev->dev_name, sizeof(cp.name));
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002446
Johan Hedberg890ea892013-03-15 17:06:52 -05002447 hci_req_add(req, HCI_OP_WRITE_LOCAL_NAME, sizeof(cp), &cp);
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002448}
2449
Johan Hedberg13928972013-03-15 17:07:00 -05002450static void set_name_complete(struct hci_dev *hdev, u8 status)
2451{
2452 struct mgmt_cp_set_local_name *cp;
2453 struct pending_cmd *cmd;
2454
2455 BT_DBG("status 0x%02x", status);
2456
2457 hci_dev_lock(hdev);
2458
2459 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
2460 if (!cmd)
2461 goto unlock;
2462
2463 cp = cmd->param;
2464
2465 if (status)
2466 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
2467 mgmt_status(status));
2468 else
2469 cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
2470 cp, sizeof(*cp));
2471
2472 mgmt_pending_remove(cmd);
2473
2474unlock:
2475 hci_dev_unlock(hdev);
2476}
2477
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002478static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002479 u16 len)
Johan Hedbergb312b1612011-03-16 14:29:37 +02002480{
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002481 struct mgmt_cp_set_local_name *cp = data;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002482 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002483 struct hci_request req;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002484 int err;
2485
2486 BT_DBG("");
2487
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002488 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002489
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05002490 /* If the old values are the same as the new ones just return a
2491 * direct command complete event.
2492 */
2493 if (!memcmp(hdev->dev_name, cp->name, sizeof(hdev->dev_name)) &&
2494 !memcmp(hdev->short_name, cp->short_name,
2495 sizeof(hdev->short_name))) {
2496 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
2497 data, len);
2498 goto failed;
2499 }
2500
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002501 memcpy(hdev->short_name, cp->short_name, sizeof(hdev->short_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002502
Johan Hedbergb5235a62012-02-21 14:32:24 +02002503 if (!hdev_is_powered(hdev)) {
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002504 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002505
2506 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002507 data, len);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002508 if (err < 0)
2509 goto failed;
2510
2511 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data, len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002512 sk);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002513
Johan Hedbergb5235a62012-02-21 14:32:24 +02002514 goto failed;
2515 }
2516
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002517 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002518 if (!cmd) {
2519 err = -ENOMEM;
2520 goto failed;
2521 }
2522
Johan Hedberg13928972013-03-15 17:07:00 -05002523 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
2524
Johan Hedberg890ea892013-03-15 17:06:52 -05002525 hci_req_init(&req, hdev);
Johan Hedberg3f985052013-03-15 17:07:02 -05002526
2527 if (lmp_bredr_capable(hdev)) {
2528 update_name(&req);
2529 update_eir(&req);
2530 }
2531
2532 if (lmp_le_capable(hdev))
2533 hci_update_ad(&req);
2534
Johan Hedberg13928972013-03-15 17:07:00 -05002535 err = hci_req_run(&req, set_name_complete);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002536 if (err < 0)
2537 mgmt_pending_remove(cmd);
2538
2539failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002540 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002541 return err;
2542}
2543
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002544static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002545 void *data, u16 data_len)
Szymon Jancc35938b2011-03-22 13:12:21 +01002546{
Szymon Jancc35938b2011-03-22 13:12:21 +01002547 struct pending_cmd *cmd;
2548 int err;
2549
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002550 BT_DBG("%s", hdev->name);
Szymon Jancc35938b2011-03-22 13:12:21 +01002551
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002552 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002553
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002554 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002555 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002556 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002557 goto unlock;
2558 }
2559
Andre Guedes9a1a1992012-07-24 15:03:48 -03002560 if (!lmp_ssp_capable(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002561 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002562 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002563 goto unlock;
2564 }
2565
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002566 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002567 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002568 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01002569 goto unlock;
2570 }
2571
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002572 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01002573 if (!cmd) {
2574 err = -ENOMEM;
2575 goto unlock;
2576 }
2577
2578 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
2579 if (err < 0)
2580 mgmt_pending_remove(cmd);
2581
2582unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002583 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002584 return err;
2585}
2586
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002587static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002588 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002589{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002590 struct mgmt_cp_add_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002591 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002592 int err;
2593
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002594 BT_DBG("%s ", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01002595
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002596 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002597
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002598 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, cp->hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002599 cp->randomizer);
Szymon Janc2763eda2011-03-22 13:12:22 +01002600 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002601 status = MGMT_STATUS_FAILED;
Szymon Janc2763eda2011-03-22 13:12:22 +01002602 else
Szymon Janca6785be2012-12-13 15:11:21 +01002603 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002604
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002605 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002606 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002607
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002608 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002609 return err;
2610}
2611
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002612static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002613 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002614{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002615 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002616 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002617 int err;
2618
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002619 BT_DBG("%s", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01002620
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002621 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002622
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002623 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr);
Szymon Janc2763eda2011-03-22 13:12:22 +01002624 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002625 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01002626 else
Szymon Janca6785be2012-12-13 15:11:21 +01002627 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002628
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002629 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002630 status, &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002631
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002632 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002633 return err;
2634}
2635
Andre Guedes5e0452c2012-02-17 20:39:38 -03002636int mgmt_interleaved_discovery(struct hci_dev *hdev)
2637{
2638 int err;
2639
2640 BT_DBG("%s", hdev->name);
2641
2642 hci_dev_lock(hdev);
2643
2644 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR_LE);
2645 if (err < 0)
2646 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2647
2648 hci_dev_unlock(hdev);
2649
2650 return err;
2651}
2652
Andre Guedes7c307722013-04-30 15:29:28 -03002653static void start_discovery_complete(struct hci_dev *hdev, u8 status)
2654{
2655 BT_DBG("status %d", status);
2656
2657 if (status) {
2658 hci_dev_lock(hdev);
2659 mgmt_start_discovery_failed(hdev, status);
2660 hci_dev_unlock(hdev);
2661 return;
2662 }
2663
2664 hci_dev_lock(hdev);
2665 hci_discovery_set_state(hdev, DISCOVERY_FINDING);
2666 hci_dev_unlock(hdev);
2667
2668 switch (hdev->discovery.type) {
2669 case DISCOV_TYPE_LE:
2670 queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable,
2671 LE_SCAN_TIMEOUT_LE_ONLY);
2672 break;
2673
2674 case DISCOV_TYPE_INTERLEAVED:
2675 queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable,
2676 LE_SCAN_TIMEOUT_BREDR_LE);
2677 break;
2678
2679 case DISCOV_TYPE_BREDR:
2680 break;
2681
2682 default:
2683 BT_ERR("Invalid discovery type %d", hdev->discovery.type);
2684 }
2685}
2686
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002687static int start_discovery(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002688 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002689{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002690 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002691 struct pending_cmd *cmd;
Andre Guedes7c307722013-04-30 15:29:28 -03002692 struct hci_cp_le_set_scan_param param_cp;
2693 struct hci_cp_le_set_scan_enable enable_cp;
2694 struct hci_cp_inquiry inq_cp;
2695 struct hci_request req;
2696 /* General inquiry access code (GIAC) */
2697 u8 lap[3] = { 0x33, 0x8b, 0x9e };
Johan Hedberg14a53662011-04-27 10:29:56 -04002698 int err;
2699
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002700 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04002701
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002702 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002703
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002704 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002705 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002706 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02002707 goto failed;
2708 }
2709
Andre Guedes642be6c2012-03-21 00:03:37 -03002710 if (test_bit(HCI_PERIODIC_INQ, &hdev->dev_flags)) {
2711 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2712 MGMT_STATUS_BUSY);
2713 goto failed;
2714 }
2715
Johan Hedbergff9ef572012-01-04 14:23:45 +02002716 if (hdev->discovery.state != DISCOVERY_STOPPED) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002717 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002718 MGMT_STATUS_BUSY);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002719 goto failed;
2720 }
2721
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002722 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002723 if (!cmd) {
2724 err = -ENOMEM;
2725 goto failed;
2726 }
2727
Andre Guedes4aab14e2012-02-17 20:39:36 -03002728 hdev->discovery.type = cp->type;
2729
Andre Guedes7c307722013-04-30 15:29:28 -03002730 hci_req_init(&req, hdev);
2731
Andre Guedes4aab14e2012-02-17 20:39:36 -03002732 switch (hdev->discovery.type) {
Andre Guedesf39799f2012-02-17 20:39:35 -03002733 case DISCOV_TYPE_BREDR:
Johan Hedberg04106752013-01-10 14:54:09 +02002734 if (!lmp_bredr_capable(hdev)) {
2735 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2736 MGMT_STATUS_NOT_SUPPORTED);
2737 mgmt_pending_remove(cmd);
2738 goto failed;
2739 }
2740
Andre Guedes7c307722013-04-30 15:29:28 -03002741 if (test_bit(HCI_INQUIRY, &hdev->flags)) {
2742 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2743 MGMT_STATUS_BUSY);
2744 mgmt_pending_remove(cmd);
2745 goto failed;
2746 }
2747
2748 hci_inquiry_cache_flush(hdev);
2749
2750 memset(&inq_cp, 0, sizeof(inq_cp));
2751 memcpy(&inq_cp.lap, lap, sizeof(inq_cp.lap));
2752 inq_cp.length = INQUIRY_LEN_BREDR;
2753 hci_req_add(&req, HCI_OP_INQUIRY, sizeof(inq_cp), &inq_cp);
Andre Guedesf39799f2012-02-17 20:39:35 -03002754 break;
2755
2756 case DISCOV_TYPE_LE:
Andre Guedes7c307722013-04-30 15:29:28 -03002757 case DISCOV_TYPE_INTERLEAVED:
Johan Hedberg757aee02013-04-24 13:05:32 +03002758 if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
Johan Hedberg04106752013-01-10 14:54:09 +02002759 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2760 MGMT_STATUS_NOT_SUPPORTED);
2761 mgmt_pending_remove(cmd);
2762 goto failed;
2763 }
2764
Andre Guedes7c307722013-04-30 15:29:28 -03002765 if (hdev->discovery.type == DISCOV_TYPE_INTERLEAVED &&
2766 !lmp_bredr_capable(hdev)) {
Johan Hedberg04106752013-01-10 14:54:09 +02002767 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2768 MGMT_STATUS_NOT_SUPPORTED);
2769 mgmt_pending_remove(cmd);
2770 goto failed;
2771 }
2772
Andre Guedes7c307722013-04-30 15:29:28 -03002773 if (test_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags)) {
2774 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2775 MGMT_STATUS_REJECTED);
2776 mgmt_pending_remove(cmd);
2777 goto failed;
2778 }
2779
2780 if (test_bit(HCI_LE_SCAN, &hdev->dev_flags)) {
2781 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2782 MGMT_STATUS_BUSY);
2783 mgmt_pending_remove(cmd);
2784 goto failed;
2785 }
2786
2787 memset(&param_cp, 0, sizeof(param_cp));
2788 param_cp.type = LE_SCAN_ACTIVE;
2789 param_cp.interval = cpu_to_le16(LE_SCAN_INT);
2790 param_cp.window = cpu_to_le16(LE_SCAN_WIN);
2791 hci_req_add(&req, HCI_OP_LE_SET_SCAN_PARAM, sizeof(param_cp),
2792 &param_cp);
2793
2794 memset(&enable_cp, 0, sizeof(enable_cp));
2795 enable_cp.enable = LE_SCAN_ENABLE;
2796 enable_cp.filter_dup = LE_SCAN_FILTER_DUP_ENABLE;
2797 hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(enable_cp),
2798 &enable_cp);
Andre Guedes5e0452c2012-02-17 20:39:38 -03002799 break;
2800
Andre Guedesf39799f2012-02-17 20:39:35 -03002801 default:
Johan Hedberg04106752013-01-10 14:54:09 +02002802 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2803 MGMT_STATUS_INVALID_PARAMS);
2804 mgmt_pending_remove(cmd);
2805 goto failed;
Andre Guedesf39799f2012-02-17 20:39:35 -03002806 }
Andre Guedes3fd24152012-02-03 17:48:01 -03002807
Andre Guedes7c307722013-04-30 15:29:28 -03002808 err = hci_req_run(&req, start_discovery_complete);
Johan Hedberg14a53662011-04-27 10:29:56 -04002809 if (err < 0)
2810 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002811 else
2812 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002813
2814failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002815 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002816 return err;
2817}
2818
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002819static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002820 u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002821{
Johan Hedbergd9306502012-02-20 23:25:18 +02002822 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002823 struct pending_cmd *cmd;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002824 struct hci_cp_remote_name_req_cancel cp;
2825 struct inquiry_entry *e;
Johan Hedberg14a53662011-04-27 10:29:56 -04002826 int err;
2827
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002828 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04002829
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002830 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002831
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002832 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002833 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002834 MGMT_STATUS_REJECTED, &mgmt_cp->type,
2835 sizeof(mgmt_cp->type));
Johan Hedbergd9306502012-02-20 23:25:18 +02002836 goto unlock;
2837 }
2838
2839 if (hdev->discovery.type != mgmt_cp->type) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002840 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002841 MGMT_STATUS_INVALID_PARAMS, &mgmt_cp->type,
2842 sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002843 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02002844 }
2845
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002846 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002847 if (!cmd) {
2848 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002849 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04002850 }
2851
Andre Guedese0d9727e2012-03-20 15:15:36 -03002852 switch (hdev->discovery.state) {
2853 case DISCOVERY_FINDING:
Andre Guedesc9ecc482012-03-15 16:52:08 -03002854 if (test_bit(HCI_INQUIRY, &hdev->flags))
2855 err = hci_cancel_inquiry(hdev);
2856 else
2857 err = hci_cancel_le_scan(hdev);
2858
Andre Guedese0d9727e2012-03-20 15:15:36 -03002859 break;
2860
2861 case DISCOVERY_RESOLVING:
2862 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002863 NAME_PENDING);
Andre Guedese0d9727e2012-03-20 15:15:36 -03002864 if (!e) {
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002865 mgmt_pending_remove(cmd);
Andre Guedese0d9727e2012-03-20 15:15:36 -03002866 err = cmd_complete(sk, hdev->id,
2867 MGMT_OP_STOP_DISCOVERY, 0,
2868 &mgmt_cp->type,
2869 sizeof(mgmt_cp->type));
2870 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2871 goto unlock;
2872 }
2873
2874 bacpy(&cp.bdaddr, &e->data.bdaddr);
2875 err = hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ_CANCEL,
2876 sizeof(cp), &cp);
2877
2878 break;
2879
2880 default:
2881 BT_DBG("unknown discovery state %u", hdev->discovery.state);
2882 err = -EFAULT;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002883 }
2884
Johan Hedberg14a53662011-04-27 10:29:56 -04002885 if (err < 0)
2886 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002887 else
2888 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002889
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002890unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002891 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002892 return err;
2893}
2894
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002895static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002896 u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02002897{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002898 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002899 struct inquiry_entry *e;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002900 int err;
2901
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002902 BT_DBG("%s", hdev->name);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002903
Johan Hedberg561aafb2012-01-04 13:31:59 +02002904 hci_dev_lock(hdev);
2905
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002906 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002907 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002908 MGMT_STATUS_FAILED);
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002909 goto failed;
2910 }
2911
Johan Hedberga198e7b2012-02-17 14:27:06 +02002912 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002913 if (!e) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002914 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002915 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002916 goto failed;
2917 }
2918
2919 if (cp->name_known) {
2920 e->name_state = NAME_KNOWN;
2921 list_del(&e->list);
2922 } else {
2923 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e202012-01-09 00:53:02 +02002924 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002925 }
2926
Johan Hedberge3846622013-01-09 15:29:33 +02002927 err = cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME, 0, &cp->addr,
2928 sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02002929
2930failed:
2931 hci_dev_unlock(hdev);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002932 return err;
2933}
2934
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002935static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002936 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002937{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002938 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002939 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03002940 int err;
2941
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002942 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03002943
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002944 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg5d0846d2013-01-20 14:27:22 +02002945 return cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE,
2946 MGMT_STATUS_INVALID_PARAMS,
2947 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002948
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002949 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002950
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002951 err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002952 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002953 status = MGMT_STATUS_FAILED;
Antti Julku7fbec222011-06-15 12:01:15 +03002954 else
Szymon Janca6785be2012-12-13 15:11:21 +01002955 status = MGMT_STATUS_SUCCESS;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002956
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002957 err = cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002958 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03002959
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002960 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002961
2962 return err;
2963}
2964
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002965static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002966 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002967{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002968 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002969 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03002970 int err;
2971
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002972 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03002973
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002974 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg5d0846d2013-01-20 14:27:22 +02002975 return cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE,
2976 MGMT_STATUS_INVALID_PARAMS,
2977 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002978
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002979 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002980
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002981 err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002982 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002983 status = MGMT_STATUS_INVALID_PARAMS;
Antti Julku7fbec222011-06-15 12:01:15 +03002984 else
Szymon Janca6785be2012-12-13 15:11:21 +01002985 status = MGMT_STATUS_SUCCESS;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002986
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002987 err = cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002988 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03002989
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002990 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002991
2992 return err;
2993}
2994
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07002995static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data,
2996 u16 len)
2997{
2998 struct mgmt_cp_set_device_id *cp = data;
Johan Hedberg890ea892013-03-15 17:06:52 -05002999 struct hci_request req;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003000 int err;
Szymon Jancc72d4b82012-03-16 16:02:57 +01003001 __u16 source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003002
3003 BT_DBG("%s", hdev->name);
3004
Szymon Jancc72d4b82012-03-16 16:02:57 +01003005 source = __le16_to_cpu(cp->source);
3006
3007 if (source > 0x0002)
3008 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEVICE_ID,
3009 MGMT_STATUS_INVALID_PARAMS);
3010
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003011 hci_dev_lock(hdev);
3012
Szymon Jancc72d4b82012-03-16 16:02:57 +01003013 hdev->devid_source = source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003014 hdev->devid_vendor = __le16_to_cpu(cp->vendor);
3015 hdev->devid_product = __le16_to_cpu(cp->product);
3016 hdev->devid_version = __le16_to_cpu(cp->version);
3017
3018 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_ID, 0, NULL, 0);
3019
Johan Hedberg890ea892013-03-15 17:06:52 -05003020 hci_req_init(&req, hdev);
3021 update_eir(&req);
3022 hci_req_run(&req, NULL);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003023
3024 hci_dev_unlock(hdev);
3025
3026 return err;
3027}
3028
Johan Hedberg33e38b32013-03-15 17:07:05 -05003029static void fast_connectable_complete(struct hci_dev *hdev, u8 status)
3030{
3031 struct pending_cmd *cmd;
3032
3033 BT_DBG("status 0x%02x", status);
3034
3035 hci_dev_lock(hdev);
3036
3037 cmd = mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev);
3038 if (!cmd)
3039 goto unlock;
3040
3041 if (status) {
3042 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3043 mgmt_status(status));
3044 } else {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05003045 struct mgmt_mode *cp = cmd->param;
3046
3047 if (cp->val)
3048 set_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3049 else
3050 clear_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3051
Johan Hedberg33e38b32013-03-15 17:07:05 -05003052 send_settings_rsp(cmd->sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev);
3053 new_settings(hdev, cmd->sk);
3054 }
3055
3056 mgmt_pending_remove(cmd);
3057
3058unlock:
3059 hci_dev_unlock(hdev);
3060}
3061
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003062static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003063 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03003064{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003065 struct mgmt_mode *cp = data;
Johan Hedberg33e38b32013-03-15 17:07:05 -05003066 struct pending_cmd *cmd;
3067 struct hci_request req;
Antti Julkuf6422ec2011-06-22 13:11:56 +03003068 int err;
3069
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003070 BT_DBG("%s", hdev->name);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003071
Johan Hedberg1a47aee2013-03-15 17:07:06 -05003072 if (!lmp_bredr_capable(hdev) || hdev->hci_ver < BLUETOOTH_VER_1_2)
Johan Hedberg33c525c2012-10-24 21:11:58 +03003073 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3074 MGMT_STATUS_NOT_SUPPORTED);
3075
Johan Hedberga7e80f22013-01-09 16:05:19 +02003076 if (cp->val != 0x00 && cp->val != 0x01)
3077 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3078 MGMT_STATUS_INVALID_PARAMS);
3079
Johan Hedberg5400c042012-02-21 16:40:33 +02003080 if (!hdev_is_powered(hdev))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003081 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003082 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5400c042012-02-21 16:40:33 +02003083
3084 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003085 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003086 MGMT_STATUS_REJECTED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003087
3088 hci_dev_lock(hdev);
3089
Johan Hedberg05cbf292013-03-15 17:07:07 -05003090 if (mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev)) {
3091 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3092 MGMT_STATUS_BUSY);
3093 goto unlock;
3094 }
3095
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05003096 if (!!cp->val == test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags)) {
3097 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
3098 hdev);
3099 goto unlock;
3100 }
3101
Johan Hedberg33e38b32013-03-15 17:07:05 -05003102 cmd = mgmt_pending_add(sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev,
3103 data, len);
3104 if (!cmd) {
3105 err = -ENOMEM;
3106 goto unlock;
3107 }
3108
3109 hci_req_init(&req, hdev);
3110
Johan Hedberg406d7802013-03-15 17:07:09 -05003111 write_fast_connectable(&req, cp->val);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003112
3113 err = hci_req_run(&req, fast_connectable_complete);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003114 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003115 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003116 MGMT_STATUS_FAILED);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003117 mgmt_pending_remove(cmd);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003118 }
3119
Johan Hedberg33e38b32013-03-15 17:07:05 -05003120unlock:
Antti Julkuf6422ec2011-06-22 13:11:56 +03003121 hci_dev_unlock(hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003122
Antti Julkuf6422ec2011-06-22 13:11:56 +03003123 return err;
3124}
3125
Johan Hedberg3f706b72013-01-20 14:27:16 +02003126static bool ltk_is_valid(struct mgmt_ltk_info *key)
3127{
Johan Hedberg44b20d32013-01-20 14:27:17 +02003128 if (key->authenticated != 0x00 && key->authenticated != 0x01)
3129 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02003130 if (key->master != 0x00 && key->master != 0x01)
3131 return false;
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003132 if (!bdaddr_type_is_le(key->addr.type))
3133 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02003134 return true;
3135}
3136
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003137static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003138 void *cp_data, u16 len)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003139{
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003140 struct mgmt_cp_load_long_term_keys *cp = cp_data;
3141 u16 key_count, expected_len;
Johan Hedberg715a5bf2013-01-09 15:29:34 +02003142 int i, err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003143
Marcel Holtmann1f350c82012-03-12 20:31:08 -07003144 key_count = __le16_to_cpu(cp->key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003145
3146 expected_len = sizeof(*cp) + key_count *
3147 sizeof(struct mgmt_ltk_info);
3148 if (expected_len != len) {
3149 BT_ERR("load_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003150 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003151 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
Johan Hedberge57e6192013-01-20 14:27:14 +02003152 MGMT_STATUS_INVALID_PARAMS);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003153 }
3154
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003155 BT_DBG("%s key_count %u", hdev->name, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003156
Johan Hedberg54ad6d82013-01-20 14:27:15 +02003157 for (i = 0; i < key_count; i++) {
3158 struct mgmt_ltk_info *key = &cp->keys[i];
3159
Johan Hedberg3f706b72013-01-20 14:27:16 +02003160 if (!ltk_is_valid(key))
Johan Hedberg54ad6d82013-01-20 14:27:15 +02003161 return cmd_status(sk, hdev->id,
3162 MGMT_OP_LOAD_LONG_TERM_KEYS,
3163 MGMT_STATUS_INVALID_PARAMS);
3164 }
3165
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003166 hci_dev_lock(hdev);
3167
3168 hci_smp_ltks_clear(hdev);
3169
3170 for (i = 0; i < key_count; i++) {
3171 struct mgmt_ltk_info *key = &cp->keys[i];
3172 u8 type;
3173
3174 if (key->master)
3175 type = HCI_SMP_LTK;
3176 else
3177 type = HCI_SMP_LTK_SLAVE;
3178
Hemant Gupta4596fde2012-04-16 14:57:40 +05303179 hci_add_ltk(hdev, &key->addr.bdaddr,
Andre Guedes378b5b72012-04-24 21:02:51 -03003180 bdaddr_to_le(key->addr.type),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003181 type, 0, key->authenticated, key->val,
3182 key->enc_size, key->ediv, key->rand);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003183 }
3184
Johan Hedberg715a5bf2013-01-09 15:29:34 +02003185 err = cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, 0,
3186 NULL, 0);
3187
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003188 hci_dev_unlock(hdev);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003189
Johan Hedberg715a5bf2013-01-09 15:29:34 +02003190 return err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003191}
3192
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02003193static const struct mgmt_handler {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003194 int (*func) (struct sock *sk, struct hci_dev *hdev, void *data,
3195 u16 data_len);
Johan Hedbergbe22b542012-03-01 22:24:41 +02003196 bool var_len;
3197 size_t data_len;
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003198} mgmt_handlers[] = {
3199 { NULL }, /* 0x0000 (no command) */
Johan Hedbergbe22b542012-03-01 22:24:41 +02003200 { read_version, false, MGMT_READ_VERSION_SIZE },
3201 { read_commands, false, MGMT_READ_COMMANDS_SIZE },
3202 { read_index_list, false, MGMT_READ_INDEX_LIST_SIZE },
3203 { read_controller_info, false, MGMT_READ_INFO_SIZE },
3204 { set_powered, false, MGMT_SETTING_SIZE },
3205 { set_discoverable, false, MGMT_SET_DISCOVERABLE_SIZE },
3206 { set_connectable, false, MGMT_SETTING_SIZE },
3207 { set_fast_connectable, false, MGMT_SETTING_SIZE },
3208 { set_pairable, false, MGMT_SETTING_SIZE },
3209 { set_link_security, false, MGMT_SETTING_SIZE },
3210 { set_ssp, false, MGMT_SETTING_SIZE },
3211 { set_hs, false, MGMT_SETTING_SIZE },
3212 { set_le, false, MGMT_SETTING_SIZE },
3213 { set_dev_class, false, MGMT_SET_DEV_CLASS_SIZE },
3214 { set_local_name, false, MGMT_SET_LOCAL_NAME_SIZE },
3215 { add_uuid, false, MGMT_ADD_UUID_SIZE },
3216 { remove_uuid, false, MGMT_REMOVE_UUID_SIZE },
3217 { load_link_keys, true, MGMT_LOAD_LINK_KEYS_SIZE },
3218 { load_long_term_keys, true, MGMT_LOAD_LONG_TERM_KEYS_SIZE },
3219 { disconnect, false, MGMT_DISCONNECT_SIZE },
3220 { get_connections, false, MGMT_GET_CONNECTIONS_SIZE },
3221 { pin_code_reply, false, MGMT_PIN_CODE_REPLY_SIZE },
3222 { pin_code_neg_reply, false, MGMT_PIN_CODE_NEG_REPLY_SIZE },
3223 { set_io_capability, false, MGMT_SET_IO_CAPABILITY_SIZE },
3224 { pair_device, false, MGMT_PAIR_DEVICE_SIZE },
3225 { cancel_pair_device, false, MGMT_CANCEL_PAIR_DEVICE_SIZE },
3226 { unpair_device, false, MGMT_UNPAIR_DEVICE_SIZE },
3227 { user_confirm_reply, false, MGMT_USER_CONFIRM_REPLY_SIZE },
3228 { user_confirm_neg_reply, false, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
3229 { user_passkey_reply, false, MGMT_USER_PASSKEY_REPLY_SIZE },
3230 { user_passkey_neg_reply, false, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
3231 { read_local_oob_data, false, MGMT_READ_LOCAL_OOB_DATA_SIZE },
3232 { add_remote_oob_data, false, MGMT_ADD_REMOTE_OOB_DATA_SIZE },
3233 { remove_remote_oob_data, false, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
3234 { start_discovery, false, MGMT_START_DISCOVERY_SIZE },
3235 { stop_discovery, false, MGMT_STOP_DISCOVERY_SIZE },
3236 { confirm_name, false, MGMT_CONFIRM_NAME_SIZE },
3237 { block_device, false, MGMT_BLOCK_DEVICE_SIZE },
3238 { unblock_device, false, MGMT_UNBLOCK_DEVICE_SIZE },
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003239 { set_device_id, false, MGMT_SET_DEVICE_ID_SIZE },
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003240};
3241
3242
Johan Hedberg03811012010-12-08 00:21:06 +02003243int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
3244{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003245 void *buf;
3246 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02003247 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01003248 u16 opcode, index, len;
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003249 struct hci_dev *hdev = NULL;
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02003250 const struct mgmt_handler *handler;
Johan Hedberg03811012010-12-08 00:21:06 +02003251 int err;
3252
3253 BT_DBG("got %zu bytes", msglen);
3254
3255 if (msglen < sizeof(*hdr))
3256 return -EINVAL;
3257
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03003258 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02003259 if (!buf)
3260 return -ENOMEM;
3261
3262 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
3263 err = -EFAULT;
3264 goto done;
3265 }
3266
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003267 hdr = buf;
Marcel Holtmann1f350c82012-03-12 20:31:08 -07003268 opcode = __le16_to_cpu(hdr->opcode);
3269 index = __le16_to_cpu(hdr->index);
3270 len = __le16_to_cpu(hdr->len);
Johan Hedberg03811012010-12-08 00:21:06 +02003271
3272 if (len != msglen - sizeof(*hdr)) {
3273 err = -EINVAL;
3274 goto done;
3275 }
3276
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003277 if (index != MGMT_INDEX_NONE) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003278 hdev = hci_dev_get(index);
3279 if (!hdev) {
3280 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003281 MGMT_STATUS_INVALID_INDEX);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003282 goto done;
3283 }
3284 }
3285
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003286 if (opcode >= ARRAY_SIZE(mgmt_handlers) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003287 mgmt_handlers[opcode].func == NULL) {
Johan Hedberg03811012010-12-08 00:21:06 +02003288 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02003289 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003290 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003291 goto done;
Johan Hedberg03811012010-12-08 00:21:06 +02003292 }
3293
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003294 if ((hdev && opcode < MGMT_OP_READ_INFO) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003295 (!hdev && opcode >= MGMT_OP_READ_INFO)) {
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003296 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003297 MGMT_STATUS_INVALID_INDEX);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003298 goto done;
3299 }
3300
Johan Hedbergbe22b542012-03-01 22:24:41 +02003301 handler = &mgmt_handlers[opcode];
3302
3303 if ((handler->var_len && len < handler->data_len) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003304 (!handler->var_len && len != handler->data_len)) {
Johan Hedbergbe22b542012-03-01 22:24:41 +02003305 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003306 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergbe22b542012-03-01 22:24:41 +02003307 goto done;
3308 }
3309
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003310 if (hdev)
3311 mgmt_init_hdev(sk, hdev);
3312
3313 cp = buf + sizeof(*hdr);
3314
Johan Hedbergbe22b542012-03-01 22:24:41 +02003315 err = handler->func(sk, hdev, cp, len);
Johan Hedberge41d8b42010-12-13 21:07:03 +02003316 if (err < 0)
3317 goto done;
3318
Johan Hedberg03811012010-12-08 00:21:06 +02003319 err = msglen;
3320
3321done:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003322 if (hdev)
3323 hci_dev_put(hdev);
3324
Johan Hedberg03811012010-12-08 00:21:06 +02003325 kfree(buf);
3326 return err;
3327}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003328
Johan Hedbergb24752f2011-11-03 14:40:33 +02003329static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
3330{
3331 u8 *status = data;
3332
3333 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
3334 mgmt_pending_remove(cmd);
3335}
3336
Johan Hedberg744cf192011-11-08 20:40:14 +02003337int mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003338{
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03003339 if (!mgmt_valid_hdev(hdev))
3340 return -ENOTSUPP;
3341
Johan Hedberg744cf192011-11-08 20:40:14 +02003342 return mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003343}
3344
Johan Hedberg744cf192011-11-08 20:40:14 +02003345int mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003346{
Johan Hedberg5f159032012-03-02 03:13:19 +02003347 u8 status = MGMT_STATUS_INVALID_INDEX;
Johan Hedbergb24752f2011-11-03 14:40:33 +02003348
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03003349 if (!mgmt_valid_hdev(hdev))
3350 return -ENOTSUPP;
3351
Johan Hedberg744cf192011-11-08 20:40:14 +02003352 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02003353
Johan Hedberg744cf192011-11-08 20:40:14 +02003354 return mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02003355}
3356
Johan Hedberg73f22f62010-12-29 16:00:25 +02003357struct cmd_lookup {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02003358 struct sock *sk;
Johan Hedberg69ab39e2011-12-15 00:47:35 +02003359 struct hci_dev *hdev;
Johan Hedberg90e70452012-02-23 23:09:40 +02003360 u8 mgmt_status;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02003361};
3362
Johan Hedberg69ab39e2011-12-15 00:47:35 +02003363static void settings_rsp(struct pending_cmd *cmd, void *data)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02003364{
Johan Hedberg73f22f62010-12-29 16:00:25 +02003365 struct cmd_lookup *match = data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02003366
Johan Hedberg69ab39e2011-12-15 00:47:35 +02003367 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02003368
3369 list_del(&cmd->list);
3370
3371 if (match->sk == NULL) {
3372 match->sk = cmd->sk;
3373 sock_hold(match->sk);
3374 }
3375
3376 mgmt_pending_free(cmd);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003377}
Johan Hedberg5add6af2010-12-16 10:00:37 +02003378
Johan Hedberg890ea892013-03-15 17:06:52 -05003379static void set_bredr_scan(struct hci_request *req)
Johan Hedberg7f0ae642012-10-24 21:11:57 +03003380{
Johan Hedberg890ea892013-03-15 17:06:52 -05003381 struct hci_dev *hdev = req->hdev;
Johan Hedberg7f0ae642012-10-24 21:11:57 +03003382 u8 scan = 0;
3383
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05003384 /* Ensure that fast connectable is disabled. This function will
3385 * not do anything if the page scan parameters are already what
3386 * they should be.
3387 */
3388 write_fast_connectable(req, false);
3389
Johan Hedberg7f0ae642012-10-24 21:11:57 +03003390 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3391 scan |= SCAN_PAGE;
3392 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3393 scan |= SCAN_INQUIRY;
3394
Johan Hedberg890ea892013-03-15 17:06:52 -05003395 if (scan)
3396 hci_req_add(req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
Johan Hedberg7f0ae642012-10-24 21:11:57 +03003397}
3398
Johan Hedberg229ab392013-03-15 17:06:53 -05003399static void powered_complete(struct hci_dev *hdev, u8 status)
3400{
3401 struct cmd_lookup match = { NULL, hdev };
3402
3403 BT_DBG("status 0x%02x", status);
3404
3405 hci_dev_lock(hdev);
3406
3407 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
3408
3409 new_settings(hdev, match.sk);
3410
3411 hci_dev_unlock(hdev);
3412
3413 if (match.sk)
3414 sock_put(match.sk);
3415}
3416
Johan Hedberg70da6242013-03-15 17:06:51 -05003417static int powered_update_hci(struct hci_dev *hdev)
3418{
Johan Hedberg890ea892013-03-15 17:06:52 -05003419 struct hci_request req;
Johan Hedberg70da6242013-03-15 17:06:51 -05003420 u8 link_sec;
3421
Johan Hedberg890ea892013-03-15 17:06:52 -05003422 hci_req_init(&req, hdev);
3423
Johan Hedberg70da6242013-03-15 17:06:51 -05003424 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) &&
3425 !lmp_host_ssp_capable(hdev)) {
3426 u8 ssp = 1;
3427
Johan Hedberg890ea892013-03-15 17:06:52 -05003428 hci_req_add(&req, HCI_OP_WRITE_SSP_MODE, 1, &ssp);
Johan Hedberg70da6242013-03-15 17:06:51 -05003429 }
3430
Johan Hedbergc73eee92013-04-19 18:35:21 +03003431 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags) &&
3432 lmp_bredr_capable(hdev)) {
Johan Hedberg70da6242013-03-15 17:06:51 -05003433 struct hci_cp_write_le_host_supported cp;
3434
3435 cp.le = 1;
3436 cp.simul = lmp_le_br_capable(hdev);
3437
3438 /* Check first if we already have the right
3439 * host state (host features set)
3440 */
3441 if (cp.le != lmp_host_le_capable(hdev) ||
3442 cp.simul != lmp_host_le_br_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05003443 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED,
3444 sizeof(cp), &cp);
Johan Hedberg70da6242013-03-15 17:06:51 -05003445 }
3446
3447 link_sec = test_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
3448 if (link_sec != test_bit(HCI_AUTH, &hdev->flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05003449 hci_req_add(&req, HCI_OP_WRITE_AUTH_ENABLE,
3450 sizeof(link_sec), &link_sec);
Johan Hedberg70da6242013-03-15 17:06:51 -05003451
3452 if (lmp_bredr_capable(hdev)) {
Johan Hedberg890ea892013-03-15 17:06:52 -05003453 set_bredr_scan(&req);
3454 update_class(&req);
Johan Hedberg13928972013-03-15 17:07:00 -05003455 update_name(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05003456 update_eir(&req);
Johan Hedberg70da6242013-03-15 17:06:51 -05003457 }
3458
Johan Hedberg229ab392013-03-15 17:06:53 -05003459 return hci_req_run(&req, powered_complete);
Johan Hedberg70da6242013-03-15 17:06:51 -05003460}
3461
Johan Hedberg744cf192011-11-08 20:40:14 +02003462int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg5add6af2010-12-16 10:00:37 +02003463{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02003464 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg229ab392013-03-15 17:06:53 -05003465 u8 status_not_powered = MGMT_STATUS_NOT_POWERED;
3466 u8 zero_cod[] = { 0, 0, 0 };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003467 int err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02003468
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003469 if (!test_bit(HCI_MGMT, &hdev->dev_flags))
3470 return 0;
3471
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003472 if (powered) {
Johan Hedberg229ab392013-03-15 17:06:53 -05003473 if (powered_update_hci(hdev) == 0)
3474 return 0;
Johan Hedbergfe038882013-01-16 16:15:34 +02003475
Johan Hedberg229ab392013-03-15 17:06:53 -05003476 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp,
3477 &match);
3478 goto new_settings;
Johan Hedbergb24752f2011-11-03 14:40:33 +02003479 }
3480
Johan Hedberg229ab392013-03-15 17:06:53 -05003481 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
3482 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status_not_powered);
3483
3484 if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0)
3485 mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
3486 zero_cod, sizeof(zero_cod), NULL);
3487
3488new_settings:
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003489 err = new_settings(hdev, match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02003490
3491 if (match.sk)
3492 sock_put(match.sk);
3493
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003494 return err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02003495}
Johan Hedberg73f22f62010-12-29 16:00:25 +02003496
Johan Hedberg96570ff2013-05-29 09:51:29 +03003497int mgmt_set_powered_failed(struct hci_dev *hdev, int err)
3498{
3499 struct pending_cmd *cmd;
3500 u8 status;
3501
3502 cmd = mgmt_pending_find(MGMT_OP_SET_POWERED, hdev);
3503 if (!cmd)
3504 return -ENOENT;
3505
3506 if (err == -ERFKILL)
3507 status = MGMT_STATUS_RFKILLED;
3508 else
3509 status = MGMT_STATUS_FAILED;
3510
3511 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_POWERED, status);
3512
3513 mgmt_pending_remove(cmd);
3514
3515 return err;
3516}
3517
Johan Hedberg744cf192011-11-08 20:40:14 +02003518int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg73f22f62010-12-29 16:00:25 +02003519{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02003520 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003521 bool changed = false;
3522 int err = 0;
Johan Hedberg73f22f62010-12-29 16:00:25 +02003523
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003524 if (discoverable) {
3525 if (!test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3526 changed = true;
3527 } else {
3528 if (test_and_clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3529 changed = true;
3530 }
Johan Hedberg73f22f62010-12-29 16:00:25 +02003531
Johan Hedberged9b5f22012-02-21 20:47:06 +02003532 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003533 &match);
Johan Hedberged9b5f22012-02-21 20:47:06 +02003534
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003535 if (changed)
3536 err = new_settings(hdev, match.sk);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003537
Johan Hedberg73f22f62010-12-29 16:00:25 +02003538 if (match.sk)
3539 sock_put(match.sk);
3540
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003541 return err;
Johan Hedberg73f22f62010-12-29 16:00:25 +02003542}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003543
Johan Hedberg744cf192011-11-08 20:40:14 +02003544int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003545{
Johan Hedberg2b76f452013-03-15 17:07:04 -05003546 struct pending_cmd *cmd;
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003547 bool changed = false;
3548 int err = 0;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003549
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003550 if (connectable) {
3551 if (!test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3552 changed = true;
3553 } else {
3554 if (test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3555 changed = true;
3556 }
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003557
Johan Hedberg2b76f452013-03-15 17:07:04 -05003558 cmd = mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberged9b5f22012-02-21 20:47:06 +02003559
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003560 if (changed)
Johan Hedberg2b76f452013-03-15 17:07:04 -05003561 err = new_settings(hdev, cmd ? cmd->sk : NULL);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003562
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003563 return err;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003564}
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003565
Johan Hedberg744cf192011-11-08 20:40:14 +02003566int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003567{
Johan Hedbergca69b792011-11-11 18:10:00 +02003568 u8 mgmt_err = mgmt_status(status);
3569
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003570 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02003571 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003572 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003573
3574 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02003575 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003576 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003577
3578 return 0;
3579}
3580
Cristian Chilipirea53168e52012-05-09 08:44:52 +03003581int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
3582 bool persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003583{
Johan Hedberg86742e12011-11-07 23:13:38 +02003584 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003585
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003586 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003587
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003588 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02003589 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03003590 ev.key.addr.type = BDADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003591 ev.key.type = key->type;
Andrei Emeltchenko9b3b4462012-05-23 11:31:20 +03003592 memcpy(ev.key.val, key->val, HCI_LINK_KEY_SIZE);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003593 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003594
Johan Hedberg744cf192011-11-08 20:40:14 +02003595 return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003596}
Johan Hedbergf7520542011-01-20 12:34:39 +02003597
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003598int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
3599{
3600 struct mgmt_ev_new_long_term_key ev;
3601
3602 memset(&ev, 0, sizeof(ev));
3603
3604 ev.store_hint = persistent;
3605 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003606 ev.key.addr.type = link_to_bdaddr(LE_LINK, key->bdaddr_type);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003607 ev.key.authenticated = key->authenticated;
3608 ev.key.enc_size = key->enc_size;
3609 ev.key.ediv = key->ediv;
3610
3611 if (key->type == HCI_SMP_LTK)
3612 ev.key.master = 1;
3613
3614 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
3615 memcpy(ev.key.val, key->val, sizeof(key->val));
3616
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003617 return mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev),
3618 NULL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003619}
3620
Johan Hedbergafc747a2012-01-15 18:11:07 +02003621int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003622 u8 addr_type, u32 flags, u8 *name, u8 name_len,
3623 u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02003624{
Johan Hedbergb644ba32012-01-17 21:48:47 +02003625 char buf[512];
3626 struct mgmt_ev_device_connected *ev = (void *) buf;
3627 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02003628
Johan Hedbergb644ba32012-01-17 21:48:47 +02003629 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003630 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02003631
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02003632 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02003633
Johan Hedbergb644ba32012-01-17 21:48:47 +02003634 if (name_len > 0)
3635 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003636 name, name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003637
3638 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
Brian Gix53156382012-03-09 14:07:03 -08003639 eir_len = eir_append_data(ev->eir, eir_len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003640 EIR_CLASS_OF_DEV, dev_class, 3);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003641
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02003642 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003643
3644 return mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003645 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02003646}
3647
Johan Hedberg8962ee72011-01-20 12:40:27 +02003648static void disconnect_rsp(struct pending_cmd *cmd, void *data)
3649{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01003650 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003651 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02003652 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003653
Johan Hedberg88c3df12012-02-09 14:27:38 +02003654 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3655 rp.addr.type = cp->addr.type;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003656
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003657 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003658 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003659
3660 *sk = cmd->sk;
3661 sock_hold(*sk);
3662
Johan Hedberga664b5b2011-02-19 12:06:02 -03003663 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003664}
3665
Johan Hedberg124f6e32012-02-09 13:50:12 +02003666static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02003667{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003668 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02003669 struct mgmt_cp_unpair_device *cp = cmd->param;
3670 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02003671
3672 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02003673 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3674 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02003675
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003676 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
3677
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003678 cmd_complete(cmd->sk, cmd->index, cmd->opcode, 0, &rp, sizeof(rp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02003679
3680 mgmt_pending_remove(cmd);
3681}
3682
Johan Hedbergafc747a2012-01-15 18:11:07 +02003683int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02003684 u8 link_type, u8 addr_type, u8 reason)
Johan Hedbergf7520542011-01-20 12:34:39 +02003685{
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02003686 struct mgmt_ev_device_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003687 struct sock *sk = NULL;
3688 int err;
3689
Johan Hedberg744cf192011-11-08 20:40:14 +02003690 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02003691
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02003692 bacpy(&ev.addr.bdaddr, bdaddr);
3693 ev.addr.type = link_to_bdaddr(link_type, addr_type);
3694 ev.reason = reason;
Johan Hedbergf7520542011-01-20 12:34:39 +02003695
Johan Hedbergafc747a2012-01-15 18:11:07 +02003696 err = mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003697 sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003698
3699 if (sk)
Szymon Jancd97dcb62012-03-16 16:02:56 +01003700 sock_put(sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003701
Johan Hedberg124f6e32012-02-09 13:50:12 +02003702 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003703 hdev);
Johan Hedberga8a1d192011-11-10 15:54:38 +02003704
Johan Hedberg8962ee72011-01-20 12:40:27 +02003705 return err;
3706}
3707
Johan Hedberg88c3df12012-02-09 14:27:38 +02003708int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003709 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02003710{
Johan Hedberg88c3df12012-02-09 14:27:38 +02003711 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003712 struct pending_cmd *cmd;
3713 int err;
3714
Jefferson Delfes36a75f12012-09-18 13:36:54 -04003715 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
3716 hdev);
3717
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003718 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003719 if (!cmd)
3720 return -ENOENT;
3721
Johan Hedberg88c3df12012-02-09 14:27:38 +02003722 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003723 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02003724
Johan Hedberg88c3df12012-02-09 14:27:38 +02003725 err = cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003726 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003727
Johan Hedberga664b5b2011-02-19 12:06:02 -03003728 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003729
3730 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02003731}
Johan Hedberg17d5c042011-01-22 06:09:08 +02003732
Johan Hedberg48264f02011-11-09 13:58:58 +02003733int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003734 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02003735{
3736 struct mgmt_ev_connect_failed ev;
3737
Johan Hedberg4c659c32011-11-07 23:13:39 +02003738 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003739 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003740 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003741
Johan Hedberg744cf192011-11-08 20:40:14 +02003742 return mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003743}
Johan Hedberg980e1a52011-01-22 06:10:07 +02003744
Johan Hedberg744cf192011-11-08 20:40:14 +02003745int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003746{
3747 struct mgmt_ev_pin_code_request ev;
3748
Johan Hedbergd8457692012-02-17 14:24:57 +02003749 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03003750 ev.addr.type = BDADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02003751 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003752
Johan Hedberg744cf192011-11-08 20:40:14 +02003753 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003754 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003755}
3756
Johan Hedberg744cf192011-11-08 20:40:14 +02003757int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003758 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003759{
3760 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003761 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003762 int err;
3763
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003764 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003765 if (!cmd)
3766 return -ENOENT;
3767
Johan Hedbergd8457692012-02-17 14:24:57 +02003768 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03003769 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003770
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003771 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003772 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003773
Johan Hedberga664b5b2011-02-19 12:06:02 -03003774 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003775
3776 return err;
3777}
3778
Johan Hedberg744cf192011-11-08 20:40:14 +02003779int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003780 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003781{
3782 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003783 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003784 int err;
3785
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003786 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003787 if (!cmd)
3788 return -ENOENT;
3789
Johan Hedbergd8457692012-02-17 14:24:57 +02003790 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03003791 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003792
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003793 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003794 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003795
Johan Hedberga664b5b2011-02-19 12:06:02 -03003796 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003797
3798 return err;
3799}
Johan Hedberga5c29682011-02-19 12:05:57 -03003800
Johan Hedberg744cf192011-11-08 20:40:14 +02003801int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003802 u8 link_type, u8 addr_type, __le32 value,
3803 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03003804{
3805 struct mgmt_ev_user_confirm_request ev;
3806
Johan Hedberg744cf192011-11-08 20:40:14 +02003807 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03003808
Johan Hedberg272d90d2012-02-09 15:26:12 +02003809 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003810 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07003811 ev.confirm_hint = confirm_hint;
Andrei Emeltchenko78e8098e2012-03-09 13:00:50 +02003812 ev.value = value;
Johan Hedberga5c29682011-02-19 12:05:57 -03003813
Johan Hedberg744cf192011-11-08 20:40:14 +02003814 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003815 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03003816}
3817
Johan Hedberg272d90d2012-02-09 15:26:12 +02003818int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003819 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08003820{
3821 struct mgmt_ev_user_passkey_request ev;
3822
3823 BT_DBG("%s", hdev->name);
3824
Johan Hedberg272d90d2012-02-09 15:26:12 +02003825 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003826 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08003827
3828 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003829 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08003830}
3831
Brian Gix0df4c182011-11-16 13:53:13 -08003832static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003833 u8 link_type, u8 addr_type, u8 status,
3834 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03003835{
3836 struct pending_cmd *cmd;
3837 struct mgmt_rp_user_confirm_reply rp;
3838 int err;
3839
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003840 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03003841 if (!cmd)
3842 return -ENOENT;
3843
Johan Hedberg272d90d2012-02-09 15:26:12 +02003844 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003845 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003846 err = cmd_complete(cmd->sk, hdev->id, opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003847 &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03003848
Johan Hedberga664b5b2011-02-19 12:06:02 -03003849 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03003850
3851 return err;
3852}
3853
Johan Hedberg744cf192011-11-08 20:40:14 +02003854int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003855 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003856{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003857 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003858 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003859}
3860
Johan Hedberg272d90d2012-02-09 15:26:12 +02003861int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003862 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003863{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003864 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03003865 status,
3866 MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003867}
Johan Hedberg2a611692011-02-19 12:06:00 -03003868
Brian Gix604086b2011-11-23 08:28:33 -08003869int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003870 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003871{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003872 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003873 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003874}
3875
Johan Hedberg272d90d2012-02-09 15:26:12 +02003876int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003877 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003878{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003879 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03003880 status,
3881 MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003882}
3883
Johan Hedberg92a25252012-09-06 18:39:26 +03003884int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr,
3885 u8 link_type, u8 addr_type, u32 passkey,
3886 u8 entered)
3887{
3888 struct mgmt_ev_passkey_notify ev;
3889
3890 BT_DBG("%s", hdev->name);
3891
3892 bacpy(&ev.addr.bdaddr, bdaddr);
3893 ev.addr.type = link_to_bdaddr(link_type, addr_type);
3894 ev.passkey = __cpu_to_le32(passkey);
3895 ev.entered = entered;
3896
3897 return mgmt_event(MGMT_EV_PASSKEY_NOTIFY, hdev, &ev, sizeof(ev), NULL);
3898}
3899
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003900int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003901 u8 addr_type, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03003902{
3903 struct mgmt_ev_auth_failed ev;
3904
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003905 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003906 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003907 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03003908
Johan Hedberg744cf192011-11-08 20:40:14 +02003909 return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03003910}
Johan Hedbergb312b1612011-03-16 14:29:37 +02003911
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003912int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
3913{
3914 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg47990ea2012-02-22 11:58:37 +02003915 bool changed = false;
3916 int err = 0;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003917
3918 if (status) {
3919 u8 mgmt_err = mgmt_status(status);
3920 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003921 cmd_status_rsp, &mgmt_err);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003922 return 0;
3923 }
3924
Johan Hedberg47990ea2012-02-22 11:58:37 +02003925 if (test_bit(HCI_AUTH, &hdev->flags)) {
3926 if (!test_and_set_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
3927 changed = true;
3928 } else {
3929 if (test_and_clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
3930 changed = true;
3931 }
3932
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003933 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003934 &match);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003935
Johan Hedberg47990ea2012-02-22 11:58:37 +02003936 if (changed)
3937 err = new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003938
3939 if (match.sk)
3940 sock_put(match.sk);
3941
3942 return err;
3943}
3944
Johan Hedberg890ea892013-03-15 17:06:52 -05003945static void clear_eir(struct hci_request *req)
Johan Hedbergcacaf522012-02-21 00:52:42 +02003946{
Johan Hedberg890ea892013-03-15 17:06:52 -05003947 struct hci_dev *hdev = req->hdev;
Johan Hedbergcacaf522012-02-21 00:52:42 +02003948 struct hci_cp_write_eir cp;
3949
Johan Hedberg976eb202012-10-24 21:12:01 +03003950 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05003951 return;
Johan Hedbergcacaf522012-02-21 00:52:42 +02003952
Johan Hedbergc80da272012-02-22 15:38:48 +02003953 memset(hdev->eir, 0, sizeof(hdev->eir));
3954
Johan Hedbergcacaf522012-02-21 00:52:42 +02003955 memset(&cp, 0, sizeof(cp));
3956
Johan Hedberg890ea892013-03-15 17:06:52 -05003957 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedbergcacaf522012-02-21 00:52:42 +02003958}
3959
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003960int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003961{
3962 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg890ea892013-03-15 17:06:52 -05003963 struct hci_request req;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003964 bool changed = false;
3965 int err = 0;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003966
3967 if (status) {
3968 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003969
3970 if (enable && test_and_clear_bit(HCI_SSP_ENABLED,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003971 &hdev->dev_flags))
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003972 err = new_settings(hdev, NULL);
3973
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003974 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
3975 &mgmt_err);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003976
3977 return err;
3978 }
3979
3980 if (enable) {
3981 if (!test_and_set_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3982 changed = true;
3983 } else {
3984 if (test_and_clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3985 changed = true;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003986 }
3987
3988 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
3989
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003990 if (changed)
3991 err = new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003992
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02003993 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003994 sock_put(match.sk);
3995
Johan Hedberg890ea892013-03-15 17:06:52 -05003996 hci_req_init(&req, hdev);
3997
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02003998 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05003999 update_eir(&req);
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004000 else
Johan Hedberg890ea892013-03-15 17:06:52 -05004001 clear_eir(&req);
4002
4003 hci_req_run(&req, NULL);
Johan Hedbergcacaf522012-02-21 00:52:42 +02004004
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004005 return err;
4006}
4007
Johan Hedberg92da6092013-03-15 17:06:55 -05004008static void sk_lookup(struct pending_cmd *cmd, void *data)
Johan Hedberg90e70452012-02-23 23:09:40 +02004009{
4010 struct cmd_lookup *match = data;
4011
Johan Hedberg90e70452012-02-23 23:09:40 +02004012 if (match->sk == NULL) {
4013 match->sk = cmd->sk;
4014 sock_hold(match->sk);
4015 }
Johan Hedberg90e70452012-02-23 23:09:40 +02004016}
4017
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004018int mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004019 u8 status)
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004020{
Johan Hedberg90e70452012-02-23 23:09:40 +02004021 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
4022 int err = 0;
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004023
Johan Hedberg92da6092013-03-15 17:06:55 -05004024 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, sk_lookup, &match);
4025 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, sk_lookup, &match);
4026 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, sk_lookup, &match);
Johan Hedberg90e70452012-02-23 23:09:40 +02004027
4028 if (!status)
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004029 err = mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class,
4030 3, NULL);
Johan Hedberg90e70452012-02-23 23:09:40 +02004031
4032 if (match.sk)
4033 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004034
4035 return err;
4036}
4037
Johan Hedberg744cf192011-11-08 20:40:14 +02004038int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02004039{
Johan Hedbergb312b1612011-03-16 14:29:37 +02004040 struct mgmt_cp_set_local_name ev;
Johan Hedberg13928972013-03-15 17:07:00 -05004041 struct pending_cmd *cmd;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02004042
Johan Hedberg13928972013-03-15 17:07:00 -05004043 if (status)
4044 return 0;
Johan Hedbergb312b1612011-03-16 14:29:37 +02004045
4046 memset(&ev, 0, sizeof(ev));
4047 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02004048 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02004049
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004050 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05004051 if (!cmd) {
4052 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
Johan Hedbergb312b1612011-03-16 14:29:37 +02004053
Johan Hedberg13928972013-03-15 17:07:00 -05004054 /* If this is a HCI command related to powering on the
4055 * HCI dev don't send any mgmt signals.
4056 */
4057 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev))
4058 return 0;
Johan Hedbergb312b1612011-03-16 14:29:37 +02004059 }
4060
Johan Hedberg13928972013-03-15 17:07:00 -05004061 return mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
4062 cmd ? cmd->sk : NULL);
Johan Hedbergb312b1612011-03-16 14:29:37 +02004063}
Szymon Jancc35938b2011-03-22 13:12:21 +01004064
Johan Hedberg744cf192011-11-08 20:40:14 +02004065int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004066 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01004067{
4068 struct pending_cmd *cmd;
4069 int err;
4070
Johan Hedberg744cf192011-11-08 20:40:14 +02004071 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01004072
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004073 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01004074 if (!cmd)
4075 return -ENOENT;
4076
4077 if (status) {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004078 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
4079 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01004080 } else {
4081 struct mgmt_rp_read_local_oob_data rp;
4082
4083 memcpy(rp.hash, hash, sizeof(rp.hash));
4084 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
4085
Johan Hedberg744cf192011-11-08 20:40:14 +02004086 err = cmd_complete(cmd->sk, hdev->id,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004087 MGMT_OP_READ_LOCAL_OOB_DATA, 0, &rp,
4088 sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01004089 }
4090
4091 mgmt_pending_remove(cmd);
4092
4093 return err;
4094}
Johan Hedberge17acd42011-03-30 23:57:16 +03004095
Johan Hedberg06199cf2012-02-22 16:37:11 +02004096int mgmt_le_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
4097{
4098 struct cmd_lookup match = { NULL, hdev };
4099 bool changed = false;
4100 int err = 0;
4101
4102 if (status) {
4103 u8 mgmt_err = mgmt_status(status);
4104
4105 if (enable && test_and_clear_bit(HCI_LE_ENABLED,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004106 &hdev->dev_flags))
Szymon Jancd97dcb62012-03-16 16:02:56 +01004107 err = new_settings(hdev, NULL);
Johan Hedberg06199cf2012-02-22 16:37:11 +02004108
Szymon Jancd97dcb62012-03-16 16:02:56 +01004109 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, cmd_status_rsp,
4110 &mgmt_err);
Johan Hedberg06199cf2012-02-22 16:37:11 +02004111
4112 return err;
4113 }
4114
4115 if (enable) {
4116 if (!test_and_set_bit(HCI_LE_ENABLED, &hdev->dev_flags))
4117 changed = true;
4118 } else {
4119 if (test_and_clear_bit(HCI_LE_ENABLED, &hdev->dev_flags))
4120 changed = true;
4121 }
4122
4123 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
4124
4125 if (changed)
4126 err = new_settings(hdev, match.sk);
4127
4128 if (match.sk)
4129 sock_put(match.sk);
4130
4131 return err;
4132}
4133
Johan Hedberg48264f02011-11-09 13:58:58 +02004134int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004135 u8 addr_type, u8 *dev_class, s8 rssi, u8 cfm_name, u8
4136 ssp, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03004137{
Johan Hedberge319d2e2012-01-15 19:51:59 +02004138 char buf[512];
4139 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02004140 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03004141
Johan Hedberg1dc06092012-01-15 21:01:23 +02004142 /* Leave 5 bytes for a potential CoD field */
4143 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Andre Guedes7d262f82012-01-10 18:20:49 -03004144 return -EINVAL;
4145
Johan Hedberg1dc06092012-01-15 21:01:23 +02004146 memset(buf, 0, sizeof(buf));
4147
Johan Hedberge319d2e2012-01-15 19:51:59 +02004148 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004149 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberge319d2e2012-01-15 19:51:59 +02004150 ev->rssi = rssi;
Johan Hedberg9a395a82012-02-23 00:00:32 +02004151 if (cfm_name)
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05304152 ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_CONFIRM_NAME);
Johan Hedberg388fc8f2012-02-23 00:38:59 +02004153 if (!ssp)
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05304154 ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_LEGACY_PAIRING);
Johan Hedberge17acd42011-03-30 23:57:16 +03004155
Johan Hedberg1dc06092012-01-15 21:01:23 +02004156 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02004157 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03004158
Johan Hedberg1dc06092012-01-15 21:01:23 +02004159 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
4160 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004161 dev_class, 3);
Johan Hedberg1dc06092012-01-15 21:01:23 +02004162
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004163 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedberg1dc06092012-01-15 21:01:23 +02004164 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03004165
Johan Hedberge319d2e2012-01-15 19:51:59 +02004166 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03004167}
Johan Hedberga88a9652011-03-30 13:18:12 +03004168
Johan Hedbergb644ba32012-01-17 21:48:47 +02004169int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004170 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03004171{
Johan Hedbergb644ba32012-01-17 21:48:47 +02004172 struct mgmt_ev_device_found *ev;
4173 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
4174 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03004175
Johan Hedbergb644ba32012-01-17 21:48:47 +02004176 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03004177
Johan Hedbergb644ba32012-01-17 21:48:47 +02004178 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03004179
Johan Hedbergb644ba32012-01-17 21:48:47 +02004180 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004181 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004182 ev->rssi = rssi;
4183
4184 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004185 name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004186
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004187 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004188
Johan Hedberg053c7e02012-02-04 00:06:00 +02004189 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004190 sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03004191}
Johan Hedberg314b2382011-04-27 10:29:57 -04004192
Andre Guedes7a135102011-11-09 17:14:25 -03004193int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
Johan Hedberg164a6e72011-11-01 17:06:44 +02004194{
4195 struct pending_cmd *cmd;
Johan Hedbergf808e162012-02-19 12:52:07 +02004196 u8 type;
Johan Hedberg164a6e72011-11-01 17:06:44 +02004197 int err;
4198
Andre Guedes203159d2012-02-13 15:41:01 -03004199 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
4200
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004201 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02004202 if (!cmd)
4203 return -ENOENT;
4204
Johan Hedbergf808e162012-02-19 12:52:07 +02004205 type = hdev->discovery.type;
4206
4207 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004208 &type, sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02004209 mgmt_pending_remove(cmd);
4210
4211 return err;
4212}
4213
Andre Guedese6d465c2011-11-09 17:14:26 -03004214int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
4215{
4216 struct pending_cmd *cmd;
4217 int err;
4218
4219 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
4220 if (!cmd)
4221 return -ENOENT;
4222
Johan Hedbergd9306502012-02-20 23:25:18 +02004223 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004224 &hdev->discovery.type, sizeof(hdev->discovery.type));
Johan Hedberg03811012010-12-08 00:21:06 +02004225 mgmt_pending_remove(cmd);
4226
4227 return err;
4228}
Johan Hedberg314b2382011-04-27 10:29:57 -04004229
Johan Hedberg744cf192011-11-08 20:40:14 +02004230int mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04004231{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02004232 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02004233 struct pending_cmd *cmd;
4234
Andre Guedes343fb142011-11-22 17:14:19 -03004235 BT_DBG("%s discovering %u", hdev->name, discovering);
4236
Johan Hedberg164a6e72011-11-01 17:06:44 +02004237 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004238 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02004239 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004240 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02004241
4242 if (cmd != NULL) {
Johan Hedbergf808e162012-02-19 12:52:07 +02004243 u8 type = hdev->discovery.type;
4244
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004245 cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0, &type,
4246 sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02004247 mgmt_pending_remove(cmd);
4248 }
4249
Johan Hedbergf963e8e2012-02-20 23:30:44 +02004250 memset(&ev, 0, sizeof(ev));
4251 ev.type = hdev->discovery.type;
4252 ev.discovering = discovering;
4253
4254 return mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04004255}
Antti Julku5e762442011-08-25 16:48:02 +03004256
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004257int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03004258{
4259 struct pending_cmd *cmd;
4260 struct mgmt_ev_device_blocked ev;
4261
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004262 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03004263
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004264 bacpy(&ev.addr.bdaddr, bdaddr);
4265 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03004266
Johan Hedberg744cf192011-11-08 20:40:14 +02004267 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004268 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03004269}
4270
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004271int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03004272{
4273 struct pending_cmd *cmd;
4274 struct mgmt_ev_device_unblocked ev;
4275
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004276 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03004277
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004278 bacpy(&ev.addr.bdaddr, bdaddr);
4279 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03004280
Johan Hedberg744cf192011-11-08 20:40:14 +02004281 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004282 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03004283}
Marcel Holtmannd7b7e792012-02-20 21:47:49 +01004284
4285module_param(enable_hs, bool, 0644);
4286MODULE_PARM_DESC(enable_hs, "Enable High Speed support");