blob: 4c830c62ef7412a8b4888b7a775b68117591240a [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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-12-13 21:07:06 +0200217
Andre Guedes790eff42012-06-07 19:05:46 -0300218 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_KERNEL);
Johan Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-12-13 21:07:06 +0200234 kfree_skb(skb);
235
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300236 return err;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200237}
238
Johan Hedbergaee9b212012-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 Hedbergaee9b212012-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 Hedbergaee9b212012-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 Hedbergaee9b212012-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 Hedbergaee9b212012-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergaee9b212012-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 Hedbergf7b64e692010-12-13 21:07:06 +0200921
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300922 hci_dev_lock(hdev);
Johan Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedberg13ecd8b2013-01-09 15:29:38 +02001354 hci_dev_lock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001355
1356 val = !!cp->val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001357 enabled = lmp_host_le_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001358
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001359 if (!hdev_is_powered(hdev) || val == enabled) {
Johan Hedberg06199cf2012-02-22 16:37:11 +02001360 bool changed = false;
1361
1362 if (val != test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
1363 change_bit(HCI_LE_ENABLED, &hdev->dev_flags);
1364 changed = true;
1365 }
1366
1367 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1368 if (err < 0)
Johan Hedberg1de028c2012-02-29 19:55:35 -08001369 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001370
1371 if (changed)
1372 err = new_settings(hdev, sk);
1373
Johan Hedberg1de028c2012-02-29 19:55:35 -08001374 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001375 }
1376
1377 if (mgmt_pending_find(MGMT_OP_SET_LE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001378 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001379 MGMT_STATUS_BUSY);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001380 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001381 }
1382
1383 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
1384 if (!cmd) {
1385 err = -ENOMEM;
Johan Hedberg1de028c2012-02-29 19:55:35 -08001386 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001387 }
1388
1389 memset(&hci_cp, 0, sizeof(hci_cp));
1390
1391 if (val) {
1392 hci_cp.le = val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001393 hci_cp.simul = lmp_le_br_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001394 }
1395
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001396 err = hci_send_cmd(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp),
1397 &hci_cp);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05301398 if (err < 0)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001399 mgmt_pending_remove(cmd);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001400
Johan Hedberg1de028c2012-02-29 19:55:35 -08001401unlock:
1402 hci_dev_unlock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001403 return err;
1404}
1405
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001406/* This is a helper function to test for pending mgmt commands that can
1407 * cause CoD or EIR HCI commands. We can only allow one such pending
1408 * mgmt command at a time since otherwise we cannot easily track what
1409 * the current values are, will be, and based on that calculate if a new
1410 * HCI command needs to be sent and if yes with what value.
1411 */
1412static bool pending_eir_or_class(struct hci_dev *hdev)
1413{
1414 struct pending_cmd *cmd;
1415
1416 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
1417 switch (cmd->opcode) {
1418 case MGMT_OP_ADD_UUID:
1419 case MGMT_OP_REMOVE_UUID:
1420 case MGMT_OP_SET_DEV_CLASS:
1421 case MGMT_OP_SET_POWERED:
1422 return true;
1423 }
1424 }
1425
1426 return false;
1427}
1428
Johan Hedberg83be8ec2013-01-27 00:31:29 +02001429static const u8 bluetooth_base_uuid[] = {
1430 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
1431 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1432};
1433
1434static u8 get_uuid_size(const u8 *uuid)
1435{
1436 u32 val;
1437
1438 if (memcmp(uuid, bluetooth_base_uuid, 12))
1439 return 128;
1440
1441 val = get_unaligned_le32(&uuid[12]);
1442 if (val > 0xffff)
1443 return 32;
1444
1445 return 16;
1446}
1447
Johan Hedberg92da6092013-03-15 17:06:55 -05001448static void mgmt_class_complete(struct hci_dev *hdev, u16 mgmt_op, u8 status)
1449{
1450 struct pending_cmd *cmd;
1451
1452 hci_dev_lock(hdev);
1453
1454 cmd = mgmt_pending_find(mgmt_op, hdev);
1455 if (!cmd)
1456 goto unlock;
1457
1458 cmd_complete(cmd->sk, cmd->index, cmd->opcode, mgmt_status(status),
1459 hdev->dev_class, 3);
1460
1461 mgmt_pending_remove(cmd);
1462
1463unlock:
1464 hci_dev_unlock(hdev);
1465}
1466
1467static void add_uuid_complete(struct hci_dev *hdev, u8 status)
1468{
1469 BT_DBG("status 0x%02x", status);
1470
1471 mgmt_class_complete(hdev, MGMT_OP_ADD_UUID, status);
1472}
1473
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001474static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001475{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001476 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001477 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05001478 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001479 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001480 int err;
1481
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001482 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001483
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001484 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001485
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001486 if (pending_eir_or_class(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001487 err = cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001488 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001489 goto failed;
1490 }
1491
Andre Guedes92c4c202012-06-07 19:05:44 -03001492 uuid = kmalloc(sizeof(*uuid), GFP_KERNEL);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001493 if (!uuid) {
1494 err = -ENOMEM;
1495 goto failed;
1496 }
1497
1498 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001499 uuid->svc_hint = cp->svc_hint;
Johan Hedberg83be8ec2013-01-27 00:31:29 +02001500 uuid->size = get_uuid_size(cp->uuid);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001501
Johan Hedbergde66aa62013-01-27 00:31:27 +02001502 list_add_tail(&uuid->list, &hdev->uuids);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001503
Johan Hedberg890ea892013-03-15 17:06:52 -05001504 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001505
Johan Hedberg890ea892013-03-15 17:06:52 -05001506 update_class(&req);
1507 update_eir(&req);
1508
Johan Hedberg92da6092013-03-15 17:06:55 -05001509 err = hci_req_run(&req, add_uuid_complete);
1510 if (err < 0) {
1511 if (err != -ENODATA)
1512 goto failed;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001513
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001514 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001515 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001516 goto failed;
1517 }
1518
1519 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05001520 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02001521 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05001522 goto failed;
1523 }
1524
1525 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001526
1527failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001528 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001529 return err;
1530}
1531
Johan Hedberg24b78d02012-02-23 23:24:30 +02001532static bool enable_service_cache(struct hci_dev *hdev)
1533{
1534 if (!hdev_is_powered(hdev))
1535 return false;
1536
1537 if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg46818ed2013-01-14 22:33:52 +02001538 queue_delayed_work(hdev->workqueue, &hdev->service_cache,
1539 CACHE_TIMEOUT);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001540 return true;
1541 }
1542
1543 return false;
1544}
1545
Johan Hedberg92da6092013-03-15 17:06:55 -05001546static void remove_uuid_complete(struct hci_dev *hdev, u8 status)
1547{
1548 BT_DBG("status 0x%02x", status);
1549
1550 mgmt_class_complete(hdev, MGMT_OP_REMOVE_UUID, status);
1551}
1552
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001553static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001554 u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001555{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001556 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001557 struct pending_cmd *cmd;
Johan Hedberg056341c2013-01-27 00:31:30 +02001558 struct bt_uuid *match, *tmp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001559 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 -05001560 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001561 int err, found;
1562
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001563 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001564
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001565 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001566
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001567 if (pending_eir_or_class(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001568 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001569 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001570 goto unlock;
1571 }
1572
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001573 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
1574 err = hci_uuids_clear(hdev);
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001575
Johan Hedberg24b78d02012-02-23 23:24:30 +02001576 if (enable_service_cache(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001577 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001578 0, hdev->dev_class, 3);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001579 goto unlock;
1580 }
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001581
Johan Hedberg9246a862012-02-23 21:33:16 +02001582 goto update_class;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001583 }
1584
1585 found = 0;
1586
Johan Hedberg056341c2013-01-27 00:31:30 +02001587 list_for_each_entry_safe(match, tmp, &hdev->uuids, list) {
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001588 if (memcmp(match->uuid, cp->uuid, 16) != 0)
1589 continue;
1590
1591 list_del(&match->list);
Johan Hedberg482049f2012-11-08 10:25:26 +01001592 kfree(match);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001593 found++;
1594 }
1595
1596 if (found == 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001597 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001598 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001599 goto unlock;
1600 }
1601
Johan Hedberg9246a862012-02-23 21:33:16 +02001602update_class:
Johan Hedberg890ea892013-03-15 17:06:52 -05001603 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001604
Johan Hedberg890ea892013-03-15 17:06:52 -05001605 update_class(&req);
1606 update_eir(&req);
1607
Johan Hedberg92da6092013-03-15 17:06:55 -05001608 err = hci_req_run(&req, remove_uuid_complete);
1609 if (err < 0) {
1610 if (err != -ENODATA)
1611 goto unlock;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001612
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001613 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001614 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001615 goto unlock;
1616 }
1617
1618 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05001619 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02001620 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05001621 goto unlock;
1622 }
1623
1624 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001625
1626unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001627 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001628 return err;
1629}
1630
Johan Hedberg92da6092013-03-15 17:06:55 -05001631static void set_class_complete(struct hci_dev *hdev, u8 status)
1632{
1633 BT_DBG("status 0x%02x", status);
1634
1635 mgmt_class_complete(hdev, MGMT_OP_SET_DEV_CLASS, status);
1636}
1637
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001638static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001639 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001640{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001641 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001642 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05001643 struct hci_request req;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001644 int err;
1645
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001646 BT_DBG("request for %s", hdev->name);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001647
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001648 if (!lmp_bredr_capable(hdev))
1649 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
1650 MGMT_STATUS_NOT_SUPPORTED);
1651
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001652 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001653
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001654 if (pending_eir_or_class(hdev)) {
1655 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
1656 MGMT_STATUS_BUSY);
1657 goto unlock;
1658 }
1659
1660 if ((cp->minor & 0x03) != 0 || (cp->major & 0xe0) != 0) {
1661 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
1662 MGMT_STATUS_INVALID_PARAMS);
1663 goto unlock;
1664 }
1665
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001666 hdev->major_class = cp->major;
1667 hdev->minor_class = cp->minor;
1668
Johan Hedberg932f5ff2012-02-22 22:11:32 +02001669 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001670 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001671 hdev->dev_class, 3);
Johan Hedberg932f5ff2012-02-22 22:11:32 +02001672 goto unlock;
1673 }
1674
Johan Hedberg890ea892013-03-15 17:06:52 -05001675 hci_req_init(&req, hdev);
1676
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001677 if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02001678 hci_dev_unlock(hdev);
1679 cancel_delayed_work_sync(&hdev->service_cache);
1680 hci_dev_lock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -05001681 update_eir(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +02001682 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02001683
Johan Hedberg890ea892013-03-15 17:06:52 -05001684 update_class(&req);
1685
Johan Hedberg92da6092013-03-15 17:06:55 -05001686 err = hci_req_run(&req, set_class_complete);
1687 if (err < 0) {
1688 if (err != -ENODATA)
1689 goto unlock;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001690
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001691 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001692 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001693 goto unlock;
1694 }
1695
1696 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05001697 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02001698 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05001699 goto unlock;
1700 }
1701
1702 err = 0;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001703
Johan Hedbergb5235a62012-02-21 14:32:24 +02001704unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001705 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001706 return err;
1707}
1708
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001709static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001710 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001711{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001712 struct mgmt_cp_load_link_keys *cp = data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001713 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001714 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001715
Marcel Holtmann1f350c82012-03-12 20:31:08 -07001716 key_count = __le16_to_cpu(cp->key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001717
Johan Hedberg86742e12011-11-07 23:13:38 +02001718 expected_len = sizeof(*cp) + key_count *
1719 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001720 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001721 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001722 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001723 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001724 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001725 }
1726
Johan Hedberg4ae143012013-01-20 14:27:13 +02001727 if (cp->debug_keys != 0x00 && cp->debug_keys != 0x01)
1728 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
1729 MGMT_STATUS_INVALID_PARAMS);
1730
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001731 BT_DBG("%s debug_keys %u key_count %u", hdev->name, cp->debug_keys,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001732 key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001733
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001734 for (i = 0; i < key_count; i++) {
1735 struct mgmt_link_key_info *key = &cp->keys[i];
1736
1737 if (key->addr.type != BDADDR_BREDR)
1738 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
1739 MGMT_STATUS_INVALID_PARAMS);
1740 }
1741
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001742 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001743
1744 hci_link_keys_clear(hdev);
1745
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001746 set_bit(HCI_LINK_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001747
1748 if (cp->debug_keys)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001749 set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001750 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001751 clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001752
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001753 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001754 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001755
Johan Hedbergd753fdc2012-02-17 14:06:34 +02001756 hci_add_link_key(hdev, NULL, 0, &key->addr.bdaddr, key->val,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001757 key->type, key->pin_len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001758 }
1759
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001760 cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02001761
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001762 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001763
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001764 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001765}
1766
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001767static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001768 u8 addr_type, struct sock *skip_sk)
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001769{
1770 struct mgmt_ev_device_unpaired ev;
1771
1772 bacpy(&ev.addr.bdaddr, bdaddr);
1773 ev.addr.type = addr_type;
1774
1775 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001776 skip_sk);
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001777}
1778
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001779static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001780 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001781{
Johan Hedberg124f6e32012-02-09 13:50:12 +02001782 struct mgmt_cp_unpair_device *cp = data;
1783 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001784 struct hci_cp_disconnect dc;
1785 struct pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001786 struct hci_conn *conn;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001787 int err;
1788
Johan Hedberga8a1d192011-11-10 15:54:38 +02001789 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02001790 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1791 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001792
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001793 if (!bdaddr_type_is_valid(cp->addr.type))
1794 return cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
1795 MGMT_STATUS_INVALID_PARAMS,
1796 &rp, sizeof(rp));
1797
Johan Hedberg118da702013-01-20 14:27:20 +02001798 if (cp->disconnect != 0x00 && cp->disconnect != 0x01)
1799 return cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
1800 MGMT_STATUS_INVALID_PARAMS,
1801 &rp, sizeof(rp));
1802
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001803 hci_dev_lock(hdev);
1804
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001805 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001806 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001807 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001808 goto unlock;
1809 }
1810
Andre Guedes591f47f2012-04-24 21:02:49 -03001811 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg124f6e32012-02-09 13:50:12 +02001812 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
1813 else
1814 err = hci_remove_ltk(hdev, &cp->addr.bdaddr);
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03001815
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001816 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001817 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001818 MGMT_STATUS_NOT_PAIRED, &rp, sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001819 goto unlock;
1820 }
1821
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001822 if (cp->disconnect) {
Andre Guedes591f47f2012-04-24 21:02:49 -03001823 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001824 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001825 &cp->addr.bdaddr);
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001826 else
1827 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001828 &cp->addr.bdaddr);
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001829 } else {
1830 conn = NULL;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001831 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001832
Johan Hedberga8a1d192011-11-10 15:54:38 +02001833 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001834 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001835 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001836 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001837 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001838 }
1839
Johan Hedberg124f6e32012-02-09 13:50:12 +02001840 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001841 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02001842 if (!cmd) {
1843 err = -ENOMEM;
1844 goto unlock;
1845 }
1846
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02001847 dc.handle = cpu_to_le16(conn->handle);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001848 dc.reason = 0x13; /* Remote User Terminated Connection */
1849 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1850 if (err < 0)
1851 mgmt_pending_remove(cmd);
1852
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001853unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001854 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001855 return err;
1856}
1857
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001858static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001859 u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02001860{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001861 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg06a63b12013-01-20 14:27:21 +02001862 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001863 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03001864 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001865 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001866 int err;
1867
1868 BT_DBG("");
1869
Johan Hedberg06a63b12013-01-20 14:27:21 +02001870 memset(&rp, 0, sizeof(rp));
1871 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1872 rp.addr.type = cp->addr.type;
1873
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001874 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg06a63b12013-01-20 14:27:21 +02001875 return cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
1876 MGMT_STATUS_INVALID_PARAMS,
1877 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001878
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001879 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001880
1881 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02001882 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
1883 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02001884 goto failed;
1885 }
1886
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001887 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02001888 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
1889 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02001890 goto failed;
1891 }
1892
Andre Guedes591f47f2012-04-24 21:02:49 -03001893 if (cp->addr.type == BDADDR_BREDR)
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03001894 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
1895 &cp->addr.bdaddr);
Johan Hedberg88c3df12012-02-09 14:27:38 +02001896 else
1897 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03001898
Vishal Agarwalf9607272012-06-13 05:32:43 +05301899 if (!conn || conn->state == BT_OPEN || conn->state == BT_CLOSED) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02001900 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
1901 MGMT_STATUS_NOT_CONNECTED, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02001902 goto failed;
1903 }
1904
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001905 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001906 if (!cmd) {
1907 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001908 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001909 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001910
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02001911 dc.handle = cpu_to_le16(conn->handle);
Andre Guedes3701f942012-06-11 18:41:12 -03001912 dc.reason = HCI_ERROR_REMOTE_USER_TERM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001913
1914 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1915 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001916 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001917
1918failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001919 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001920 return err;
1921}
1922
Andre Guedes57c14772012-04-24 21:02:50 -03001923static u8 link_to_bdaddr(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02001924{
1925 switch (link_type) {
1926 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02001927 switch (addr_type) {
1928 case ADDR_LE_DEV_PUBLIC:
Andre Guedes591f47f2012-04-24 21:02:49 -03001929 return BDADDR_LE_PUBLIC;
Andre Guedes0ed09142012-04-03 08:46:54 -03001930
Johan Hedberg48264f02011-11-09 13:58:58 +02001931 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03001932 /* Fallback to LE Random address type */
Andre Guedes591f47f2012-04-24 21:02:49 -03001933 return BDADDR_LE_RANDOM;
Johan Hedberg48264f02011-11-09 13:58:58 +02001934 }
Andre Guedes0ed09142012-04-03 08:46:54 -03001935
Johan Hedberg4c659c32011-11-07 23:13:39 +02001936 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03001937 /* Fallback to BR/EDR type */
Andre Guedes591f47f2012-04-24 21:02:49 -03001938 return BDADDR_BREDR;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001939 }
1940}
1941
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001942static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data,
1943 u16 data_len)
Johan Hedberg2784eb42011-01-21 13:56:35 +02001944{
Johan Hedberg2784eb42011-01-21 13:56:35 +02001945 struct mgmt_rp_get_connections *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001946 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02001947 size_t rp_len;
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001948 int err;
1949 u16 i;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001950
1951 BT_DBG("");
1952
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001953 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001954
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001955 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001956 err = cmd_status(sk, hdev->id, MGMT_OP_GET_CONNECTIONS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001957 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001958 goto unlock;
1959 }
1960
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001961 i = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02001962 list_for_each_entry(c, &hdev->conn_hash.list, list) {
1963 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001964 i++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001965 }
1966
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001967 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Andre Guedes92c4c202012-06-07 19:05:44 -03001968 rp = kmalloc(rp_len, GFP_KERNEL);
Johan Hedberga38528f2011-01-22 06:46:43 +02001969 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02001970 err = -ENOMEM;
1971 goto unlock;
1972 }
1973
Johan Hedberg2784eb42011-01-21 13:56:35 +02001974 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001975 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02001976 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
1977 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001978 bacpy(&rp->addr[i].bdaddr, &c->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03001979 rp->addr[i].type = link_to_bdaddr(c->type, c->dst_type);
Andre Guedes0ed09142012-04-03 08:46:54 -03001980 if (c->type == SCO_LINK || c->type == ESCO_LINK)
Johan Hedberg4c659c32011-11-07 23:13:39 +02001981 continue;
1982 i++;
1983 }
1984
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02001985 rp->conn_count = cpu_to_le16(i);
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001986
Johan Hedberg4c659c32011-11-07 23:13:39 +02001987 /* Recalculate length in case of filtered SCO connections, etc */
1988 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02001989
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001990 err = cmd_complete(sk, hdev->id, MGMT_OP_GET_CONNECTIONS, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001991 rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001992
Johan Hedberga38528f2011-01-22 06:46:43 +02001993 kfree(rp);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001994
1995unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001996 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001997 return err;
1998}
1999
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002000static int send_pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002001 struct mgmt_cp_pin_code_neg_reply *cp)
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002002{
2003 struct pending_cmd *cmd;
2004 int err;
2005
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002006 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002007 sizeof(*cp));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002008 if (!cmd)
2009 return -ENOMEM;
2010
Johan Hedbergd8457692012-02-17 14:24:57 +02002011 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002012 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002013 if (err < 0)
2014 mgmt_pending_remove(cmd);
2015
2016 return err;
2017}
2018
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002019static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002020 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002021{
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002022 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002023 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002024 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03002025 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002026 int err;
2027
2028 BT_DBG("");
2029
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002030 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002031
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002032 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002033 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002034 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002035 goto failed;
2036 }
2037
Johan Hedbergd8457692012-02-17 14:24:57 +02002038 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002039 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002040 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002041 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002042 goto failed;
2043 }
2044
2045 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02002046 struct mgmt_cp_pin_code_neg_reply ncp;
2047
2048 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002049
2050 BT_ERR("PIN code is not 16 bytes long");
2051
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002052 err = send_pin_code_neg_reply(sk, hdev, &ncp);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002053 if (err >= 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002054 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002055 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002056
2057 goto failed;
2058 }
2059
Gustavo F. Padovan00abfe42012-03-01 00:37:10 -03002060 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002061 if (!cmd) {
2062 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002063 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002064 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02002065
Johan Hedbergd8457692012-02-17 14:24:57 +02002066 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002067 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02002068 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002069
2070 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
2071 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002072 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002073
2074failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002075 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002076 return err;
2077}
2078
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002079static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,
2080 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002081{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002082 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002083
2084 BT_DBG("");
2085
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002086 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002087
2088 hdev->io_capability = cp->io_capability;
2089
2090 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002091 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002092
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002093 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002094
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002095 return cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, 0, NULL,
2096 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002097}
2098
Gustavo Padovan6039aa72012-05-23 04:04:18 -03002099static struct pending_cmd *find_pairing(struct hci_conn *conn)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002100{
2101 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002102 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002103
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002104 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03002105 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
2106 continue;
2107
Johan Hedberge9a416b2011-02-19 12:05:56 -03002108 if (cmd->user_data != conn)
2109 continue;
2110
2111 return cmd;
2112 }
2113
2114 return NULL;
2115}
2116
2117static void pairing_complete(struct pending_cmd *cmd, u8 status)
2118{
2119 struct mgmt_rp_pair_device rp;
2120 struct hci_conn *conn = cmd->user_data;
2121
Johan Hedbergba4e5642011-11-11 00:07:34 +02002122 bacpy(&rp.addr.bdaddr, &conn->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002123 rp.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002124
Johan Hedbergaee9b212012-02-18 15:07:59 +02002125 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002126 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002127
2128 /* So we don't get further callbacks for this connection */
2129 conn->connect_cfm_cb = NULL;
2130 conn->security_cfm_cb = NULL;
2131 conn->disconn_cfm_cb = NULL;
2132
David Herrmann76a68ba2013-04-06 20:28:37 +02002133 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002134
Johan Hedberga664b5b2011-02-19 12:06:02 -03002135 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002136}
2137
2138static void pairing_complete_cb(struct hci_conn *conn, u8 status)
2139{
2140 struct pending_cmd *cmd;
2141
2142 BT_DBG("status %u", status);
2143
Johan Hedberg56e5cb82011-11-08 20:40:16 +02002144 cmd = find_pairing(conn);
2145 if (!cmd)
2146 BT_DBG("Unable to find a pending command");
2147 else
Johan Hedberge2113262012-02-18 15:20:03 +02002148 pairing_complete(cmd, mgmt_status(status));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002149}
2150
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302151static void le_connect_complete_cb(struct hci_conn *conn, u8 status)
2152{
2153 struct pending_cmd *cmd;
2154
2155 BT_DBG("status %u", status);
2156
2157 if (!status)
2158 return;
2159
2160 cmd = find_pairing(conn);
2161 if (!cmd)
2162 BT_DBG("Unable to find a pending command");
2163 else
2164 pairing_complete(cmd, mgmt_status(status));
2165}
2166
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002167static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002168 u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002169{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002170 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02002171 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002172 struct pending_cmd *cmd;
2173 u8 sec_level, auth_type;
2174 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002175 int err;
2176
2177 BT_DBG("");
2178
Szymon Jancf950a30e2013-01-18 12:48:07 +01002179 memset(&rp, 0, sizeof(rp));
2180 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2181 rp.addr.type = cp->addr.type;
2182
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002183 if (!bdaddr_type_is_valid(cp->addr.type))
2184 return cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2185 MGMT_STATUS_INVALID_PARAMS,
2186 &rp, sizeof(rp));
2187
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002188 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002189
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002190 if (!hdev_is_powered(hdev)) {
Szymon Jancf950a30e2013-01-18 12:48:07 +01002191 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2192 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002193 goto unlock;
2194 }
2195
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002196 sec_level = BT_SECURITY_MEDIUM;
2197 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002198 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002199 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03002200 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002201
Andre Guedes591f47f2012-04-24 21:02:49 -03002202 if (cp->addr.type == BDADDR_BREDR)
Andre Guedesb12f62c2012-04-24 21:02:54 -03002203 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr,
2204 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002205 else
Andre Guedesb12f62c2012-04-24 21:02:54 -03002206 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr,
2207 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002208
Ville Tervo30e76272011-02-22 16:10:53 -03002209 if (IS_ERR(conn)) {
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002210 int status;
2211
2212 if (PTR_ERR(conn) == -EBUSY)
2213 status = MGMT_STATUS_BUSY;
2214 else
2215 status = MGMT_STATUS_CONNECT_FAILED;
2216
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002217 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002218 status, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002219 sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002220 goto unlock;
2221 }
2222
2223 if (conn->connect_cfm_cb) {
David Herrmann76a68ba2013-04-06 20:28:37 +02002224 hci_conn_drop(conn);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002225 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002226 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002227 goto unlock;
2228 }
2229
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002230 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002231 if (!cmd) {
2232 err = -ENOMEM;
David Herrmann76a68ba2013-04-06 20:28:37 +02002233 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002234 goto unlock;
2235 }
2236
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002237 /* For LE, just connecting isn't a proof that the pairing finished */
Andre Guedes591f47f2012-04-24 21:02:49 -03002238 if (cp->addr.type == BDADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002239 conn->connect_cfm_cb = pairing_complete_cb;
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302240 else
2241 conn->connect_cfm_cb = le_connect_complete_cb;
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002242
Johan Hedberge9a416b2011-02-19 12:05:56 -03002243 conn->security_cfm_cb = pairing_complete_cb;
2244 conn->disconn_cfm_cb = pairing_complete_cb;
2245 conn->io_capability = cp->io_cap;
2246 cmd->user_data = conn;
2247
2248 if (conn->state == BT_CONNECTED &&
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002249 hci_conn_security(conn, sec_level, auth_type))
Johan Hedberge9a416b2011-02-19 12:05:56 -03002250 pairing_complete(cmd, 0);
2251
2252 err = 0;
2253
2254unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002255 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002256 return err;
2257}
2258
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002259static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
2260 u16 len)
Johan Hedberg28424702012-02-02 04:02:29 +02002261{
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002262 struct mgmt_addr_info *addr = data;
Johan Hedberg28424702012-02-02 04:02:29 +02002263 struct pending_cmd *cmd;
2264 struct hci_conn *conn;
2265 int err;
2266
2267 BT_DBG("");
2268
Johan Hedberg28424702012-02-02 04:02:29 +02002269 hci_dev_lock(hdev);
2270
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002271 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002272 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002273 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002274 goto unlock;
2275 }
2276
Johan Hedberg28424702012-02-02 04:02:29 +02002277 cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
2278 if (!cmd) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002279 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002280 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002281 goto unlock;
2282 }
2283
2284 conn = cmd->user_data;
2285
2286 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002287 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002288 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002289 goto unlock;
2290 }
2291
2292 pairing_complete(cmd, MGMT_STATUS_CANCELLED);
2293
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002294 err = cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002295 addr, sizeof(*addr));
Johan Hedberg28424702012-02-02 04:02:29 +02002296unlock:
2297 hci_dev_unlock(hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02002298 return err;
2299}
2300
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002301static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
Johan Hedberg1707c602013-03-15 17:07:15 -05002302 struct mgmt_addr_info *addr, u16 mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002303 u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03002304{
Johan Hedberga5c29682011-02-19 12:05:57 -03002305 struct pending_cmd *cmd;
Brian Gix0df4c182011-11-16 13:53:13 -08002306 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03002307 int err;
2308
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002309 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02002310
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002311 if (!hdev_is_powered(hdev)) {
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002312 err = cmd_complete(sk, hdev->id, mgmt_op,
2313 MGMT_STATUS_NOT_POWERED, addr,
2314 sizeof(*addr));
Brian Gix0df4c182011-11-16 13:53:13 -08002315 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002316 }
2317
Johan Hedberg1707c602013-03-15 17:07:15 -05002318 if (addr->type == BDADDR_BREDR)
2319 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &addr->bdaddr);
Johan Hedberg272d90d2012-02-09 15:26:12 +02002320 else
Johan Hedberg1707c602013-03-15 17:07:15 -05002321 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &addr->bdaddr);
Brian Gix47c15e22011-11-16 13:53:14 -08002322
Johan Hedberg272d90d2012-02-09 15:26:12 +02002323 if (!conn) {
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002324 err = cmd_complete(sk, hdev->id, mgmt_op,
2325 MGMT_STATUS_NOT_CONNECTED, addr,
2326 sizeof(*addr));
Johan Hedberg272d90d2012-02-09 15:26:12 +02002327 goto done;
2328 }
2329
Johan Hedberg1707c602013-03-15 17:07:15 -05002330 if (addr->type == BDADDR_LE_PUBLIC || addr->type == BDADDR_LE_RANDOM) {
Brian Gix47c15e22011-11-16 13:53:14 -08002331 /* Continue with pairing via SMP */
Brian Gix5fe57d92011-12-21 16:12:13 -08002332 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix47c15e22011-11-16 13:53:14 -08002333
Brian Gix5fe57d92011-12-21 16:12:13 -08002334 if (!err)
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002335 err = cmd_complete(sk, hdev->id, mgmt_op,
2336 MGMT_STATUS_SUCCESS, addr,
2337 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08002338 else
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002339 err = cmd_complete(sk, hdev->id, mgmt_op,
2340 MGMT_STATUS_FAILED, addr,
2341 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08002342
Brian Gix47c15e22011-11-16 13:53:14 -08002343 goto done;
2344 }
2345
Johan Hedberg1707c602013-03-15 17:07:15 -05002346 cmd = mgmt_pending_add(sk, mgmt_op, hdev, addr, sizeof(*addr));
Johan Hedberga5c29682011-02-19 12:05:57 -03002347 if (!cmd) {
2348 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08002349 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002350 }
2351
Brian Gix0df4c182011-11-16 13:53:13 -08002352 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08002353 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
2354 struct hci_cp_user_passkey_reply cp;
2355
Johan Hedberg1707c602013-03-15 17:07:15 -05002356 bacpy(&cp.bdaddr, &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002357 cp.passkey = passkey;
2358 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
2359 } else
Johan Hedberg1707c602013-03-15 17:07:15 -05002360 err = hci_send_cmd(hdev, hci_op, sizeof(addr->bdaddr),
2361 &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002362
Johan Hedberga664b5b2011-02-19 12:06:02 -03002363 if (err < 0)
2364 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002365
Brian Gix0df4c182011-11-16 13:53:13 -08002366done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002367 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002368 return err;
2369}
2370
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302371static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
2372 void *data, u16 len)
2373{
2374 struct mgmt_cp_pin_code_neg_reply *cp = data;
2375
2376 BT_DBG("");
2377
Johan Hedberg1707c602013-03-15 17:07:15 -05002378 return user_pairing_resp(sk, hdev, &cp->addr,
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302379 MGMT_OP_PIN_CODE_NEG_REPLY,
2380 HCI_OP_PIN_CODE_NEG_REPLY, 0);
2381}
2382
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002383static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2384 u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002385{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002386 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002387
2388 BT_DBG("");
2389
2390 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002391 return cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002392 MGMT_STATUS_INVALID_PARAMS);
Brian Gix0df4c182011-11-16 13:53:13 -08002393
Johan Hedberg1707c602013-03-15 17:07:15 -05002394 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002395 MGMT_OP_USER_CONFIRM_REPLY,
2396 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002397}
2398
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002399static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002400 void *data, u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002401{
Johan Hedbergc9c26592011-12-15 00:47:41 +02002402 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002403
2404 BT_DBG("");
2405
Johan Hedberg1707c602013-03-15 17:07:15 -05002406 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002407 MGMT_OP_USER_CONFIRM_NEG_REPLY,
2408 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002409}
2410
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002411static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2412 u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002413{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002414 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002415
2416 BT_DBG("");
2417
Johan Hedberg1707c602013-03-15 17:07:15 -05002418 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002419 MGMT_OP_USER_PASSKEY_REPLY,
2420 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08002421}
2422
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002423static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002424 void *data, u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002425{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002426 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002427
2428 BT_DBG("");
2429
Johan Hedberg1707c602013-03-15 17:07:15 -05002430 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002431 MGMT_OP_USER_PASSKEY_NEG_REPLY,
2432 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08002433}
2434
Johan Hedberg13928972013-03-15 17:07:00 -05002435static void update_name(struct hci_request *req)
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002436{
Johan Hedberg13928972013-03-15 17:07:00 -05002437 struct hci_dev *hdev = req->hdev;
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002438 struct hci_cp_write_local_name cp;
2439
Johan Hedberg13928972013-03-15 17:07:00 -05002440 memcpy(cp.name, hdev->dev_name, sizeof(cp.name));
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002441
Johan Hedberg890ea892013-03-15 17:06:52 -05002442 hci_req_add(req, HCI_OP_WRITE_LOCAL_NAME, sizeof(cp), &cp);
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002443}
2444
Johan Hedberg13928972013-03-15 17:07:00 -05002445static void set_name_complete(struct hci_dev *hdev, u8 status)
2446{
2447 struct mgmt_cp_set_local_name *cp;
2448 struct pending_cmd *cmd;
2449
2450 BT_DBG("status 0x%02x", status);
2451
2452 hci_dev_lock(hdev);
2453
2454 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
2455 if (!cmd)
2456 goto unlock;
2457
2458 cp = cmd->param;
2459
2460 if (status)
2461 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
2462 mgmt_status(status));
2463 else
2464 cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
2465 cp, sizeof(*cp));
2466
2467 mgmt_pending_remove(cmd);
2468
2469unlock:
2470 hci_dev_unlock(hdev);
2471}
2472
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002473static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002474 u16 len)
Johan Hedbergb312b1612011-03-16 14:29:37 +02002475{
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002476 struct mgmt_cp_set_local_name *cp = data;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002477 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002478 struct hci_request req;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002479 int err;
2480
2481 BT_DBG("");
2482
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002483 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002484
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05002485 /* If the old values are the same as the new ones just return a
2486 * direct command complete event.
2487 */
2488 if (!memcmp(hdev->dev_name, cp->name, sizeof(hdev->dev_name)) &&
2489 !memcmp(hdev->short_name, cp->short_name,
2490 sizeof(hdev->short_name))) {
2491 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
2492 data, len);
2493 goto failed;
2494 }
2495
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002496 memcpy(hdev->short_name, cp->short_name, sizeof(hdev->short_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002497
Johan Hedbergb5235a62012-02-21 14:32:24 +02002498 if (!hdev_is_powered(hdev)) {
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002499 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002500
2501 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002502 data, len);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002503 if (err < 0)
2504 goto failed;
2505
2506 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data, len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002507 sk);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002508
Johan Hedbergb5235a62012-02-21 14:32:24 +02002509 goto failed;
2510 }
2511
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002512 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002513 if (!cmd) {
2514 err = -ENOMEM;
2515 goto failed;
2516 }
2517
Johan Hedberg13928972013-03-15 17:07:00 -05002518 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
2519
Johan Hedberg890ea892013-03-15 17:06:52 -05002520 hci_req_init(&req, hdev);
Johan Hedberg3f985052013-03-15 17:07:02 -05002521
2522 if (lmp_bredr_capable(hdev)) {
2523 update_name(&req);
2524 update_eir(&req);
2525 }
2526
2527 if (lmp_le_capable(hdev))
2528 hci_update_ad(&req);
2529
Johan Hedberg13928972013-03-15 17:07:00 -05002530 err = hci_req_run(&req, set_name_complete);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002531 if (err < 0)
2532 mgmt_pending_remove(cmd);
2533
2534failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002535 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002536 return err;
2537}
2538
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002539static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002540 void *data, u16 data_len)
Szymon Jancc35938b2011-03-22 13:12:21 +01002541{
Szymon Jancc35938b2011-03-22 13:12:21 +01002542 struct pending_cmd *cmd;
2543 int err;
2544
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002545 BT_DBG("%s", hdev->name);
Szymon Jancc35938b2011-03-22 13:12:21 +01002546
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002547 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002548
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002549 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002550 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002551 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002552 goto unlock;
2553 }
2554
Andre Guedes9a1a1992012-07-24 15:03:48 -03002555 if (!lmp_ssp_capable(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002556 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002557 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002558 goto unlock;
2559 }
2560
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002561 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002562 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002563 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01002564 goto unlock;
2565 }
2566
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002567 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01002568 if (!cmd) {
2569 err = -ENOMEM;
2570 goto unlock;
2571 }
2572
2573 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
2574 if (err < 0)
2575 mgmt_pending_remove(cmd);
2576
2577unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002578 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002579 return err;
2580}
2581
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002582static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002583 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002584{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002585 struct mgmt_cp_add_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002586 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002587 int err;
2588
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002589 BT_DBG("%s ", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01002590
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002591 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002592
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002593 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, cp->hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002594 cp->randomizer);
Szymon Janc2763eda2011-03-22 13:12:22 +01002595 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002596 status = MGMT_STATUS_FAILED;
Szymon Janc2763eda2011-03-22 13:12:22 +01002597 else
Szymon Janca6785be2012-12-13 15:11:21 +01002598 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002599
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002600 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002601 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002602
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002603 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002604 return err;
2605}
2606
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002607static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002608 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002609{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002610 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002611 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002612 int err;
2613
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002614 BT_DBG("%s", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01002615
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002616 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002617
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002618 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr);
Szymon Janc2763eda2011-03-22 13:12:22 +01002619 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002620 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01002621 else
Szymon Janca6785be2012-12-13 15:11:21 +01002622 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002623
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002624 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002625 status, &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002626
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002627 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002628 return err;
2629}
2630
Andre Guedes5e0452c2012-02-17 20:39:38 -03002631int mgmt_interleaved_discovery(struct hci_dev *hdev)
2632{
2633 int err;
2634
2635 BT_DBG("%s", hdev->name);
2636
2637 hci_dev_lock(hdev);
2638
2639 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR_LE);
2640 if (err < 0)
2641 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2642
2643 hci_dev_unlock(hdev);
2644
2645 return err;
2646}
2647
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002648static int start_discovery(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002649 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002650{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002651 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002652 struct pending_cmd *cmd;
Johan Hedberg14a53662011-04-27 10:29:56 -04002653 int err;
2654
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002655 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04002656
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002657 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002658
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002659 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002660 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002661 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02002662 goto failed;
2663 }
2664
Andre Guedes642be6c2012-03-21 00:03:37 -03002665 if (test_bit(HCI_PERIODIC_INQ, &hdev->dev_flags)) {
2666 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2667 MGMT_STATUS_BUSY);
2668 goto failed;
2669 }
2670
Johan Hedbergff9ef572012-01-04 14:23:45 +02002671 if (hdev->discovery.state != DISCOVERY_STOPPED) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002672 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002673 MGMT_STATUS_BUSY);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002674 goto failed;
2675 }
2676
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002677 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002678 if (!cmd) {
2679 err = -ENOMEM;
2680 goto failed;
2681 }
2682
Andre Guedes4aab14e2012-02-17 20:39:36 -03002683 hdev->discovery.type = cp->type;
2684
2685 switch (hdev->discovery.type) {
Andre Guedesf39799f2012-02-17 20:39:35 -03002686 case DISCOV_TYPE_BREDR:
Johan Hedberg04106752013-01-10 14:54:09 +02002687 if (!lmp_bredr_capable(hdev)) {
2688 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2689 MGMT_STATUS_NOT_SUPPORTED);
2690 mgmt_pending_remove(cmd);
2691 goto failed;
2692 }
2693
2694 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
Andre Guedesf39799f2012-02-17 20:39:35 -03002695 break;
2696
2697 case DISCOV_TYPE_LE:
Johan Hedberg04106752013-01-10 14:54:09 +02002698 if (!lmp_host_le_capable(hdev)) {
2699 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2700 MGMT_STATUS_NOT_SUPPORTED);
2701 mgmt_pending_remove(cmd);
2702 goto failed;
2703 }
2704
Andre Guedes5df480b2013-04-04 20:21:00 -03002705 err = hci_le_scan(hdev, LE_SCAN_ACTIVE, LE_SCAN_INT,
Johan Hedberg04106752013-01-10 14:54:09 +02002706 LE_SCAN_WIN, LE_SCAN_TIMEOUT_LE_ONLY);
Andre Guedesf39799f2012-02-17 20:39:35 -03002707 break;
2708
Andre Guedes5e0452c2012-02-17 20:39:38 -03002709 case DISCOV_TYPE_INTERLEAVED:
Johan Hedberg04106752013-01-10 14:54:09 +02002710 if (!lmp_host_le_capable(hdev) || !lmp_bredr_capable(hdev)) {
2711 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2712 MGMT_STATUS_NOT_SUPPORTED);
2713 mgmt_pending_remove(cmd);
2714 goto failed;
2715 }
2716
Andre Guedes5df480b2013-04-04 20:21:00 -03002717 err = hci_le_scan(hdev, LE_SCAN_ACTIVE, LE_SCAN_INT,
2718 LE_SCAN_WIN, LE_SCAN_TIMEOUT_BREDR_LE);
Andre Guedes5e0452c2012-02-17 20:39:38 -03002719 break;
2720
Andre Guedesf39799f2012-02-17 20:39:35 -03002721 default:
Johan Hedberg04106752013-01-10 14:54:09 +02002722 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2723 MGMT_STATUS_INVALID_PARAMS);
2724 mgmt_pending_remove(cmd);
2725 goto failed;
Andre Guedesf39799f2012-02-17 20:39:35 -03002726 }
Andre Guedes3fd24152012-02-03 17:48:01 -03002727
Johan Hedberg14a53662011-04-27 10:29:56 -04002728 if (err < 0)
2729 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002730 else
2731 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002732
2733failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002734 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002735 return err;
2736}
2737
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002738static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002739 u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002740{
Johan Hedbergd9306502012-02-20 23:25:18 +02002741 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002742 struct pending_cmd *cmd;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002743 struct hci_cp_remote_name_req_cancel cp;
2744 struct inquiry_entry *e;
Johan Hedberg14a53662011-04-27 10:29:56 -04002745 int err;
2746
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002747 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04002748
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002749 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002750
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002751 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002752 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002753 MGMT_STATUS_REJECTED, &mgmt_cp->type,
2754 sizeof(mgmt_cp->type));
Johan Hedbergd9306502012-02-20 23:25:18 +02002755 goto unlock;
2756 }
2757
2758 if (hdev->discovery.type != mgmt_cp->type) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002759 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002760 MGMT_STATUS_INVALID_PARAMS, &mgmt_cp->type,
2761 sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002762 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02002763 }
2764
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002765 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002766 if (!cmd) {
2767 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002768 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04002769 }
2770
Andre Guedese0d9727e2012-03-20 15:15:36 -03002771 switch (hdev->discovery.state) {
2772 case DISCOVERY_FINDING:
Andre Guedesc9ecc482012-03-15 16:52:08 -03002773 if (test_bit(HCI_INQUIRY, &hdev->flags))
2774 err = hci_cancel_inquiry(hdev);
2775 else
2776 err = hci_cancel_le_scan(hdev);
2777
Andre Guedese0d9727e2012-03-20 15:15:36 -03002778 break;
2779
2780 case DISCOVERY_RESOLVING:
2781 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002782 NAME_PENDING);
Andre Guedese0d9727e2012-03-20 15:15:36 -03002783 if (!e) {
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002784 mgmt_pending_remove(cmd);
Andre Guedese0d9727e2012-03-20 15:15:36 -03002785 err = cmd_complete(sk, hdev->id,
2786 MGMT_OP_STOP_DISCOVERY, 0,
2787 &mgmt_cp->type,
2788 sizeof(mgmt_cp->type));
2789 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2790 goto unlock;
2791 }
2792
2793 bacpy(&cp.bdaddr, &e->data.bdaddr);
2794 err = hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ_CANCEL,
2795 sizeof(cp), &cp);
2796
2797 break;
2798
2799 default:
2800 BT_DBG("unknown discovery state %u", hdev->discovery.state);
2801 err = -EFAULT;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002802 }
2803
Johan Hedberg14a53662011-04-27 10:29:56 -04002804 if (err < 0)
2805 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002806 else
2807 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002808
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002809unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002810 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002811 return err;
2812}
2813
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002814static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002815 u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02002816{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002817 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002818 struct inquiry_entry *e;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002819 int err;
2820
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002821 BT_DBG("%s", hdev->name);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002822
Johan Hedberg561aafb2012-01-04 13:31:59 +02002823 hci_dev_lock(hdev);
2824
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002825 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002826 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002827 MGMT_STATUS_FAILED);
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002828 goto failed;
2829 }
2830
Johan Hedberga198e7b2012-02-17 14:27:06 +02002831 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002832 if (!e) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002833 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002834 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002835 goto failed;
2836 }
2837
2838 if (cp->name_known) {
2839 e->name_state = NAME_KNOWN;
2840 list_del(&e->list);
2841 } else {
2842 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e20a2012-01-09 00:53:02 +02002843 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002844 }
2845
Johan Hedberge3846622013-01-09 15:29:33 +02002846 err = cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME, 0, &cp->addr,
2847 sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02002848
2849failed:
2850 hci_dev_unlock(hdev);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002851 return err;
2852}
2853
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002854static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002855 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002856{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002857 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002858 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03002859 int err;
2860
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002861 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03002862
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002863 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg5d0846d2013-01-20 14:27:22 +02002864 return cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE,
2865 MGMT_STATUS_INVALID_PARAMS,
2866 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002867
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002868 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002869
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002870 err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002871 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002872 status = MGMT_STATUS_FAILED;
Antti Julku7fbec222011-06-15 12:01:15 +03002873 else
Szymon Janca6785be2012-12-13 15:11:21 +01002874 status = MGMT_STATUS_SUCCESS;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002875
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002876 err = cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002877 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03002878
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002879 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002880
2881 return err;
2882}
2883
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002884static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002885 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002886{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002887 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002888 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03002889 int err;
2890
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002891 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03002892
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002893 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg5d0846d2013-01-20 14:27:22 +02002894 return cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE,
2895 MGMT_STATUS_INVALID_PARAMS,
2896 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002897
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002898 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002899
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002900 err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002901 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002902 status = MGMT_STATUS_INVALID_PARAMS;
Antti Julku7fbec222011-06-15 12:01:15 +03002903 else
Szymon Janca6785be2012-12-13 15:11:21 +01002904 status = MGMT_STATUS_SUCCESS;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002905
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002906 err = cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002907 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03002908
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002909 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002910
2911 return err;
2912}
2913
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07002914static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data,
2915 u16 len)
2916{
2917 struct mgmt_cp_set_device_id *cp = data;
Johan Hedberg890ea892013-03-15 17:06:52 -05002918 struct hci_request req;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07002919 int err;
Szymon Jancc72d4b82012-03-16 16:02:57 +01002920 __u16 source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07002921
2922 BT_DBG("%s", hdev->name);
2923
Szymon Jancc72d4b82012-03-16 16:02:57 +01002924 source = __le16_to_cpu(cp->source);
2925
2926 if (source > 0x0002)
2927 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEVICE_ID,
2928 MGMT_STATUS_INVALID_PARAMS);
2929
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07002930 hci_dev_lock(hdev);
2931
Szymon Jancc72d4b82012-03-16 16:02:57 +01002932 hdev->devid_source = source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07002933 hdev->devid_vendor = __le16_to_cpu(cp->vendor);
2934 hdev->devid_product = __le16_to_cpu(cp->product);
2935 hdev->devid_version = __le16_to_cpu(cp->version);
2936
2937 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_ID, 0, NULL, 0);
2938
Johan Hedberg890ea892013-03-15 17:06:52 -05002939 hci_req_init(&req, hdev);
2940 update_eir(&req);
2941 hci_req_run(&req, NULL);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07002942
2943 hci_dev_unlock(hdev);
2944
2945 return err;
2946}
2947
Johan Hedberg33e38b32013-03-15 17:07:05 -05002948static void fast_connectable_complete(struct hci_dev *hdev, u8 status)
2949{
2950 struct pending_cmd *cmd;
2951
2952 BT_DBG("status 0x%02x", status);
2953
2954 hci_dev_lock(hdev);
2955
2956 cmd = mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev);
2957 if (!cmd)
2958 goto unlock;
2959
2960 if (status) {
2961 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
2962 mgmt_status(status));
2963 } else {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05002964 struct mgmt_mode *cp = cmd->param;
2965
2966 if (cp->val)
2967 set_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
2968 else
2969 clear_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
2970
Johan Hedberg33e38b32013-03-15 17:07:05 -05002971 send_settings_rsp(cmd->sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev);
2972 new_settings(hdev, cmd->sk);
2973 }
2974
2975 mgmt_pending_remove(cmd);
2976
2977unlock:
2978 hci_dev_unlock(hdev);
2979}
2980
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002981static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002982 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03002983{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002984 struct mgmt_mode *cp = data;
Johan Hedberg33e38b32013-03-15 17:07:05 -05002985 struct pending_cmd *cmd;
2986 struct hci_request req;
Antti Julkuf6422ec2011-06-22 13:11:56 +03002987 int err;
2988
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002989 BT_DBG("%s", hdev->name);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002990
Johan Hedberg1a47aee2013-03-15 17:07:06 -05002991 if (!lmp_bredr_capable(hdev) || hdev->hci_ver < BLUETOOTH_VER_1_2)
Johan Hedberg33c525c2012-10-24 21:11:58 +03002992 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
2993 MGMT_STATUS_NOT_SUPPORTED);
2994
Johan Hedberga7e80f22013-01-09 16:05:19 +02002995 if (cp->val != 0x00 && cp->val != 0x01)
2996 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
2997 MGMT_STATUS_INVALID_PARAMS);
2998
Johan Hedberg5400c042012-02-21 16:40:33 +02002999 if (!hdev_is_powered(hdev))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003000 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003001 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5400c042012-02-21 16:40:33 +02003002
3003 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003004 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003005 MGMT_STATUS_REJECTED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003006
3007 hci_dev_lock(hdev);
3008
Johan Hedberg05cbf292013-03-15 17:07:07 -05003009 if (mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev)) {
3010 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3011 MGMT_STATUS_BUSY);
3012 goto unlock;
3013 }
3014
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05003015 if (!!cp->val == test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags)) {
3016 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
3017 hdev);
3018 goto unlock;
3019 }
3020
Johan Hedberg33e38b32013-03-15 17:07:05 -05003021 cmd = mgmt_pending_add(sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev,
3022 data, len);
3023 if (!cmd) {
3024 err = -ENOMEM;
3025 goto unlock;
3026 }
3027
3028 hci_req_init(&req, hdev);
3029
Johan Hedberg406d7802013-03-15 17:07:09 -05003030 write_fast_connectable(&req, cp->val);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003031
3032 err = hci_req_run(&req, fast_connectable_complete);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003033 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003034 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003035 MGMT_STATUS_FAILED);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003036 mgmt_pending_remove(cmd);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003037 }
3038
Johan Hedberg33e38b32013-03-15 17:07:05 -05003039unlock:
Antti Julkuf6422ec2011-06-22 13:11:56 +03003040 hci_dev_unlock(hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003041
Antti Julkuf6422ec2011-06-22 13:11:56 +03003042 return err;
3043}
3044
Johan Hedberg3f706b72013-01-20 14:27:16 +02003045static bool ltk_is_valid(struct mgmt_ltk_info *key)
3046{
Johan Hedberg44b20d32013-01-20 14:27:17 +02003047 if (key->authenticated != 0x00 && key->authenticated != 0x01)
3048 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02003049 if (key->master != 0x00 && key->master != 0x01)
3050 return false;
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003051 if (!bdaddr_type_is_le(key->addr.type))
3052 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02003053 return true;
3054}
3055
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003056static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003057 void *cp_data, u16 len)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003058{
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003059 struct mgmt_cp_load_long_term_keys *cp = cp_data;
3060 u16 key_count, expected_len;
Johan Hedberg715a5bf2013-01-09 15:29:34 +02003061 int i, err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003062
Marcel Holtmann1f350c82012-03-12 20:31:08 -07003063 key_count = __le16_to_cpu(cp->key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003064
3065 expected_len = sizeof(*cp) + key_count *
3066 sizeof(struct mgmt_ltk_info);
3067 if (expected_len != len) {
3068 BT_ERR("load_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003069 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003070 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
Johan Hedberge57e6192013-01-20 14:27:14 +02003071 MGMT_STATUS_INVALID_PARAMS);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003072 }
3073
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003074 BT_DBG("%s key_count %u", hdev->name, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003075
Johan Hedberg54ad6d82013-01-20 14:27:15 +02003076 for (i = 0; i < key_count; i++) {
3077 struct mgmt_ltk_info *key = &cp->keys[i];
3078
Johan Hedberg3f706b72013-01-20 14:27:16 +02003079 if (!ltk_is_valid(key))
Johan Hedberg54ad6d82013-01-20 14:27:15 +02003080 return cmd_status(sk, hdev->id,
3081 MGMT_OP_LOAD_LONG_TERM_KEYS,
3082 MGMT_STATUS_INVALID_PARAMS);
3083 }
3084
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003085 hci_dev_lock(hdev);
3086
3087 hci_smp_ltks_clear(hdev);
3088
3089 for (i = 0; i < key_count; i++) {
3090 struct mgmt_ltk_info *key = &cp->keys[i];
3091 u8 type;
3092
3093 if (key->master)
3094 type = HCI_SMP_LTK;
3095 else
3096 type = HCI_SMP_LTK_SLAVE;
3097
Hemant Gupta4596fde2012-04-16 14:57:40 +05303098 hci_add_ltk(hdev, &key->addr.bdaddr,
Andre Guedes378b5b72012-04-24 21:02:51 -03003099 bdaddr_to_le(key->addr.type),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003100 type, 0, key->authenticated, key->val,
3101 key->enc_size, key->ediv, key->rand);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003102 }
3103
Johan Hedberg715a5bf2013-01-09 15:29:34 +02003104 err = cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, 0,
3105 NULL, 0);
3106
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003107 hci_dev_unlock(hdev);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003108
Johan Hedberg715a5bf2013-01-09 15:29:34 +02003109 return err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003110}
3111
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02003112static const struct mgmt_handler {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003113 int (*func) (struct sock *sk, struct hci_dev *hdev, void *data,
3114 u16 data_len);
Johan Hedbergbe22b542012-03-01 22:24:41 +02003115 bool var_len;
3116 size_t data_len;
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003117} mgmt_handlers[] = {
3118 { NULL }, /* 0x0000 (no command) */
Johan Hedbergbe22b542012-03-01 22:24:41 +02003119 { read_version, false, MGMT_READ_VERSION_SIZE },
3120 { read_commands, false, MGMT_READ_COMMANDS_SIZE },
3121 { read_index_list, false, MGMT_READ_INDEX_LIST_SIZE },
3122 { read_controller_info, false, MGMT_READ_INFO_SIZE },
3123 { set_powered, false, MGMT_SETTING_SIZE },
3124 { set_discoverable, false, MGMT_SET_DISCOVERABLE_SIZE },
3125 { set_connectable, false, MGMT_SETTING_SIZE },
3126 { set_fast_connectable, false, MGMT_SETTING_SIZE },
3127 { set_pairable, false, MGMT_SETTING_SIZE },
3128 { set_link_security, false, MGMT_SETTING_SIZE },
3129 { set_ssp, false, MGMT_SETTING_SIZE },
3130 { set_hs, false, MGMT_SETTING_SIZE },
3131 { set_le, false, MGMT_SETTING_SIZE },
3132 { set_dev_class, false, MGMT_SET_DEV_CLASS_SIZE },
3133 { set_local_name, false, MGMT_SET_LOCAL_NAME_SIZE },
3134 { add_uuid, false, MGMT_ADD_UUID_SIZE },
3135 { remove_uuid, false, MGMT_REMOVE_UUID_SIZE },
3136 { load_link_keys, true, MGMT_LOAD_LINK_KEYS_SIZE },
3137 { load_long_term_keys, true, MGMT_LOAD_LONG_TERM_KEYS_SIZE },
3138 { disconnect, false, MGMT_DISCONNECT_SIZE },
3139 { get_connections, false, MGMT_GET_CONNECTIONS_SIZE },
3140 { pin_code_reply, false, MGMT_PIN_CODE_REPLY_SIZE },
3141 { pin_code_neg_reply, false, MGMT_PIN_CODE_NEG_REPLY_SIZE },
3142 { set_io_capability, false, MGMT_SET_IO_CAPABILITY_SIZE },
3143 { pair_device, false, MGMT_PAIR_DEVICE_SIZE },
3144 { cancel_pair_device, false, MGMT_CANCEL_PAIR_DEVICE_SIZE },
3145 { unpair_device, false, MGMT_UNPAIR_DEVICE_SIZE },
3146 { user_confirm_reply, false, MGMT_USER_CONFIRM_REPLY_SIZE },
3147 { user_confirm_neg_reply, false, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
3148 { user_passkey_reply, false, MGMT_USER_PASSKEY_REPLY_SIZE },
3149 { user_passkey_neg_reply, false, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
3150 { read_local_oob_data, false, MGMT_READ_LOCAL_OOB_DATA_SIZE },
3151 { add_remote_oob_data, false, MGMT_ADD_REMOTE_OOB_DATA_SIZE },
3152 { remove_remote_oob_data, false, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
3153 { start_discovery, false, MGMT_START_DISCOVERY_SIZE },
3154 { stop_discovery, false, MGMT_STOP_DISCOVERY_SIZE },
3155 { confirm_name, false, MGMT_CONFIRM_NAME_SIZE },
3156 { block_device, false, MGMT_BLOCK_DEVICE_SIZE },
3157 { unblock_device, false, MGMT_UNBLOCK_DEVICE_SIZE },
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003158 { set_device_id, false, MGMT_SET_DEVICE_ID_SIZE },
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003159};
3160
3161
Johan Hedberg03811012010-12-08 00:21:06 +02003162int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
3163{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003164 void *buf;
3165 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02003166 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01003167 u16 opcode, index, len;
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003168 struct hci_dev *hdev = NULL;
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02003169 const struct mgmt_handler *handler;
Johan Hedberg03811012010-12-08 00:21:06 +02003170 int err;
3171
3172 BT_DBG("got %zu bytes", msglen);
3173
3174 if (msglen < sizeof(*hdr))
3175 return -EINVAL;
3176
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03003177 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02003178 if (!buf)
3179 return -ENOMEM;
3180
3181 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
3182 err = -EFAULT;
3183 goto done;
3184 }
3185
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003186 hdr = buf;
Marcel Holtmann1f350c82012-03-12 20:31:08 -07003187 opcode = __le16_to_cpu(hdr->opcode);
3188 index = __le16_to_cpu(hdr->index);
3189 len = __le16_to_cpu(hdr->len);
Johan Hedberg03811012010-12-08 00:21:06 +02003190
3191 if (len != msglen - sizeof(*hdr)) {
3192 err = -EINVAL;
3193 goto done;
3194 }
3195
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003196 if (index != MGMT_INDEX_NONE) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003197 hdev = hci_dev_get(index);
3198 if (!hdev) {
3199 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003200 MGMT_STATUS_INVALID_INDEX);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003201 goto done;
3202 }
3203 }
3204
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003205 if (opcode >= ARRAY_SIZE(mgmt_handlers) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003206 mgmt_handlers[opcode].func == NULL) {
Johan Hedberg03811012010-12-08 00:21:06 +02003207 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02003208 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003209 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003210 goto done;
Johan Hedberg03811012010-12-08 00:21:06 +02003211 }
3212
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003213 if ((hdev && opcode < MGMT_OP_READ_INFO) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003214 (!hdev && opcode >= MGMT_OP_READ_INFO)) {
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003215 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003216 MGMT_STATUS_INVALID_INDEX);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003217 goto done;
3218 }
3219
Johan Hedbergbe22b542012-03-01 22:24:41 +02003220 handler = &mgmt_handlers[opcode];
3221
3222 if ((handler->var_len && len < handler->data_len) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003223 (!handler->var_len && len != handler->data_len)) {
Johan Hedbergbe22b542012-03-01 22:24:41 +02003224 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003225 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergbe22b542012-03-01 22:24:41 +02003226 goto done;
3227 }
3228
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003229 if (hdev)
3230 mgmt_init_hdev(sk, hdev);
3231
3232 cp = buf + sizeof(*hdr);
3233
Johan Hedbergbe22b542012-03-01 22:24:41 +02003234 err = handler->func(sk, hdev, cp, len);
Johan Hedberge41d8b42010-12-13 21:07:03 +02003235 if (err < 0)
3236 goto done;
3237
Johan Hedberg03811012010-12-08 00:21:06 +02003238 err = msglen;
3239
3240done:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003241 if (hdev)
3242 hci_dev_put(hdev);
3243
Johan Hedberg03811012010-12-08 00:21:06 +02003244 kfree(buf);
3245 return err;
3246}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003247
Johan Hedbergb24752f2011-11-03 14:40:33 +02003248static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
3249{
3250 u8 *status = data;
3251
3252 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
3253 mgmt_pending_remove(cmd);
3254}
3255
Johan Hedberg744cf192011-11-08 20:40:14 +02003256int mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003257{
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03003258 if (!mgmt_valid_hdev(hdev))
3259 return -ENOTSUPP;
3260
Johan Hedberg744cf192011-11-08 20:40:14 +02003261 return mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003262}
3263
Johan Hedberg744cf192011-11-08 20:40:14 +02003264int mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003265{
Johan Hedberg5f159032012-03-02 03:13:19 +02003266 u8 status = MGMT_STATUS_INVALID_INDEX;
Johan Hedbergb24752f2011-11-03 14:40:33 +02003267
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03003268 if (!mgmt_valid_hdev(hdev))
3269 return -ENOTSUPP;
3270
Johan Hedberg744cf192011-11-08 20:40:14 +02003271 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02003272
Johan Hedberg744cf192011-11-08 20:40:14 +02003273 return mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02003274}
3275
Johan Hedberg73f22f62010-12-29 16:00:25 +02003276struct cmd_lookup {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02003277 struct sock *sk;
Johan Hedberg69ab39e2011-12-15 00:47:35 +02003278 struct hci_dev *hdev;
Johan Hedberg90e70452012-02-23 23:09:40 +02003279 u8 mgmt_status;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02003280};
3281
Johan Hedberg69ab39e2011-12-15 00:47:35 +02003282static void settings_rsp(struct pending_cmd *cmd, void *data)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02003283{
Johan Hedberg73f22f62010-12-29 16:00:25 +02003284 struct cmd_lookup *match = data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02003285
Johan Hedberg69ab39e2011-12-15 00:47:35 +02003286 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02003287
3288 list_del(&cmd->list);
3289
3290 if (match->sk == NULL) {
3291 match->sk = cmd->sk;
3292 sock_hold(match->sk);
3293 }
3294
3295 mgmt_pending_free(cmd);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003296}
Johan Hedberg5add6af2010-12-16 10:00:37 +02003297
Johan Hedberg890ea892013-03-15 17:06:52 -05003298static void set_bredr_scan(struct hci_request *req)
Johan Hedberg7f0ae642012-10-24 21:11:57 +03003299{
Johan Hedberg890ea892013-03-15 17:06:52 -05003300 struct hci_dev *hdev = req->hdev;
Johan Hedberg7f0ae642012-10-24 21:11:57 +03003301 u8 scan = 0;
3302
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05003303 /* Ensure that fast connectable is disabled. This function will
3304 * not do anything if the page scan parameters are already what
3305 * they should be.
3306 */
3307 write_fast_connectable(req, false);
3308
Johan Hedberg7f0ae642012-10-24 21:11:57 +03003309 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3310 scan |= SCAN_PAGE;
3311 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3312 scan |= SCAN_INQUIRY;
3313
Johan Hedberg890ea892013-03-15 17:06:52 -05003314 if (scan)
3315 hci_req_add(req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
Johan Hedberg7f0ae642012-10-24 21:11:57 +03003316}
3317
Johan Hedberg229ab392013-03-15 17:06:53 -05003318static void powered_complete(struct hci_dev *hdev, u8 status)
3319{
3320 struct cmd_lookup match = { NULL, hdev };
3321
3322 BT_DBG("status 0x%02x", status);
3323
3324 hci_dev_lock(hdev);
3325
3326 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
3327
3328 new_settings(hdev, match.sk);
3329
3330 hci_dev_unlock(hdev);
3331
3332 if (match.sk)
3333 sock_put(match.sk);
3334}
3335
Johan Hedberg70da6242013-03-15 17:06:51 -05003336static int powered_update_hci(struct hci_dev *hdev)
3337{
Johan Hedberg890ea892013-03-15 17:06:52 -05003338 struct hci_request req;
Johan Hedberg70da6242013-03-15 17:06:51 -05003339 u8 link_sec;
3340
Johan Hedberg890ea892013-03-15 17:06:52 -05003341 hci_req_init(&req, hdev);
3342
Johan Hedberg70da6242013-03-15 17:06:51 -05003343 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) &&
3344 !lmp_host_ssp_capable(hdev)) {
3345 u8 ssp = 1;
3346
Johan Hedberg890ea892013-03-15 17:06:52 -05003347 hci_req_add(&req, HCI_OP_WRITE_SSP_MODE, 1, &ssp);
Johan Hedberg70da6242013-03-15 17:06:51 -05003348 }
3349
3350 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
3351 struct hci_cp_write_le_host_supported cp;
3352
3353 cp.le = 1;
3354 cp.simul = lmp_le_br_capable(hdev);
3355
3356 /* Check first if we already have the right
3357 * host state (host features set)
3358 */
3359 if (cp.le != lmp_host_le_capable(hdev) ||
3360 cp.simul != lmp_host_le_br_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05003361 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED,
3362 sizeof(cp), &cp);
Johan Hedberg70da6242013-03-15 17:06:51 -05003363 }
3364
3365 link_sec = test_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
3366 if (link_sec != test_bit(HCI_AUTH, &hdev->flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05003367 hci_req_add(&req, HCI_OP_WRITE_AUTH_ENABLE,
3368 sizeof(link_sec), &link_sec);
Johan Hedberg70da6242013-03-15 17:06:51 -05003369
3370 if (lmp_bredr_capable(hdev)) {
Johan Hedberg890ea892013-03-15 17:06:52 -05003371 set_bredr_scan(&req);
3372 update_class(&req);
Johan Hedberg13928972013-03-15 17:07:00 -05003373 update_name(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05003374 update_eir(&req);
Johan Hedberg70da6242013-03-15 17:06:51 -05003375 }
3376
Johan Hedberg229ab392013-03-15 17:06:53 -05003377 return hci_req_run(&req, powered_complete);
Johan Hedberg70da6242013-03-15 17:06:51 -05003378}
3379
Johan Hedberg744cf192011-11-08 20:40:14 +02003380int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg5add6af2010-12-16 10:00:37 +02003381{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02003382 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg229ab392013-03-15 17:06:53 -05003383 u8 status_not_powered = MGMT_STATUS_NOT_POWERED;
3384 u8 zero_cod[] = { 0, 0, 0 };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003385 int err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02003386
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003387 if (!test_bit(HCI_MGMT, &hdev->dev_flags))
3388 return 0;
3389
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003390 if (powered) {
Johan Hedberg229ab392013-03-15 17:06:53 -05003391 if (powered_update_hci(hdev) == 0)
3392 return 0;
Johan Hedbergfe038882013-01-16 16:15:34 +02003393
Johan Hedberg229ab392013-03-15 17:06:53 -05003394 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp,
3395 &match);
3396 goto new_settings;
Johan Hedbergb24752f2011-11-03 14:40:33 +02003397 }
3398
Johan Hedberg229ab392013-03-15 17:06:53 -05003399 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
3400 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status_not_powered);
3401
3402 if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0)
3403 mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
3404 zero_cod, sizeof(zero_cod), NULL);
3405
3406new_settings:
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003407 err = new_settings(hdev, match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02003408
3409 if (match.sk)
3410 sock_put(match.sk);
3411
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003412 return err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02003413}
Johan Hedberg73f22f62010-12-29 16:00:25 +02003414
Johan Hedberg744cf192011-11-08 20:40:14 +02003415int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg73f22f62010-12-29 16:00:25 +02003416{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02003417 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003418 bool changed = false;
3419 int err = 0;
Johan Hedberg73f22f62010-12-29 16:00:25 +02003420
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003421 if (discoverable) {
3422 if (!test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3423 changed = true;
3424 } else {
3425 if (test_and_clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3426 changed = true;
3427 }
Johan Hedberg73f22f62010-12-29 16:00:25 +02003428
Johan Hedberged9b5f22012-02-21 20:47:06 +02003429 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003430 &match);
Johan Hedberged9b5f22012-02-21 20:47:06 +02003431
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003432 if (changed)
3433 err = new_settings(hdev, match.sk);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003434
Johan Hedberg73f22f62010-12-29 16:00:25 +02003435 if (match.sk)
3436 sock_put(match.sk);
3437
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003438 return err;
Johan Hedberg73f22f62010-12-29 16:00:25 +02003439}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003440
Johan Hedberg744cf192011-11-08 20:40:14 +02003441int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003442{
Johan Hedberg2b76f452013-03-15 17:07:04 -05003443 struct pending_cmd *cmd;
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003444 bool changed = false;
3445 int err = 0;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003446
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003447 if (connectable) {
3448 if (!test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3449 changed = true;
3450 } else {
3451 if (test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3452 changed = true;
3453 }
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003454
Johan Hedberg2b76f452013-03-15 17:07:04 -05003455 cmd = mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberged9b5f22012-02-21 20:47:06 +02003456
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003457 if (changed)
Johan Hedberg2b76f452013-03-15 17:07:04 -05003458 err = new_settings(hdev, cmd ? cmd->sk : NULL);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003459
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003460 return err;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003461}
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003462
Johan Hedberg744cf192011-11-08 20:40:14 +02003463int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003464{
Johan Hedbergca69b792011-11-11 18:10:00 +02003465 u8 mgmt_err = mgmt_status(status);
3466
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003467 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02003468 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003469 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003470
3471 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02003472 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003473 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003474
3475 return 0;
3476}
3477
Cristian Chilipirea53168e52012-05-09 08:44:52 +03003478int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
3479 bool persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003480{
Johan Hedberg86742e12011-11-07 23:13:38 +02003481 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003482
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003483 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003484
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003485 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02003486 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03003487 ev.key.addr.type = BDADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003488 ev.key.type = key->type;
Andrei Emeltchenko9b3b4462012-05-23 11:31:20 +03003489 memcpy(ev.key.val, key->val, HCI_LINK_KEY_SIZE);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003490 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003491
Johan Hedberg744cf192011-11-08 20:40:14 +02003492 return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003493}
Johan Hedbergf7520542011-01-20 12:34:39 +02003494
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003495int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
3496{
3497 struct mgmt_ev_new_long_term_key ev;
3498
3499 memset(&ev, 0, sizeof(ev));
3500
3501 ev.store_hint = persistent;
3502 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003503 ev.key.addr.type = link_to_bdaddr(LE_LINK, key->bdaddr_type);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003504 ev.key.authenticated = key->authenticated;
3505 ev.key.enc_size = key->enc_size;
3506 ev.key.ediv = key->ediv;
3507
3508 if (key->type == HCI_SMP_LTK)
3509 ev.key.master = 1;
3510
3511 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
3512 memcpy(ev.key.val, key->val, sizeof(key->val));
3513
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003514 return mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev),
3515 NULL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003516}
3517
Johan Hedbergafc747a2012-01-15 18:11:07 +02003518int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003519 u8 addr_type, u32 flags, u8 *name, u8 name_len,
3520 u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02003521{
Johan Hedbergb644ba32012-01-17 21:48:47 +02003522 char buf[512];
3523 struct mgmt_ev_device_connected *ev = (void *) buf;
3524 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02003525
Johan Hedbergb644ba32012-01-17 21:48:47 +02003526 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003527 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02003528
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02003529 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02003530
Johan Hedbergb644ba32012-01-17 21:48:47 +02003531 if (name_len > 0)
3532 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003533 name, name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003534
3535 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
Brian Gix53156382012-03-09 14:07:03 -08003536 eir_len = eir_append_data(ev->eir, eir_len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003537 EIR_CLASS_OF_DEV, dev_class, 3);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003538
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02003539 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003540
3541 return mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003542 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02003543}
3544
Johan Hedberg8962ee72011-01-20 12:40:27 +02003545static void disconnect_rsp(struct pending_cmd *cmd, void *data)
3546{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01003547 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003548 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02003549 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003550
Johan Hedberg88c3df12012-02-09 14:27:38 +02003551 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3552 rp.addr.type = cp->addr.type;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003553
Johan Hedbergaee9b212012-02-18 15:07:59 +02003554 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003555 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003556
3557 *sk = cmd->sk;
3558 sock_hold(*sk);
3559
Johan Hedberga664b5b2011-02-19 12:06:02 -03003560 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003561}
3562
Johan Hedberg124f6e32012-02-09 13:50:12 +02003563static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02003564{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003565 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02003566 struct mgmt_cp_unpair_device *cp = cmd->param;
3567 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02003568
3569 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02003570 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3571 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02003572
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003573 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
3574
Johan Hedbergaee9b212012-02-18 15:07:59 +02003575 cmd_complete(cmd->sk, cmd->index, cmd->opcode, 0, &rp, sizeof(rp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02003576
3577 mgmt_pending_remove(cmd);
3578}
3579
Johan Hedbergafc747a2012-01-15 18:11:07 +02003580int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02003581 u8 link_type, u8 addr_type, u8 reason)
Johan Hedbergf7520542011-01-20 12:34:39 +02003582{
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02003583 struct mgmt_ev_device_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003584 struct sock *sk = NULL;
3585 int err;
3586
Johan Hedberg744cf192011-11-08 20:40:14 +02003587 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02003588
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02003589 bacpy(&ev.addr.bdaddr, bdaddr);
3590 ev.addr.type = link_to_bdaddr(link_type, addr_type);
3591 ev.reason = reason;
Johan Hedbergf7520542011-01-20 12:34:39 +02003592
Johan Hedbergafc747a2012-01-15 18:11:07 +02003593 err = mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003594 sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003595
3596 if (sk)
Szymon Jancd97dcb62012-03-16 16:02:56 +01003597 sock_put(sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003598
Johan Hedberg124f6e32012-02-09 13:50:12 +02003599 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003600 hdev);
Johan Hedberga8a1d192011-11-10 15:54:38 +02003601
Johan Hedberg8962ee72011-01-20 12:40:27 +02003602 return err;
3603}
3604
Johan Hedberg88c3df12012-02-09 14:27:38 +02003605int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003606 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02003607{
Johan Hedberg88c3df12012-02-09 14:27:38 +02003608 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003609 struct pending_cmd *cmd;
3610 int err;
3611
Jefferson Delfes36a75f12012-09-18 13:36:54 -04003612 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
3613 hdev);
3614
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003615 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003616 if (!cmd)
3617 return -ENOENT;
3618
Johan Hedberg88c3df12012-02-09 14:27:38 +02003619 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003620 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02003621
Johan Hedberg88c3df12012-02-09 14:27:38 +02003622 err = cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003623 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003624
Johan Hedberga664b5b2011-02-19 12:06:02 -03003625 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003626
3627 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02003628}
Johan Hedberg17d5c042011-01-22 06:09:08 +02003629
Johan Hedberg48264f02011-11-09 13:58:58 +02003630int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003631 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02003632{
3633 struct mgmt_ev_connect_failed ev;
3634
Johan Hedberg4c659c32011-11-07 23:13:39 +02003635 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003636 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003637 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003638
Johan Hedberg744cf192011-11-08 20:40:14 +02003639 return mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003640}
Johan Hedberg980e1a52011-01-22 06:10:07 +02003641
Johan Hedberg744cf192011-11-08 20:40:14 +02003642int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003643{
3644 struct mgmt_ev_pin_code_request ev;
3645
Johan Hedbergd8457692012-02-17 14:24:57 +02003646 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03003647 ev.addr.type = BDADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02003648 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003649
Johan Hedberg744cf192011-11-08 20:40:14 +02003650 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003651 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003652}
3653
Johan Hedberg744cf192011-11-08 20:40:14 +02003654int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003655 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003656{
3657 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003658 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003659 int err;
3660
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003661 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003662 if (!cmd)
3663 return -ENOENT;
3664
Johan Hedbergd8457692012-02-17 14:24:57 +02003665 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03003666 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003667
Johan Hedbergaee9b212012-02-18 15:07:59 +02003668 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003669 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003670
Johan Hedberga664b5b2011-02-19 12:06:02 -03003671 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003672
3673 return err;
3674}
3675
Johan Hedberg744cf192011-11-08 20:40:14 +02003676int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003677 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003678{
3679 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003680 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003681 int err;
3682
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003683 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003684 if (!cmd)
3685 return -ENOENT;
3686
Johan Hedbergd8457692012-02-17 14:24:57 +02003687 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03003688 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003689
Johan Hedbergaee9b212012-02-18 15:07:59 +02003690 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003691 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003692
Johan Hedberga664b5b2011-02-19 12:06:02 -03003693 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003694
3695 return err;
3696}
Johan Hedberga5c29682011-02-19 12:05:57 -03003697
Johan Hedberg744cf192011-11-08 20:40:14 +02003698int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003699 u8 link_type, u8 addr_type, __le32 value,
3700 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03003701{
3702 struct mgmt_ev_user_confirm_request ev;
3703
Johan Hedberg744cf192011-11-08 20:40:14 +02003704 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03003705
Johan Hedberg272d90d2012-02-09 15:26:12 +02003706 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003707 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07003708 ev.confirm_hint = confirm_hint;
Andrei Emeltchenko78e80982012-03-09 13:00:50 +02003709 ev.value = value;
Johan Hedberga5c29682011-02-19 12:05:57 -03003710
Johan Hedberg744cf192011-11-08 20:40:14 +02003711 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003712 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03003713}
3714
Johan Hedberg272d90d2012-02-09 15:26:12 +02003715int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003716 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08003717{
3718 struct mgmt_ev_user_passkey_request ev;
3719
3720 BT_DBG("%s", hdev->name);
3721
Johan Hedberg272d90d2012-02-09 15:26:12 +02003722 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003723 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08003724
3725 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003726 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08003727}
3728
Brian Gix0df4c182011-11-16 13:53:13 -08003729static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003730 u8 link_type, u8 addr_type, u8 status,
3731 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03003732{
3733 struct pending_cmd *cmd;
3734 struct mgmt_rp_user_confirm_reply rp;
3735 int err;
3736
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003737 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03003738 if (!cmd)
3739 return -ENOENT;
3740
Johan Hedberg272d90d2012-02-09 15:26:12 +02003741 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003742 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergaee9b212012-02-18 15:07:59 +02003743 err = cmd_complete(cmd->sk, hdev->id, opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003744 &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03003745
Johan Hedberga664b5b2011-02-19 12:06:02 -03003746 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03003747
3748 return err;
3749}
3750
Johan Hedberg744cf192011-11-08 20:40:14 +02003751int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003752 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003753{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003754 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003755 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003756}
3757
Johan Hedberg272d90d2012-02-09 15:26:12 +02003758int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003759 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003760{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003761 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03003762 status,
3763 MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003764}
Johan Hedberg2a611692011-02-19 12:06:00 -03003765
Brian Gix604086b2011-11-23 08:28:33 -08003766int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003767 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003768{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003769 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003770 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003771}
3772
Johan Hedberg272d90d2012-02-09 15:26:12 +02003773int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003774 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003775{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003776 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03003777 status,
3778 MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003779}
3780
Johan Hedberg92a25252012-09-06 18:39:26 +03003781int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr,
3782 u8 link_type, u8 addr_type, u32 passkey,
3783 u8 entered)
3784{
3785 struct mgmt_ev_passkey_notify ev;
3786
3787 BT_DBG("%s", hdev->name);
3788
3789 bacpy(&ev.addr.bdaddr, bdaddr);
3790 ev.addr.type = link_to_bdaddr(link_type, addr_type);
3791 ev.passkey = __cpu_to_le32(passkey);
3792 ev.entered = entered;
3793
3794 return mgmt_event(MGMT_EV_PASSKEY_NOTIFY, hdev, &ev, sizeof(ev), NULL);
3795}
3796
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003797int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003798 u8 addr_type, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03003799{
3800 struct mgmt_ev_auth_failed ev;
3801
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003802 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003803 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003804 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03003805
Johan Hedberg744cf192011-11-08 20:40:14 +02003806 return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03003807}
Johan Hedbergb312b1612011-03-16 14:29:37 +02003808
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003809int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
3810{
3811 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg47990ea2012-02-22 11:58:37 +02003812 bool changed = false;
3813 int err = 0;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003814
3815 if (status) {
3816 u8 mgmt_err = mgmt_status(status);
3817 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003818 cmd_status_rsp, &mgmt_err);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003819 return 0;
3820 }
3821
Johan Hedberg47990ea2012-02-22 11:58:37 +02003822 if (test_bit(HCI_AUTH, &hdev->flags)) {
3823 if (!test_and_set_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
3824 changed = true;
3825 } else {
3826 if (test_and_clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
3827 changed = true;
3828 }
3829
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003830 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003831 &match);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003832
Johan Hedberg47990ea2012-02-22 11:58:37 +02003833 if (changed)
3834 err = new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003835
3836 if (match.sk)
3837 sock_put(match.sk);
3838
3839 return err;
3840}
3841
Johan Hedberg890ea892013-03-15 17:06:52 -05003842static void clear_eir(struct hci_request *req)
Johan Hedbergcacaf522012-02-21 00:52:42 +02003843{
Johan Hedberg890ea892013-03-15 17:06:52 -05003844 struct hci_dev *hdev = req->hdev;
Johan Hedbergcacaf522012-02-21 00:52:42 +02003845 struct hci_cp_write_eir cp;
3846
Johan Hedberg976eb202012-10-24 21:12:01 +03003847 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05003848 return;
Johan Hedbergcacaf522012-02-21 00:52:42 +02003849
Johan Hedbergc80da272012-02-22 15:38:48 +02003850 memset(hdev->eir, 0, sizeof(hdev->eir));
3851
Johan Hedbergcacaf522012-02-21 00:52:42 +02003852 memset(&cp, 0, sizeof(cp));
3853
Johan Hedberg890ea892013-03-15 17:06:52 -05003854 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedbergcacaf522012-02-21 00:52:42 +02003855}
3856
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003857int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003858{
3859 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg890ea892013-03-15 17:06:52 -05003860 struct hci_request req;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003861 bool changed = false;
3862 int err = 0;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003863
3864 if (status) {
3865 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003866
3867 if (enable && test_and_clear_bit(HCI_SSP_ENABLED,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003868 &hdev->dev_flags))
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003869 err = new_settings(hdev, NULL);
3870
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003871 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
3872 &mgmt_err);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003873
3874 return err;
3875 }
3876
3877 if (enable) {
3878 if (!test_and_set_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3879 changed = true;
3880 } else {
3881 if (test_and_clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3882 changed = true;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003883 }
3884
3885 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
3886
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003887 if (changed)
3888 err = new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003889
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02003890 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003891 sock_put(match.sk);
3892
Johan Hedberg890ea892013-03-15 17:06:52 -05003893 hci_req_init(&req, hdev);
3894
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02003895 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05003896 update_eir(&req);
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02003897 else
Johan Hedberg890ea892013-03-15 17:06:52 -05003898 clear_eir(&req);
3899
3900 hci_req_run(&req, NULL);
Johan Hedbergcacaf522012-02-21 00:52:42 +02003901
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003902 return err;
3903}
3904
Johan Hedberg92da6092013-03-15 17:06:55 -05003905static void sk_lookup(struct pending_cmd *cmd, void *data)
Johan Hedberg90e70452012-02-23 23:09:40 +02003906{
3907 struct cmd_lookup *match = data;
3908
Johan Hedberg90e70452012-02-23 23:09:40 +02003909 if (match->sk == NULL) {
3910 match->sk = cmd->sk;
3911 sock_hold(match->sk);
3912 }
Johan Hedberg90e70452012-02-23 23:09:40 +02003913}
3914
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003915int mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003916 u8 status)
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003917{
Johan Hedberg90e70452012-02-23 23:09:40 +02003918 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
3919 int err = 0;
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003920
Johan Hedberg92da6092013-03-15 17:06:55 -05003921 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, sk_lookup, &match);
3922 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, sk_lookup, &match);
3923 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, sk_lookup, &match);
Johan Hedberg90e70452012-02-23 23:09:40 +02003924
3925 if (!status)
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003926 err = mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class,
3927 3, NULL);
Johan Hedberg90e70452012-02-23 23:09:40 +02003928
3929 if (match.sk)
3930 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003931
3932 return err;
3933}
3934
Johan Hedberg744cf192011-11-08 20:40:14 +02003935int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02003936{
Johan Hedbergb312b1612011-03-16 14:29:37 +02003937 struct mgmt_cp_set_local_name ev;
Johan Hedberg13928972013-03-15 17:07:00 -05003938 struct pending_cmd *cmd;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003939
Johan Hedberg13928972013-03-15 17:07:00 -05003940 if (status)
3941 return 0;
Johan Hedbergb312b1612011-03-16 14:29:37 +02003942
3943 memset(&ev, 0, sizeof(ev));
3944 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003945 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003946
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003947 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05003948 if (!cmd) {
3949 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
Johan Hedbergb312b1612011-03-16 14:29:37 +02003950
Johan Hedberg13928972013-03-15 17:07:00 -05003951 /* If this is a HCI command related to powering on the
3952 * HCI dev don't send any mgmt signals.
3953 */
3954 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev))
3955 return 0;
Johan Hedbergb312b1612011-03-16 14:29:37 +02003956 }
3957
Johan Hedberg13928972013-03-15 17:07:00 -05003958 return mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
3959 cmd ? cmd->sk : NULL);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003960}
Szymon Jancc35938b2011-03-22 13:12:21 +01003961
Johan Hedberg744cf192011-11-08 20:40:14 +02003962int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003963 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01003964{
3965 struct pending_cmd *cmd;
3966 int err;
3967
Johan Hedberg744cf192011-11-08 20:40:14 +02003968 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01003969
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003970 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003971 if (!cmd)
3972 return -ENOENT;
3973
3974 if (status) {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003975 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3976 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01003977 } else {
3978 struct mgmt_rp_read_local_oob_data rp;
3979
3980 memcpy(rp.hash, hash, sizeof(rp.hash));
3981 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
3982
Johan Hedberg744cf192011-11-08 20:40:14 +02003983 err = cmd_complete(cmd->sk, hdev->id,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003984 MGMT_OP_READ_LOCAL_OOB_DATA, 0, &rp,
3985 sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01003986 }
3987
3988 mgmt_pending_remove(cmd);
3989
3990 return err;
3991}
Johan Hedberge17acd42011-03-30 23:57:16 +03003992
Johan Hedberg06199cf2012-02-22 16:37:11 +02003993int mgmt_le_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
3994{
3995 struct cmd_lookup match = { NULL, hdev };
3996 bool changed = false;
3997 int err = 0;
3998
3999 if (status) {
4000 u8 mgmt_err = mgmt_status(status);
4001
4002 if (enable && test_and_clear_bit(HCI_LE_ENABLED,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004003 &hdev->dev_flags))
Szymon Jancd97dcb62012-03-16 16:02:56 +01004004 err = new_settings(hdev, NULL);
Johan Hedberg06199cf2012-02-22 16:37:11 +02004005
Szymon Jancd97dcb62012-03-16 16:02:56 +01004006 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, cmd_status_rsp,
4007 &mgmt_err);
Johan Hedberg06199cf2012-02-22 16:37:11 +02004008
4009 return err;
4010 }
4011
4012 if (enable) {
4013 if (!test_and_set_bit(HCI_LE_ENABLED, &hdev->dev_flags))
4014 changed = true;
4015 } else {
4016 if (test_and_clear_bit(HCI_LE_ENABLED, &hdev->dev_flags))
4017 changed = true;
4018 }
4019
4020 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
4021
4022 if (changed)
4023 err = new_settings(hdev, match.sk);
4024
4025 if (match.sk)
4026 sock_put(match.sk);
4027
4028 return err;
4029}
4030
Johan Hedberg48264f02011-11-09 13:58:58 +02004031int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004032 u8 addr_type, u8 *dev_class, s8 rssi, u8 cfm_name, u8
4033 ssp, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03004034{
Johan Hedberge319d2e2012-01-15 19:51:59 +02004035 char buf[512];
4036 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02004037 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03004038
Johan Hedberg1dc06092012-01-15 21:01:23 +02004039 /* Leave 5 bytes for a potential CoD field */
4040 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Andre Guedes7d262f82012-01-10 18:20:49 -03004041 return -EINVAL;
4042
Johan Hedberg1dc06092012-01-15 21:01:23 +02004043 memset(buf, 0, sizeof(buf));
4044
Johan Hedberge319d2e2012-01-15 19:51:59 +02004045 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004046 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberge319d2e2012-01-15 19:51:59 +02004047 ev->rssi = rssi;
Johan Hedberg9a395a82012-02-23 00:00:32 +02004048 if (cfm_name)
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05304049 ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_CONFIRM_NAME);
Johan Hedberg388fc8f2012-02-23 00:38:59 +02004050 if (!ssp)
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05304051 ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_LEGACY_PAIRING);
Johan Hedberge17acd42011-03-30 23:57:16 +03004052
Johan Hedberg1dc06092012-01-15 21:01:23 +02004053 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02004054 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03004055
Johan Hedberg1dc06092012-01-15 21:01:23 +02004056 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
4057 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004058 dev_class, 3);
Johan Hedberg1dc06092012-01-15 21:01:23 +02004059
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004060 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedberg1dc06092012-01-15 21:01:23 +02004061 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03004062
Johan Hedberge319d2e2012-01-15 19:51:59 +02004063 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03004064}
Johan Hedberga88a9652011-03-30 13:18:12 +03004065
Johan Hedbergb644ba32012-01-17 21:48:47 +02004066int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004067 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03004068{
Johan Hedbergb644ba32012-01-17 21:48:47 +02004069 struct mgmt_ev_device_found *ev;
4070 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
4071 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03004072
Johan Hedbergb644ba32012-01-17 21:48:47 +02004073 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03004074
Johan Hedbergb644ba32012-01-17 21:48:47 +02004075 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03004076
Johan Hedbergb644ba32012-01-17 21:48:47 +02004077 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004078 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004079 ev->rssi = rssi;
4080
4081 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004082 name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004083
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004084 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004085
Johan Hedberg053c7e02012-02-04 00:06:00 +02004086 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004087 sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03004088}
Johan Hedberg314b2382011-04-27 10:29:57 -04004089
Andre Guedes7a135102011-11-09 17:14:25 -03004090int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
Johan Hedberg164a6e72011-11-01 17:06:44 +02004091{
4092 struct pending_cmd *cmd;
Johan Hedbergf808e162012-02-19 12:52:07 +02004093 u8 type;
Johan Hedberg164a6e72011-11-01 17:06:44 +02004094 int err;
4095
Andre Guedes203159d2012-02-13 15:41:01 -03004096 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
4097
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004098 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02004099 if (!cmd)
4100 return -ENOENT;
4101
Johan Hedbergf808e162012-02-19 12:52:07 +02004102 type = hdev->discovery.type;
4103
4104 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004105 &type, sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02004106 mgmt_pending_remove(cmd);
4107
4108 return err;
4109}
4110
Andre Guedese6d465c2011-11-09 17:14:26 -03004111int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
4112{
4113 struct pending_cmd *cmd;
4114 int err;
4115
4116 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
4117 if (!cmd)
4118 return -ENOENT;
4119
Johan Hedbergd9306502012-02-20 23:25:18 +02004120 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004121 &hdev->discovery.type, sizeof(hdev->discovery.type));
Johan Hedberg03811012010-12-08 00:21:06 +02004122 mgmt_pending_remove(cmd);
4123
4124 return err;
4125}
Johan Hedberg314b2382011-04-27 10:29:57 -04004126
Johan Hedberg744cf192011-11-08 20:40:14 +02004127int mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04004128{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02004129 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02004130 struct pending_cmd *cmd;
4131
Andre Guedes343fb142011-11-22 17:14:19 -03004132 BT_DBG("%s discovering %u", hdev->name, discovering);
4133
Johan Hedberg164a6e72011-11-01 17:06:44 +02004134 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004135 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02004136 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004137 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02004138
4139 if (cmd != NULL) {
Johan Hedbergf808e162012-02-19 12:52:07 +02004140 u8 type = hdev->discovery.type;
4141
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004142 cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0, &type,
4143 sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02004144 mgmt_pending_remove(cmd);
4145 }
4146
Johan Hedbergf963e8e2012-02-20 23:30:44 +02004147 memset(&ev, 0, sizeof(ev));
4148 ev.type = hdev->discovery.type;
4149 ev.discovering = discovering;
4150
4151 return mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04004152}
Antti Julku5e762442011-08-25 16:48:02 +03004153
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004154int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03004155{
4156 struct pending_cmd *cmd;
4157 struct mgmt_ev_device_blocked ev;
4158
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004159 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03004160
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004161 bacpy(&ev.addr.bdaddr, bdaddr);
4162 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03004163
Johan Hedberg744cf192011-11-08 20:40:14 +02004164 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004165 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03004166}
4167
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004168int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03004169{
4170 struct pending_cmd *cmd;
4171 struct mgmt_ev_device_unblocked ev;
4172
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004173 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03004174
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004175 bacpy(&ev.addr.bdaddr, bdaddr);
4176 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03004177
Johan Hedberg744cf192011-11-08 20:40:14 +02004178 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004179 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03004180}
Marcel Holtmannd7b7e792012-02-20 21:47:49 +01004181
4182module_param(enable_hs, bool, 0644);
4183MODULE_PARM_DESC(enable_hs, "Enable High Speed support");