blob: 88a342a125930c2e493347cc732450e1d13918bb [file] [log] [blame]
Johan Hedberg03811012010-12-08 00:21:06 +02001/*
2 BlueZ - Bluetooth protocol stack for Linux
Johan Hedbergea585ab2012-02-17 14:50:39 +02003
Johan Hedberg03811012010-12-08 00:21:06 +02004 Copyright (C) 2010 Nokia Corporation
Johan Hedbergea585ab2012-02-17 14:50:39 +02005 Copyright (C) 2011-2012 Intel Corporation
Johan Hedberg03811012010-12-08 00:21:06 +02006
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License version 2 as
9 published by the Free Software Foundation;
10
11 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
12 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
13 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
14 IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
15 CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
16 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19
20 ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
21 COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
22 SOFTWARE IS DISCLAIMED.
23*/
24
25/* Bluetooth HCI Management interface */
26
Johan Hedbergca69b792011-11-11 18:10:00 +020027#include <linux/kernel.h>
Szymon Janc72359752011-02-17 14:16:32 +010028#include <linux/uaccess.h>
Paul Gortmaker3a9a2312011-05-27 09:12:25 -040029#include <linux/module.h>
Johan Hedberg03811012010-12-08 00:21:06 +020030#include <asm/unaligned.h>
31
32#include <net/bluetooth/bluetooth.h>
33#include <net/bluetooth/hci_core.h>
34#include <net/bluetooth/mgmt.h>
Brian Gix5fe57d92011-12-21 16:12:13 -080035#include <net/bluetooth/smp.h>
Johan Hedberg03811012010-12-08 00:21:06 +020036
Marcel Holtmannd7b7e792012-02-20 21:47:49 +010037bool enable_hs;
38bool enable_le;
39
Johan Hedberg2da9c552012-02-17 14:39:28 +020040#define MGMT_VERSION 1
41#define MGMT_REVISION 0
Johan Hedberg02d98122010-12-13 21:07:04 +020042
Johan Hedberge70bb2e2012-02-13 16:59:33 +020043static const u16 mgmt_commands[] = {
44 MGMT_OP_READ_INDEX_LIST,
45 MGMT_OP_READ_INFO,
46 MGMT_OP_SET_POWERED,
47 MGMT_OP_SET_DISCOVERABLE,
48 MGMT_OP_SET_CONNECTABLE,
49 MGMT_OP_SET_FAST_CONNECTABLE,
50 MGMT_OP_SET_PAIRABLE,
51 MGMT_OP_SET_LINK_SECURITY,
52 MGMT_OP_SET_SSP,
53 MGMT_OP_SET_HS,
54 MGMT_OP_SET_LE,
55 MGMT_OP_SET_DEV_CLASS,
56 MGMT_OP_SET_LOCAL_NAME,
57 MGMT_OP_ADD_UUID,
58 MGMT_OP_REMOVE_UUID,
59 MGMT_OP_LOAD_LINK_KEYS,
60 MGMT_OP_LOAD_LONG_TERM_KEYS,
61 MGMT_OP_DISCONNECT,
62 MGMT_OP_GET_CONNECTIONS,
63 MGMT_OP_PIN_CODE_REPLY,
64 MGMT_OP_PIN_CODE_NEG_REPLY,
65 MGMT_OP_SET_IO_CAPABILITY,
66 MGMT_OP_PAIR_DEVICE,
67 MGMT_OP_CANCEL_PAIR_DEVICE,
68 MGMT_OP_UNPAIR_DEVICE,
69 MGMT_OP_USER_CONFIRM_REPLY,
70 MGMT_OP_USER_CONFIRM_NEG_REPLY,
71 MGMT_OP_USER_PASSKEY_REPLY,
72 MGMT_OP_USER_PASSKEY_NEG_REPLY,
73 MGMT_OP_READ_LOCAL_OOB_DATA,
74 MGMT_OP_ADD_REMOTE_OOB_DATA,
75 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
76 MGMT_OP_START_DISCOVERY,
77 MGMT_OP_STOP_DISCOVERY,
78 MGMT_OP_CONFIRM_NAME,
79 MGMT_OP_BLOCK_DEVICE,
80 MGMT_OP_UNBLOCK_DEVICE,
81};
82
83static const u16 mgmt_events[] = {
84 MGMT_EV_CONTROLLER_ERROR,
85 MGMT_EV_INDEX_ADDED,
86 MGMT_EV_INDEX_REMOVED,
87 MGMT_EV_NEW_SETTINGS,
88 MGMT_EV_CLASS_OF_DEV_CHANGED,
89 MGMT_EV_LOCAL_NAME_CHANGED,
90 MGMT_EV_NEW_LINK_KEY,
91 MGMT_EV_NEW_LONG_TERM_KEY,
92 MGMT_EV_DEVICE_CONNECTED,
93 MGMT_EV_DEVICE_DISCONNECTED,
94 MGMT_EV_CONNECT_FAILED,
95 MGMT_EV_PIN_CODE_REQUEST,
96 MGMT_EV_USER_CONFIRM_REQUEST,
97 MGMT_EV_USER_PASSKEY_REQUEST,
98 MGMT_EV_AUTH_FAILED,
99 MGMT_EV_DEVICE_FOUND,
100 MGMT_EV_DISCOVERING,
101 MGMT_EV_DEVICE_BLOCKED,
102 MGMT_EV_DEVICE_UNBLOCKED,
103 MGMT_EV_DEVICE_UNPAIRED,
104};
105
Andre Guedes3fd24152012-02-03 17:48:01 -0300106/*
107 * These LE scan and inquiry parameters were chosen according to LE General
108 * Discovery Procedure specification.
109 */
110#define LE_SCAN_TYPE 0x01
111#define LE_SCAN_WIN 0x12
112#define LE_SCAN_INT 0x12
113#define LE_SCAN_TIMEOUT_LE_ONLY 10240 /* TGAP(gen_disc_scan_min) */
Andre Guedes5e0452c2012-02-17 20:39:38 -0300114#define LE_SCAN_TIMEOUT_BREDR_LE 5120 /* TGAP(100)/2 */
Andre Guedes3fd24152012-02-03 17:48:01 -0300115
Andre Guedese8777522012-02-03 17:48:02 -0300116#define INQUIRY_LEN_BREDR 0x08 /* TGAP(100) */
Andre Guedes5e0452c2012-02-17 20:39:38 -0300117#define INQUIRY_LEN_BREDR_LE 0x04 /* TGAP(100)/2 */
Andre Guedes2519a1f2011-11-07 11:45:24 -0300118
Johan Hedberg7d785252011-12-15 00:47:39 +0200119#define SERVICE_CACHE_TIMEOUT (5 * 1000)
120
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200121#define hdev_is_powered(hdev) (test_bit(HCI_UP, &hdev->flags) && \
122 !test_bit(HCI_AUTO_OFF, &hdev->dev_flags))
123
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200124struct pending_cmd {
125 struct list_head list;
Johan Hedbergfc2f4b12011-11-09 13:58:56 +0200126 u16 opcode;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200127 int index;
Szymon Jancc68fb7f2011-03-22 13:12:19 +0100128 void *param;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200129 struct sock *sk;
Johan Hedberge9a416b2011-02-19 12:05:56 -0300130 void *user_data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200131};
132
Johan Hedbergca69b792011-11-11 18:10:00 +0200133/* HCI to MGMT error code conversion table */
134static u8 mgmt_status_table[] = {
135 MGMT_STATUS_SUCCESS,
136 MGMT_STATUS_UNKNOWN_COMMAND, /* Unknown Command */
137 MGMT_STATUS_NOT_CONNECTED, /* No Connection */
138 MGMT_STATUS_FAILED, /* Hardware Failure */
139 MGMT_STATUS_CONNECT_FAILED, /* Page Timeout */
140 MGMT_STATUS_AUTH_FAILED, /* Authentication Failed */
141 MGMT_STATUS_NOT_PAIRED, /* PIN or Key Missing */
142 MGMT_STATUS_NO_RESOURCES, /* Memory Full */
143 MGMT_STATUS_TIMEOUT, /* Connection Timeout */
144 MGMT_STATUS_NO_RESOURCES, /* Max Number of Connections */
145 MGMT_STATUS_NO_RESOURCES, /* Max Number of SCO Connections */
146 MGMT_STATUS_ALREADY_CONNECTED, /* ACL Connection Exists */
147 MGMT_STATUS_BUSY, /* Command Disallowed */
148 MGMT_STATUS_NO_RESOURCES, /* Rejected Limited Resources */
149 MGMT_STATUS_REJECTED, /* Rejected Security */
150 MGMT_STATUS_REJECTED, /* Rejected Personal */
151 MGMT_STATUS_TIMEOUT, /* Host Timeout */
152 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Feature */
153 MGMT_STATUS_INVALID_PARAMS, /* Invalid Parameters */
154 MGMT_STATUS_DISCONNECTED, /* OE User Ended Connection */
155 MGMT_STATUS_NO_RESOURCES, /* OE Low Resources */
156 MGMT_STATUS_DISCONNECTED, /* OE Power Off */
157 MGMT_STATUS_DISCONNECTED, /* Connection Terminated */
158 MGMT_STATUS_BUSY, /* Repeated Attempts */
159 MGMT_STATUS_REJECTED, /* Pairing Not Allowed */
160 MGMT_STATUS_FAILED, /* Unknown LMP PDU */
161 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Remote Feature */
162 MGMT_STATUS_REJECTED, /* SCO Offset Rejected */
163 MGMT_STATUS_REJECTED, /* SCO Interval Rejected */
164 MGMT_STATUS_REJECTED, /* Air Mode Rejected */
165 MGMT_STATUS_INVALID_PARAMS, /* Invalid LMP Parameters */
166 MGMT_STATUS_FAILED, /* Unspecified Error */
167 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported LMP Parameter Value */
168 MGMT_STATUS_FAILED, /* Role Change Not Allowed */
169 MGMT_STATUS_TIMEOUT, /* LMP Response Timeout */
170 MGMT_STATUS_FAILED, /* LMP Error Transaction Collision */
171 MGMT_STATUS_FAILED, /* LMP PDU Not Allowed */
172 MGMT_STATUS_REJECTED, /* Encryption Mode Not Accepted */
173 MGMT_STATUS_FAILED, /* Unit Link Key Used */
174 MGMT_STATUS_NOT_SUPPORTED, /* QoS Not Supported */
175 MGMT_STATUS_TIMEOUT, /* Instant Passed */
176 MGMT_STATUS_NOT_SUPPORTED, /* Pairing Not Supported */
177 MGMT_STATUS_FAILED, /* Transaction Collision */
178 MGMT_STATUS_INVALID_PARAMS, /* Unacceptable Parameter */
179 MGMT_STATUS_REJECTED, /* QoS Rejected */
180 MGMT_STATUS_NOT_SUPPORTED, /* Classification Not Supported */
181 MGMT_STATUS_REJECTED, /* Insufficient Security */
182 MGMT_STATUS_INVALID_PARAMS, /* Parameter Out Of Range */
183 MGMT_STATUS_BUSY, /* Role Switch Pending */
184 MGMT_STATUS_FAILED, /* Slot Violation */
185 MGMT_STATUS_FAILED, /* Role Switch Failed */
186 MGMT_STATUS_INVALID_PARAMS, /* EIR Too Large */
187 MGMT_STATUS_NOT_SUPPORTED, /* Simple Pairing Not Supported */
188 MGMT_STATUS_BUSY, /* Host Busy Pairing */
189 MGMT_STATUS_REJECTED, /* Rejected, No Suitable Channel */
190 MGMT_STATUS_BUSY, /* Controller Busy */
191 MGMT_STATUS_INVALID_PARAMS, /* Unsuitable Connection Interval */
192 MGMT_STATUS_TIMEOUT, /* Directed Advertising Timeout */
193 MGMT_STATUS_AUTH_FAILED, /* Terminated Due to MIC Failure */
194 MGMT_STATUS_CONNECT_FAILED, /* Connection Establishment Failed */
195 MGMT_STATUS_CONNECT_FAILED, /* MAC Connection Failed */
196};
197
198static u8 mgmt_status(u8 hci_status)
199{
200 if (hci_status < ARRAY_SIZE(mgmt_status_table))
201 return mgmt_status_table[hci_status];
202
203 return MGMT_STATUS_FAILED;
204}
205
Szymon Janc4e51eae2011-02-25 19:05:48 +0100206static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200207{
208 struct sk_buff *skb;
209 struct mgmt_hdr *hdr;
210 struct mgmt_ev_cmd_status *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300211 int err;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200212
Szymon Janc34eb5252011-02-28 14:10:08 +0100213 BT_DBG("sock %p, index %u, cmd %u, status %u", sk, index, cmd, status);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200214
215 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_ATOMIC);
216 if (!skb)
217 return -ENOMEM;
218
219 hdr = (void *) skb_put(skb, sizeof(*hdr));
220
221 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_STATUS);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100222 hdr->index = cpu_to_le16(index);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200223 hdr->len = cpu_to_le16(sizeof(*ev));
224
225 ev = (void *) skb_put(skb, sizeof(*ev));
226 ev->status = status;
227 put_unaligned_le16(cmd, &ev->opcode);
228
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300229 err = sock_queue_rcv_skb(sk, skb);
230 if (err < 0)
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200231 kfree_skb(skb);
232
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300233 return err;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200234}
235
Johan Hedbergaee9b2182012-02-18 15:07:59 +0200236static int cmd_complete(struct sock *sk, u16 index, u16 cmd, u8 status,
237 void *rp, size_t rp_len)
Johan Hedberg02d98122010-12-13 21:07:04 +0200238{
239 struct sk_buff *skb;
240 struct mgmt_hdr *hdr;
241 struct mgmt_ev_cmd_complete *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300242 int err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200243
244 BT_DBG("sock %p", sk);
245
Johan Hedberga38528f2011-01-22 06:46:43 +0200246 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + rp_len, GFP_ATOMIC);
Johan Hedberg02d98122010-12-13 21:07:04 +0200247 if (!skb)
248 return -ENOMEM;
249
250 hdr = (void *) skb_put(skb, sizeof(*hdr));
Johan Hedberga38528f2011-01-22 06:46:43 +0200251
Johan Hedberg02d98122010-12-13 21:07:04 +0200252 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100253 hdr->index = cpu_to_le16(index);
Johan Hedberga38528f2011-01-22 06:46:43 +0200254 hdr->len = cpu_to_le16(sizeof(*ev) + rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200255
Johan Hedberga38528f2011-01-22 06:46:43 +0200256 ev = (void *) skb_put(skb, sizeof(*ev) + rp_len);
257 put_unaligned_le16(cmd, &ev->opcode);
Johan Hedbergaee9b2182012-02-18 15:07:59 +0200258 ev->status = status;
Szymon Janc8020c162011-02-28 14:09:50 +0100259
260 if (rp)
261 memcpy(ev->data, rp, rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200262
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300263 err = sock_queue_rcv_skb(sk, skb);
264 if (err < 0)
Johan Hedberg02d98122010-12-13 21:07:04 +0200265 kfree_skb(skb);
266
Marcel Holtmanne5f0e152012-02-22 11:59:01 +0100267 return err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200268}
269
Johan Hedberg0f4e68c2012-02-28 17:18:30 +0200270static int read_version(struct sock *sk, struct hci_dev *hdev,
271 void *data, u16 data_len)
Johan Hedberga38528f2011-01-22 06:46:43 +0200272{
273 struct mgmt_rp_read_version rp;
274
275 BT_DBG("sock %p", sk);
276
277 rp.version = MGMT_VERSION;
278 put_unaligned_le16(MGMT_REVISION, &rp.revision);
279
Johan Hedbergaee9b2182012-02-18 15:07:59 +0200280 return cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, 0, &rp,
Szymon Janc4e51eae2011-02-25 19:05:48 +0100281 sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200282}
283
Johan Hedberg0f4e68c2012-02-28 17:18:30 +0200284static int read_commands(struct sock *sk, struct hci_dev *hdev,
285 void *data, u16 data_len)
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200286{
287 struct mgmt_rp_read_commands *rp;
288 u16 num_commands = ARRAY_SIZE(mgmt_commands);
289 u16 num_events = ARRAY_SIZE(mgmt_events);
290 u16 *opcode;
291 size_t rp_size;
292 int i, err;
293
294 BT_DBG("sock %p", sk);
295
296 rp_size = sizeof(*rp) + ((num_commands + num_events) * sizeof(u16));
297
298 rp = kmalloc(rp_size, GFP_KERNEL);
299 if (!rp)
300 return -ENOMEM;
301
302 put_unaligned_le16(num_commands, &rp->num_commands);
303 put_unaligned_le16(num_events, &rp->num_events);
304
305 for (i = 0, opcode = rp->opcodes; i < num_commands; i++, opcode++)
306 put_unaligned_le16(mgmt_commands[i], opcode);
307
308 for (i = 0; i < num_events; i++, opcode++)
309 put_unaligned_le16(mgmt_events[i], opcode);
310
Johan Hedbergaee9b2182012-02-18 15:07:59 +0200311 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_COMMANDS, 0, rp,
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200312 rp_size);
313 kfree(rp);
314
315 return err;
316}
317
Johan Hedberg0f4e68c2012-02-28 17:18:30 +0200318static int read_index_list(struct sock *sk, struct hci_dev *hdev,
319 void *data, u16 data_len)
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200320{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200321 struct mgmt_rp_read_index_list *rp;
322 struct list_head *p;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200323 struct hci_dev *d;
Johan Hedberga38528f2011-01-22 06:46:43 +0200324 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200325 u16 count;
Johan Hedberga38528f2011-01-22 06:46:43 +0200326 int i, err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200327
328 BT_DBG("sock %p", sk);
329
330 read_lock(&hci_dev_list_lock);
331
332 count = 0;
333 list_for_each(p, &hci_dev_list) {
334 count++;
335 }
336
Johan Hedberga38528f2011-01-22 06:46:43 +0200337 rp_len = sizeof(*rp) + (2 * count);
338 rp = kmalloc(rp_len, GFP_ATOMIC);
339 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100340 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200341 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100342 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200343
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200344 put_unaligned_le16(count, &rp->num_controllers);
345
346 i = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200347 list_for_each_entry(d, &hci_dev_list, list) {
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200348 if (test_bit(HCI_SETUP, &d->dev_flags))
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200349 continue;
350
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200351 put_unaligned_le16(d->id, &rp->index[i++]);
352 BT_DBG("Added hci%u", d->id);
353 }
354
355 read_unlock(&hci_dev_list_lock);
356
Johan Hedbergaee9b2182012-02-18 15:07:59 +0200357 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST, 0, rp,
Szymon Janc4e51eae2011-02-25 19:05:48 +0100358 rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200359
Johan Hedberga38528f2011-01-22 06:46:43 +0200360 kfree(rp);
361
362 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200363}
364
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200365static u32 get_supported_settings(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +0200366{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200367 u32 settings = 0;
Johan Hedberg03811012010-12-08 00:21:06 +0200368
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200369 settings |= MGMT_SETTING_POWERED;
370 settings |= MGMT_SETTING_CONNECTABLE;
371 settings |= MGMT_SETTING_FAST_CONNECTABLE;
372 settings |= MGMT_SETTING_DISCOVERABLE;
373 settings |= MGMT_SETTING_PAIRABLE;
Johan Hedberg03811012010-12-08 00:21:06 +0200374
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200375 if (hdev->features[6] & LMP_SIMPLE_PAIR)
376 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200377
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200378 if (!(hdev->features[4] & LMP_NO_BREDR)) {
379 settings |= MGMT_SETTING_BREDR;
380 settings |= MGMT_SETTING_LINK_SECURITY;
381 }
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200382
Marcel Holtmannd7b7e792012-02-20 21:47:49 +0100383 if (enable_hs)
384 settings |= MGMT_SETTING_HS;
385
386 if (enable_le) {
387 if (hdev->features[4] & LMP_LE)
388 settings |= MGMT_SETTING_LE;
389 }
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200390
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200391 return settings;
392}
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200393
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200394static u32 get_current_settings(struct hci_dev *hdev)
395{
396 u32 settings = 0;
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200397
Johan Hedbergf1f0eb02012-02-21 17:15:41 +0200398 if (hdev_is_powered(hdev))
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100399 settings |= MGMT_SETTING_POWERED;
400
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200401 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200402 settings |= MGMT_SETTING_CONNECTABLE;
403
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200404 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200405 settings |= MGMT_SETTING_DISCOVERABLE;
406
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200407 if (test_bit(HCI_PAIRABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200408 settings |= MGMT_SETTING_PAIRABLE;
409
410 if (!(hdev->features[4] & LMP_NO_BREDR))
411 settings |= MGMT_SETTING_BREDR;
412
Johan Hedberg06199cf2012-02-22 16:37:11 +0200413 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200414 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200415
Johan Hedberg47990ea2012-02-22 11:58:37 +0200416 if (test_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200417 settings |= MGMT_SETTING_LINK_SECURITY;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200418
Johan Hedberg84bde9d2012-01-25 14:21:06 +0200419 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200420 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200421
Johan Hedberg6d80dfd2012-02-20 23:50:38 +0200422 if (test_bit(HCI_HS_ENABLED, &hdev->dev_flags))
423 settings |= MGMT_SETTING_HS;
424
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200425 return settings;
Johan Hedbergc542a062011-01-26 13:11:03 +0200426}
427
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300428#define PNP_INFO_SVCLASS_ID 0x1200
429
430static u8 bluetooth_base_uuid[] = {
431 0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80,
432 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
433};
434
435static u16 get_uuid16(u8 *uuid128)
436{
437 u32 val;
438 int i;
439
440 for (i = 0; i < 12; i++) {
441 if (bluetooth_base_uuid[i] != uuid128[i])
442 return 0;
443 }
444
445 memcpy(&val, &uuid128[12], 4);
446
447 val = le32_to_cpu(val);
448 if (val > 0xffff)
449 return 0;
450
451 return (u16) val;
452}
453
454static void create_eir(struct hci_dev *hdev, u8 *data)
455{
456 u8 *ptr = data;
457 u16 eir_len = 0;
458 u16 uuid16_list[HCI_MAX_EIR_LENGTH / sizeof(u16)];
459 int i, truncated = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200460 struct bt_uuid *uuid;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300461 size_t name_len;
462
463 name_len = strlen(hdev->dev_name);
464
465 if (name_len > 0) {
466 /* EIR Data type */
467 if (name_len > 48) {
468 name_len = 48;
469 ptr[1] = EIR_NAME_SHORT;
470 } else
471 ptr[1] = EIR_NAME_COMPLETE;
472
473 /* EIR Data length */
474 ptr[0] = name_len + 1;
475
476 memcpy(ptr + 2, hdev->dev_name, name_len);
477
478 eir_len += (name_len + 2);
479 ptr += (name_len + 2);
480 }
481
482 memset(uuid16_list, 0, sizeof(uuid16_list));
483
484 /* Group all UUID16 types */
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200485 list_for_each_entry(uuid, &hdev->uuids, list) {
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300486 u16 uuid16;
487
488 uuid16 = get_uuid16(uuid->uuid);
489 if (uuid16 == 0)
490 return;
491
492 if (uuid16 < 0x1100)
493 continue;
494
495 if (uuid16 == PNP_INFO_SVCLASS_ID)
496 continue;
497
498 /* Stop if not enough space to put next UUID */
499 if (eir_len + 2 + sizeof(u16) > HCI_MAX_EIR_LENGTH) {
500 truncated = 1;
501 break;
502 }
503
504 /* Check for duplicates */
505 for (i = 0; uuid16_list[i] != 0; i++)
506 if (uuid16_list[i] == uuid16)
507 break;
508
509 if (uuid16_list[i] == 0) {
510 uuid16_list[i] = uuid16;
511 eir_len += sizeof(u16);
512 }
513 }
514
515 if (uuid16_list[0] != 0) {
516 u8 *length = ptr;
517
518 /* EIR Data type */
519 ptr[1] = truncated ? EIR_UUID16_SOME : EIR_UUID16_ALL;
520
521 ptr += 2;
522 eir_len += 2;
523
524 for (i = 0; uuid16_list[i] != 0; i++) {
525 *ptr++ = (uuid16_list[i] & 0x00ff);
526 *ptr++ = (uuid16_list[i] & 0xff00) >> 8;
527 }
528
529 /* EIR Data length */
530 *length = (i * sizeof(u16)) + 1;
531 }
532}
533
534static int update_eir(struct hci_dev *hdev)
535{
536 struct hci_cp_write_eir cp;
537
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200538 if (!hdev_is_powered(hdev))
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200539 return 0;
540
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300541 if (!(hdev->features[6] & LMP_EXT_INQ))
542 return 0;
543
Johan Hedberg84bde9d2012-01-25 14:21:06 +0200544 if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300545 return 0;
546
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200547 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300548 return 0;
549
550 memset(&cp, 0, sizeof(cp));
551
552 create_eir(hdev, cp.data);
553
554 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
555 return 0;
556
557 memcpy(hdev->eir, cp.data, sizeof(cp.data));
558
559 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
560}
561
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200562static u8 get_service_classes(struct hci_dev *hdev)
563{
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300564 struct bt_uuid *uuid;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200565 u8 val = 0;
566
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300567 list_for_each_entry(uuid, &hdev->uuids, list)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200568 val |= uuid->svc_hint;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200569
570 return val;
571}
572
573static int update_class(struct hci_dev *hdev)
574{
575 u8 cod[3];
Johan Hedbergc95f0ba2012-02-23 22:54:38 +0200576 int err;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200577
578 BT_DBG("%s", hdev->name);
579
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200580 if (!hdev_is_powered(hdev))
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200581 return 0;
582
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200583 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200584 return 0;
585
586 cod[0] = hdev->minor_class;
587 cod[1] = hdev->major_class;
588 cod[2] = get_service_classes(hdev);
589
590 if (memcmp(cod, hdev->dev_class, 3) == 0)
591 return 0;
592
Johan Hedbergc95f0ba2012-02-23 22:54:38 +0200593 err = hci_send_cmd(hdev, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
594 if (err == 0)
595 set_bit(HCI_PENDING_CLASS, &hdev->dev_flags);
596
597 return err;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200598}
599
Johan Hedberg7d785252011-12-15 00:47:39 +0200600static void service_cache_off(struct work_struct *work)
601{
602 struct hci_dev *hdev = container_of(work, struct hci_dev,
603 service_cache.work);
604
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200605 if (!test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200606 return;
607
608 hci_dev_lock(hdev);
609
610 update_eir(hdev);
611 update_class(hdev);
612
613 hci_dev_unlock(hdev);
614}
615
Johan Hedberg6a919082012-02-28 06:17:26 +0200616static void mgmt_init_hdev(struct sock *sk, struct hci_dev *hdev)
Johan Hedberg7d785252011-12-15 00:47:39 +0200617{
Johan Hedberg6a919082012-02-28 06:17:26 +0200618 if (!test_and_clear_bit(HCI_PI_MGMT_INIT, &hci_pi(sk)->flags))
619 return;
620
Johan Hedberg0cbf4ed62012-02-21 17:25:22 +0200621 if (!test_and_set_bit(HCI_MGMT, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +0200622 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
623
Johan Hedberg0cbf4ed62012-02-21 17:25:22 +0200624 /* Non-mgmt controlled devices get this bit set
625 * implicitly so that pairing works for them, however
626 * for mgmt we require user-space to explicitly enable
627 * it
628 */
629 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
630 }
Johan Hedberg7d785252011-12-15 00:47:39 +0200631}
632
Johan Hedberg0f4e68c2012-02-28 17:18:30 +0200633static int read_controller_info(struct sock *sk, struct hci_dev *hdev,
634 void *data, u16 data_len)
Johan Hedberg03811012010-12-08 00:21:06 +0200635{
636 struct mgmt_rp_read_info rp;
Johan Hedberg03811012010-12-08 00:21:06 +0200637
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200638 BT_DBG("sock %p %s", sk, hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200639
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300640 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200641
Johan Hedberg03811012010-12-08 00:21:06 +0200642 memset(&rp, 0, sizeof(rp));
643
Johan Hedberg03811012010-12-08 00:21:06 +0200644 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200645
646 rp.version = hdev->hci_ver;
647
Johan Hedberg03811012010-12-08 00:21:06 +0200648 put_unaligned_le16(hdev->manufacturer, &rp.manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200649
650 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
651 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
652
653 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedberg03811012010-12-08 00:21:06 +0200654
655 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
Johan Hedberg27fcc362012-02-22 21:46:22 +0200656 memcpy(rp.short_name, hdev->short_name, sizeof(hdev->short_name));
Johan Hedberg03811012010-12-08 00:21:06 +0200657
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300658 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200659
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200660 return cmd_complete(sk, hdev->id, MGMT_OP_READ_INFO, 0, &rp,
661 sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +0200662}
663
664static void mgmt_pending_free(struct pending_cmd *cmd)
665{
666 sock_put(cmd->sk);
667 kfree(cmd->param);
668 kfree(cmd);
669}
670
671static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
672 struct hci_dev *hdev,
673 void *data, u16 len)
674{
675 struct pending_cmd *cmd;
676
677 cmd = kmalloc(sizeof(*cmd), GFP_ATOMIC);
678 if (!cmd)
679 return NULL;
680
681 cmd->opcode = opcode;
682 cmd->index = hdev->id;
683
684 cmd->param = kmalloc(len, GFP_ATOMIC);
685 if (!cmd->param) {
686 kfree(cmd);
687 return NULL;
688 }
689
690 if (data)
691 memcpy(cmd->param, data, len);
692
693 cmd->sk = sk;
694 sock_hold(sk);
695
696 list_add(&cmd->list, &hdev->mgmt_pending);
697
698 return cmd;
699}
700
701static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
702 void (*cb)(struct pending_cmd *cmd, void *data),
703 void *data)
704{
705 struct list_head *p, *n;
706
707 list_for_each_safe(p, n, &hdev->mgmt_pending) {
708 struct pending_cmd *cmd;
709
710 cmd = list_entry(p, struct pending_cmd, list);
711
712 if (opcode > 0 && cmd->opcode != opcode)
713 continue;
714
715 cb(cmd, data);
716 }
717}
718
719static struct pending_cmd *mgmt_pending_find(u16 opcode, struct hci_dev *hdev)
720{
721 struct pending_cmd *cmd;
722
723 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
724 if (cmd->opcode == opcode)
725 return cmd;
726 }
727
728 return NULL;
729}
730
731static void mgmt_pending_remove(struct pending_cmd *cmd)
732{
733 list_del(&cmd->list);
734 mgmt_pending_free(cmd);
735}
736
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200737static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +0200738{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200739 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +0200740
Johan Hedbergaee9b2182012-02-18 15:07:59 +0200741 return cmd_complete(sk, hdev->id, opcode, 0, &settings,
742 sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +0200743}
744
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200745static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data,
746 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200747{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300748 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200749 struct pending_cmd *cmd;
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200750 int err;
Johan Hedberg03811012010-12-08 00:21:06 +0200751
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200752 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200753
754 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200755 return cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
Johan Hedbergca69b792011-11-11 18:10:00 +0200756 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200757
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300758 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200759
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100760 if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) {
761 cancel_delayed_work(&hdev->power_off);
762
763 if (cp->val) {
764 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
765 mgmt_powered(hdev, 1);
766 goto failed;
767 }
768 }
769
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200770 if (!!cp->val == hdev_is_powered(hdev)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200771 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200772 goto failed;
773 }
774
775 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200776 err = cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
Johan Hedbergca69b792011-11-11 18:10:00 +0200777 MGMT_STATUS_BUSY);
Johan Hedberg03811012010-12-08 00:21:06 +0200778 goto failed;
779 }
780
781 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
782 if (!cmd) {
783 err = -ENOMEM;
784 goto failed;
785 }
786
787 if (cp->val)
Gustavo F. Padovan7f971042011-12-18 12:40:32 -0200788 schedule_work(&hdev->power_on);
Johan Hedberg03811012010-12-08 00:21:06 +0200789 else
Gustavo F. Padovan80b7ab32011-12-17 14:52:27 -0200790 schedule_work(&hdev->power_off.work);
Johan Hedberg03811012010-12-08 00:21:06 +0200791
792 err = 0;
793
794failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300795 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200796 return err;
797}
798
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200799static int mgmt_event(u16 event, struct hci_dev *hdev, void *data,
800 u16 data_len, struct sock *skip_sk)
801{
802 struct sk_buff *skb;
803 struct mgmt_hdr *hdr;
804
805 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_ATOMIC);
806 if (!skb)
807 return -ENOMEM;
808
809 hdr = (void *) skb_put(skb, sizeof(*hdr));
810 hdr->opcode = cpu_to_le16(event);
811 if (hdev)
812 hdr->index = cpu_to_le16(hdev->id);
813 else
814 hdr->index = cpu_to_le16(MGMT_INDEX_NONE);
815 hdr->len = cpu_to_le16(data_len);
816
817 if (data)
818 memcpy(skb_put(skb, data_len), data, data_len);
819
Marcel Holtmann97e0bde2012-02-22 13:49:28 +0100820 /* Time stamp */
821 __net_timestamp(skb);
822
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200823 hci_send_to_control(skb, skip_sk);
824 kfree_skb(skb);
825
826 return 0;
827}
828
829static int new_settings(struct hci_dev *hdev, struct sock *skip)
830{
831 __le32 ev;
832
833 ev = cpu_to_le32(get_current_settings(hdev));
834
835 return mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), skip);
836}
837
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200838static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
839 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200840{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300841 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200842 struct pending_cmd *cmd;
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200843 u16 timeout;
Johan Hedberg03811012010-12-08 00:21:06 +0200844 u8 scan;
845 int err;
846
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200847 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200848
849 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200850 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +0200851 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200852
Marcel Holtmann24c54a92012-02-22 18:06:34 +0100853 timeout = get_unaligned_le16(&cp->timeout);
854 if (!cp->val && timeout > 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200855 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +0200856 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200857
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300858 hci_dev_lock(hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200859
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200860 if (!hdev_is_powered(hdev) && timeout > 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200861 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +0200862 MGMT_STATUS_NOT_POWERED);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200863 goto failed;
864 }
865
866 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
867 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200868 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +0200869 MGMT_STATUS_BUSY);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200870 goto failed;
871 }
872
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200873 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200874 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200875 MGMT_STATUS_REJECTED);
876 goto failed;
877 }
878
879 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200880 bool changed = false;
881
882 if (!!cp->val != test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
883 change_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
884 changed = true;
885 }
886
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200887 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200888 if (err < 0)
889 goto failed;
890
891 if (changed)
892 err = new_settings(hdev, sk);
893
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200894 goto failed;
895 }
896
897 if (!!cp->val == test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
Marcel Holtmann955638e2012-02-22 18:21:00 +0100898 if (hdev->discov_timeout > 0) {
899 cancel_delayed_work(&hdev->discov_off);
900 hdev->discov_timeout = 0;
901 }
902
903 if (cp->val && timeout > 0) {
904 hdev->discov_timeout = timeout;
905 queue_delayed_work(hdev->workqueue, &hdev->discov_off,
906 msecs_to_jiffies(hdev->discov_timeout * 1000));
907 }
908
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200909 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200910 goto failed;
911 }
912
913 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
914 if (!cmd) {
915 err = -ENOMEM;
916 goto failed;
917 }
918
919 scan = SCAN_PAGE;
920
921 if (cp->val)
922 scan |= SCAN_INQUIRY;
923 else
924 cancel_delayed_work(&hdev->discov_off);
925
926 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
927 if (err < 0)
928 mgmt_pending_remove(cmd);
929
Johan Hedberg03811012010-12-08 00:21:06 +0200930 if (cp->val)
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200931 hdev->discov_timeout = timeout;
Johan Hedberg03811012010-12-08 00:21:06 +0200932
933failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300934 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200935 return err;
936}
937
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200938static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
939 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200940{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300941 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200942 struct pending_cmd *cmd;
943 u8 scan;
944 int err;
945
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200946 BT_DBG("request for %s", hdev->name);
Johan Hedberge41d8b42010-12-13 21:07:03 +0200947
Johan Hedberg03811012010-12-08 00:21:06 +0200948 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200949 return cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +0200950 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200951
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300952 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200953
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200954 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200955 bool changed = false;
956
957 if (!!cp->val != test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
958 changed = true;
959
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +0200960 if (cp->val) {
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200961 set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +0200962 } else {
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200963 clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
964 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
965 }
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200966
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200967 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200968 if (err < 0)
969 goto failed;
970
971 if (changed)
972 err = new_settings(hdev, sk);
973
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200974 goto failed;
975 }
976
977 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
978 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200979 err = cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +0200980 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200981 goto failed;
982 }
983
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200984 if (!!cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200985 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200986 goto failed;
987 }
988
989 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
990 if (!cmd) {
991 err = -ENOMEM;
992 goto failed;
993 }
994
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +0200995 if (cp->val) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200996 scan = SCAN_PAGE;
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +0200997 } else {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200998 scan = 0;
999
Johan Hedbergdf2c6c52012-02-21 19:15:49 +02001000 if (test_bit(HCI_ISCAN, &hdev->flags) &&
1001 hdev->discov_timeout > 0)
1002 cancel_delayed_work(&hdev->discov_off);
1003 }
1004
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001005 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1006 if (err < 0)
1007 mgmt_pending_remove(cmd);
1008
1009failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001010 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001011 return err;
1012}
1013
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001014static int set_pairable(struct sock *sk, struct hci_dev *hdev, void *data,
1015 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001016{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001017 struct mgmt_mode *cp = data;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001018 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001019
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001020 BT_DBG("request for %s", hdev->name);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001021
1022 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001023 return cmd_status(sk, hdev->id, MGMT_OP_SET_PAIRABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02001024 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001025
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001026 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001027
1028 if (cp->val)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001029 set_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001030 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001031 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001032
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001033 err = send_settings_rsp(sk, MGMT_OP_SET_PAIRABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001034 if (err < 0)
1035 goto failed;
1036
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001037 err = new_settings(hdev, sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001038
1039failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001040 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001041 return err;
1042}
Johan Hedberg72a734e2010-12-30 00:38:22 +02001043
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001044static int set_link_security(struct sock *sk, struct hci_dev *hdev,
1045 void *data, u16 len)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001046{
1047 struct mgmt_mode *cp = data;
1048 struct pending_cmd *cmd;
Johan Hedberg816a11d2012-02-26 13:04:52 +02001049 u8 val;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001050 int err;
1051
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001052 BT_DBG("request for %s", hdev->name);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001053
1054 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001055 return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001056 MGMT_STATUS_INVALID_PARAMS);
1057
1058 hci_dev_lock(hdev);
1059
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001060 if (!hdev_is_powered(hdev)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001061 bool changed = false;
1062
1063 if (!!cp->val != test_bit(HCI_LINK_SECURITY,
1064 &hdev->dev_flags)) {
1065 change_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
1066 changed = true;
1067 }
1068
1069 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1070 if (err < 0)
1071 goto failed;
1072
1073 if (changed)
1074 err = new_settings(hdev, sk);
1075
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001076 goto failed;
1077 }
1078
1079 if (mgmt_pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001080 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001081 MGMT_STATUS_BUSY);
1082 goto failed;
1083 }
1084
1085 val = !!cp->val;
1086
1087 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1088 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1089 goto failed;
1090 }
1091
1092 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1093 if (!cmd) {
1094 err = -ENOMEM;
1095 goto failed;
1096 }
1097
1098 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1099 if (err < 0) {
1100 mgmt_pending_remove(cmd);
1101 goto failed;
1102 }
1103
1104failed:
1105 hci_dev_unlock(hdev);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001106 return err;
1107}
1108
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001109static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001110{
1111 struct mgmt_mode *cp = data;
1112 struct pending_cmd *cmd;
Johan Hedberg816a11d2012-02-26 13:04:52 +02001113 u8 val;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001114 int err;
1115
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001116 BT_DBG("request for %s", hdev->name);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001117
1118 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001119 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001120 MGMT_STATUS_INVALID_PARAMS);
1121
1122 hci_dev_lock(hdev);
1123
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001124 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001125 err = cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001126 MGMT_STATUS_NOT_SUPPORTED);
1127 goto failed;
1128 }
1129
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001130 val = !!cp->val;
1131
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001132 if (!hdev_is_powered(hdev)) {
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001133 bool changed = false;
1134
1135 if (val != test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) {
1136 change_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
1137 changed = true;
1138 }
1139
1140 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1141 if (err < 0)
1142 goto failed;
1143
1144 if (changed)
1145 err = new_settings(hdev, sk);
1146
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001147 goto failed;
1148 }
1149
1150 if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001151 err = cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1152 MGMT_STATUS_BUSY);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001153 goto failed;
1154 }
1155
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001156 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) == val) {
1157 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1158 goto failed;
1159 }
1160
1161 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1162 if (!cmd) {
1163 err = -ENOMEM;
1164 goto failed;
1165 }
1166
1167 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, sizeof(val), &val);
1168 if (err < 0) {
1169 mgmt_pending_remove(cmd);
1170 goto failed;
1171 }
1172
1173failed:
1174 hci_dev_unlock(hdev);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001175 return err;
1176}
1177
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001178static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001179{
1180 struct mgmt_mode *cp = data;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001181
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001182 BT_DBG("request for %s", hdev->name);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001183
1184 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001185 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001186 MGMT_STATUS_INVALID_PARAMS);
1187
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001188 if (!enable_hs)
1189 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1190 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001191
1192 if (cp->val)
1193 set_bit(HCI_HS_ENABLED, &hdev->dev_flags);
1194 else
1195 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
1196
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001197 return send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001198}
1199
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001200static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001201{
1202 struct mgmt_mode *cp = data;
1203 struct hci_cp_write_le_host_supported hci_cp;
1204 struct pending_cmd *cmd;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001205 int err;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001206 u8 val, enabled;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001207
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001208 BT_DBG("request for %s", hdev->name);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001209
1210 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001211 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
Johan Hedberg06199cf2012-02-22 16:37:11 +02001212 MGMT_STATUS_INVALID_PARAMS);
1213
Johan Hedberg1de028c2012-02-29 19:55:35 -08001214 hci_dev_lock(hdev);
1215
Johan Hedberg06199cf2012-02-22 16:37:11 +02001216 if (!enable_le || !(hdev->features[4] & LMP_LE)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001217 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
Johan Hedberg06199cf2012-02-22 16:37:11 +02001218 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001219 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001220 }
1221
1222 val = !!cp->val;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001223 enabled = !!(hdev->host_features[0] & LMP_HOST_LE);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001224
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001225 if (!hdev_is_powered(hdev) || val == enabled) {
Johan Hedberg06199cf2012-02-22 16:37:11 +02001226 bool changed = false;
1227
1228 if (val != test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
1229 change_bit(HCI_LE_ENABLED, &hdev->dev_flags);
1230 changed = true;
1231 }
1232
1233 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1234 if (err < 0)
Johan Hedberg1de028c2012-02-29 19:55:35 -08001235 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001236
1237 if (changed)
1238 err = new_settings(hdev, sk);
1239
Johan Hedberg1de028c2012-02-29 19:55:35 -08001240 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001241 }
1242
1243 if (mgmt_pending_find(MGMT_OP_SET_LE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001244 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1245 MGMT_STATUS_BUSY);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001246 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001247 }
1248
1249 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
1250 if (!cmd) {
1251 err = -ENOMEM;
Johan Hedberg1de028c2012-02-29 19:55:35 -08001252 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001253 }
1254
1255 memset(&hci_cp, 0, sizeof(hci_cp));
1256
1257 if (val) {
1258 hci_cp.le = val;
1259 hci_cp.simul = !!(hdev->features[6] & LMP_SIMUL_LE_BR);
1260 }
1261
1262 err = hci_send_cmd(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED,
1263 sizeof(hci_cp), &hci_cp);
1264 if (err < 0) {
1265 mgmt_pending_remove(cmd);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001266 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001267 }
1268
Johan Hedberg1de028c2012-02-29 19:55:35 -08001269unlock:
1270 hci_dev_unlock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001271 return err;
1272}
1273
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001274static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001275{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001276 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001277 struct pending_cmd *cmd;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001278 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001279 int err;
1280
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001281 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001282
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001283 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001284 return cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID,
Johan Hedbergca69b792011-11-11 18:10:00 +02001285 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001286
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001287 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001288
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001289 if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001290 err = cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID,
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001291 MGMT_STATUS_BUSY);
1292 goto failed;
1293 }
1294
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001295 uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC);
1296 if (!uuid) {
1297 err = -ENOMEM;
1298 goto failed;
1299 }
1300
1301 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001302 uuid->svc_hint = cp->svc_hint;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001303
1304 list_add(&uuid->list, &hdev->uuids);
1305
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001306 err = update_class(hdev);
1307 if (err < 0)
1308 goto failed;
1309
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001310 err = update_eir(hdev);
1311 if (err < 0)
1312 goto failed;
1313
Johan Hedberg90e70452012-02-23 23:09:40 +02001314 if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001315 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0,
Johan Hedberg90e70452012-02-23 23:09:40 +02001316 hdev->dev_class, 3);
1317 goto failed;
1318 }
1319
1320 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len);
1321 if (!cmd) {
1322 err = -ENOMEM;
1323 goto failed;
1324 }
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001325
1326failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001327 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001328 return err;
1329}
1330
Johan Hedberg24b78d02012-02-23 23:24:30 +02001331static bool enable_service_cache(struct hci_dev *hdev)
1332{
1333 if (!hdev_is_powered(hdev))
1334 return false;
1335
1336 if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
1337 schedule_delayed_work(&hdev->service_cache,
1338 msecs_to_jiffies(SERVICE_CACHE_TIMEOUT));
1339 return true;
1340 }
1341
1342 return false;
1343}
1344
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001345static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
1346 u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001347{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001348 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001349 struct pending_cmd *cmd;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001350 struct list_head *p, *n;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001351 u8 bt_uuid_any[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001352 int err, found;
1353
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001354 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001355
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001356 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001357 return cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Johan Hedbergca69b792011-11-11 18:10:00 +02001358 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001359
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001360 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001361
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001362 if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001363 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001364 MGMT_STATUS_BUSY);
1365 goto unlock;
1366 }
1367
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001368 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
1369 err = hci_uuids_clear(hdev);
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001370
Johan Hedberg24b78d02012-02-23 23:24:30 +02001371 if (enable_service_cache(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001372 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID,
1373 0, hdev->dev_class, 3);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001374 goto unlock;
1375 }
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001376
Johan Hedberg9246a862012-02-23 21:33:16 +02001377 goto update_class;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001378 }
1379
1380 found = 0;
1381
1382 list_for_each_safe(p, n, &hdev->uuids) {
1383 struct bt_uuid *match = list_entry(p, struct bt_uuid, list);
1384
1385 if (memcmp(match->uuid, cp->uuid, 16) != 0)
1386 continue;
1387
1388 list_del(&match->list);
1389 found++;
1390 }
1391
1392 if (found == 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001393 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Johan Hedbergca69b792011-11-11 18:10:00 +02001394 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001395 goto unlock;
1396 }
1397
Johan Hedberg9246a862012-02-23 21:33:16 +02001398update_class:
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001399 err = update_class(hdev);
1400 if (err < 0)
1401 goto unlock;
1402
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001403 err = update_eir(hdev);
1404 if (err < 0)
1405 goto unlock;
1406
Johan Hedberg90e70452012-02-23 23:09:40 +02001407 if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001408 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0,
Johan Hedberg9997a532012-02-23 15:57:46 +02001409 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001410 goto unlock;
1411 }
1412
1413 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
1414 if (!cmd) {
1415 err = -ENOMEM;
1416 goto unlock;
1417 }
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001418
1419unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001420 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001421 return err;
1422}
1423
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001424static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
1425 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001426{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001427 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001428 struct pending_cmd *cmd;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001429 int err;
1430
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001431 BT_DBG("request for %s", hdev->name);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001432
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001433 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001434 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
Johan Hedbergca69b792011-11-11 18:10:00 +02001435 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001436
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001437 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001438
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001439 if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001440 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001441 MGMT_STATUS_BUSY);
1442 goto unlock;
1443 }
1444
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001445 hdev->major_class = cp->major;
1446 hdev->minor_class = cp->minor;
1447
Johan Hedberg932f5ff2012-02-22 22:11:32 +02001448 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001449 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Johan Hedberg932f5ff2012-02-22 22:11:32 +02001450 hdev->dev_class, 3);
1451 goto unlock;
1452 }
1453
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001454 if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02001455 hci_dev_unlock(hdev);
1456 cancel_delayed_work_sync(&hdev->service_cache);
1457 hci_dev_lock(hdev);
Johan Hedberg14c0b602011-12-15 00:47:37 +02001458 update_eir(hdev);
Johan Hedberg7d785252011-12-15 00:47:39 +02001459 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02001460
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001461 err = update_class(hdev);
Johan Hedberg90e70452012-02-23 23:09:40 +02001462 if (err < 0)
1463 goto unlock;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001464
Johan Hedberg90e70452012-02-23 23:09:40 +02001465 if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001466 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Johan Hedberg8ec37032012-02-22 22:02:50 +02001467 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001468 goto unlock;
1469 }
1470
1471 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
1472 if (!cmd) {
1473 err = -ENOMEM;
1474 goto unlock;
1475 }
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001476
Johan Hedbergb5235a62012-02-21 14:32:24 +02001477unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001478 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001479 return err;
1480}
1481
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001482static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
1483 u16 len)
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001484{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001485 struct mgmt_cp_load_link_keys *cp = data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001486 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001487 int i;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001488
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001489 if (len < sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001490 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
Johan Hedbergca69b792011-11-11 18:10:00 +02001491 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001492
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001493 key_count = get_unaligned_le16(&cp->key_count);
1494
Johan Hedberg86742e12011-11-07 23:13:38 +02001495 expected_len = sizeof(*cp) + key_count *
1496 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001497 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001498 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001499 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001500 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
Johan Hedbergca69b792011-11-11 18:10:00 +02001501 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001502 }
1503
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001504 BT_DBG("%s debug_keys %u key_count %u", hdev->name, cp->debug_keys,
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001505 key_count);
1506
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001507 hci_dev_lock(hdev);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001508
1509 hci_link_keys_clear(hdev);
1510
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001511 set_bit(HCI_LINK_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001512
1513 if (cp->debug_keys)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001514 set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001515 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001516 clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001517
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001518 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001519 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001520
Johan Hedbergd753fdc2012-02-17 14:06:34 +02001521 hci_add_link_key(hdev, NULL, 0, &key->addr.bdaddr, key->val,
1522 key->type, key->pin_len);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001523 }
1524
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001525 cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02001526
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001527 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001528
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001529 return 0;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001530}
1531
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001532static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
1533 u8 addr_type, struct sock *skip_sk)
1534{
1535 struct mgmt_ev_device_unpaired ev;
1536
1537 bacpy(&ev.addr.bdaddr, bdaddr);
1538 ev.addr.type = addr_type;
1539
1540 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
1541 skip_sk);
1542}
1543
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001544static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
1545 u16 len)
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001546{
Johan Hedberg124f6e32012-02-09 13:50:12 +02001547 struct mgmt_cp_unpair_device *cp = data;
1548 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001549 struct hci_cp_disconnect dc;
1550 struct pending_cmd *cmd;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001551 struct hci_conn *conn;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001552 int err;
1553
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001554 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001555 return cmd_status(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02001556 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001557
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001558 hci_dev_lock(hdev);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001559
Johan Hedberga8a1d192011-11-10 15:54:38 +02001560 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02001561 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1562 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001563
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001564 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001565 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001566 MGMT_STATUS_NOT_POWERED,
1567 &rp, sizeof(rp));
1568 goto unlock;
1569 }
1570
Johan Hedberg124f6e32012-02-09 13:50:12 +02001571 if (cp->addr.type == MGMT_ADDR_BREDR)
1572 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
1573 else
1574 err = hci_remove_ltk(hdev, &cp->addr.bdaddr);
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03001575
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001576 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001577 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001578 MGMT_STATUS_NOT_PAIRED,
1579 &rp, sizeof(rp));
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001580 goto unlock;
1581 }
1582
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001583 if (cp->disconnect) {
1584 if (cp->addr.type == MGMT_ADDR_BREDR)
1585 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
1586 &cp->addr.bdaddr);
1587 else
1588 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
1589 &cp->addr.bdaddr);
1590 } else {
1591 conn = NULL;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001592 }
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001593
Johan Hedberga8a1d192011-11-10 15:54:38 +02001594 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001595 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0,
Johan Hedbergaee9b2182012-02-18 15:07:59 +02001596 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001597 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001598 goto unlock;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001599 }
1600
Johan Hedberg124f6e32012-02-09 13:50:12 +02001601 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
1602 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02001603 if (!cmd) {
1604 err = -ENOMEM;
1605 goto unlock;
1606 }
1607
1608 put_unaligned_le16(conn->handle, &dc.handle);
1609 dc.reason = 0x13; /* Remote User Terminated Connection */
1610 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1611 if (err < 0)
1612 mgmt_pending_remove(cmd);
1613
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001614unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001615 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001616 return err;
1617}
1618
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001619static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
1620 u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02001621{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001622 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001623 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03001624 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001625 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001626 int err;
1627
1628 BT_DBG("");
1629
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001630 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001631 return cmd_status(sk, hdev->id, MGMT_OP_DISCONNECT,
Johan Hedbergca69b792011-11-11 18:10:00 +02001632 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001633
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001634 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001635
1636 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001637 err = cmd_status(sk, hdev->id, MGMT_OP_DISCONNECT,
Johan Hedbergca69b792011-11-11 18:10:00 +02001638 MGMT_STATUS_NOT_POWERED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001639 goto failed;
1640 }
1641
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001642 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001643 err = cmd_status(sk, hdev->id, MGMT_OP_DISCONNECT,
Johan Hedbergca69b792011-11-11 18:10:00 +02001644 MGMT_STATUS_BUSY);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001645 goto failed;
1646 }
1647
Johan Hedberg88c3df12012-02-09 14:27:38 +02001648 if (cp->addr.type == MGMT_ADDR_BREDR)
1649 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
1650 else
1651 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03001652
Johan Hedberg8962ee72011-01-20 12:40:27 +02001653 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001654 err = cmd_status(sk, hdev->id, MGMT_OP_DISCONNECT,
Johan Hedbergca69b792011-11-11 18:10:00 +02001655 MGMT_STATUS_NOT_CONNECTED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001656 goto failed;
1657 }
1658
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001659 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001660 if (!cmd) {
1661 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001662 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001663 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001664
1665 put_unaligned_le16(conn->handle, &dc.handle);
1666 dc.reason = 0x13; /* Remote User Terminated Connection */
1667
1668 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1669 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001670 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001671
1672failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001673 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001674 return err;
1675}
1676
Johan Hedberg48264f02011-11-09 13:58:58 +02001677static u8 link_to_mgmt(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02001678{
1679 switch (link_type) {
1680 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02001681 switch (addr_type) {
1682 case ADDR_LE_DEV_PUBLIC:
1683 return MGMT_ADDR_LE_PUBLIC;
1684 case ADDR_LE_DEV_RANDOM:
1685 return MGMT_ADDR_LE_RANDOM;
1686 default:
1687 return MGMT_ADDR_INVALID;
1688 }
Johan Hedberg4c659c32011-11-07 23:13:39 +02001689 case ACL_LINK:
1690 return MGMT_ADDR_BREDR;
1691 default:
1692 return MGMT_ADDR_INVALID;
1693 }
1694}
1695
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02001696static int get_connections(struct sock *sk, struct hci_dev *hdev,
1697 void *data, u16 data_len)
Johan Hedberg2784eb42011-01-21 13:56:35 +02001698{
Johan Hedberg2784eb42011-01-21 13:56:35 +02001699 struct mgmt_rp_get_connections *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001700 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02001701 size_t rp_len;
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001702 int err;
1703 u16 i;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001704
1705 BT_DBG("");
1706
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001707 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001708
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001709 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001710 err = cmd_status(sk, hdev->id, MGMT_OP_GET_CONNECTIONS,
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001711 MGMT_STATUS_NOT_POWERED);
1712 goto unlock;
1713 }
1714
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001715 i = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02001716 list_for_each_entry(c, &hdev->conn_hash.list, list) {
1717 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001718 i++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001719 }
1720
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001721 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberga38528f2011-01-22 06:46:43 +02001722 rp = kmalloc(rp_len, GFP_ATOMIC);
1723 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02001724 err = -ENOMEM;
1725 goto unlock;
1726 }
1727
Johan Hedberg2784eb42011-01-21 13:56:35 +02001728 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001729 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02001730 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
1731 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001732 bacpy(&rp->addr[i].bdaddr, &c->dst);
Johan Hedberg48264f02011-11-09 13:58:58 +02001733 rp->addr[i].type = link_to_mgmt(c->type, c->dst_type);
Johan Hedberg4c659c32011-11-07 23:13:39 +02001734 if (rp->addr[i].type == MGMT_ADDR_INVALID)
1735 continue;
1736 i++;
1737 }
1738
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001739 put_unaligned_le16(i, &rp->conn_count);
1740
Johan Hedberg4c659c32011-11-07 23:13:39 +02001741 /* Recalculate length in case of filtered SCO connections, etc */
1742 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02001743
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001744 err = cmd_complete(sk, hdev->id, MGMT_OP_GET_CONNECTIONS, 0, rp,
1745 rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001746
Johan Hedberga38528f2011-01-22 06:46:43 +02001747 kfree(rp);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001748
1749unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001750 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001751 return err;
1752}
1753
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001754static int send_pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
1755 struct mgmt_cp_pin_code_neg_reply *cp)
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001756{
1757 struct pending_cmd *cmd;
1758 int err;
1759
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001760 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001761 sizeof(*cp));
1762 if (!cmd)
1763 return -ENOMEM;
1764
Johan Hedbergd8457692012-02-17 14:24:57 +02001765 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
1766 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001767 if (err < 0)
1768 mgmt_pending_remove(cmd);
1769
1770 return err;
1771}
1772
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001773static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data,
1774 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001775{
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001776 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001777 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001778 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03001779 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001780 int err;
1781
1782 BT_DBG("");
1783
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001784 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001785 return cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001786 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001787
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001788 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001789
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001790 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001791 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001792 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001793 goto failed;
1794 }
1795
Johan Hedbergd8457692012-02-17 14:24:57 +02001796 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001797 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001798 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001799 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001800 goto failed;
1801 }
1802
1803 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02001804 struct mgmt_cp_pin_code_neg_reply ncp;
1805
1806 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001807
1808 BT_ERR("PIN code is not 16 bytes long");
1809
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001810 err = send_pin_code_neg_reply(sk, hdev, &ncp);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001811 if (err >= 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001812 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001813 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001814
1815 goto failed;
1816 }
1817
Gustavo F. Padovan00abfe42012-03-01 00:37:10 -03001818 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001819 if (!cmd) {
1820 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001821 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001822 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02001823
Johan Hedbergd8457692012-02-17 14:24:57 +02001824 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001825 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02001826 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02001827
1828 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
1829 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001830 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001831
1832failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001833 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001834 return err;
1835}
1836
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001837static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
1838 void *data, u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001839{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001840 struct mgmt_cp_pin_code_neg_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001841 int err;
1842
1843 BT_DBG("");
1844
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001845 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001846 return cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001847 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001848
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001849 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001850
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001851 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001852 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001853 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001854 goto failed;
1855 }
1856
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001857 err = send_pin_code_neg_reply(sk, hdev, cp);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001858
1859failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001860 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001861 return err;
1862}
1863
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001864static int set_io_capability(struct sock *sk, struct hci_dev *hdev,
1865 void *data, u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001866{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001867 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001868
1869 BT_DBG("");
1870
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001871 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001872 return cmd_status(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001873 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001874
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001875 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001876
1877 hdev->io_capability = cp->io_capability;
1878
1879 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Szymon Jancb8534e02011-03-01 16:55:34 +01001880 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001881
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001882 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001883
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001884 return cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, 0,
1885 NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001886}
1887
Johan Hedberge9a416b2011-02-19 12:05:56 -03001888static inline struct pending_cmd *find_pairing(struct hci_conn *conn)
1889{
1890 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001891 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001892
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001893 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03001894 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
1895 continue;
1896
Johan Hedberge9a416b2011-02-19 12:05:56 -03001897 if (cmd->user_data != conn)
1898 continue;
1899
1900 return cmd;
1901 }
1902
1903 return NULL;
1904}
1905
1906static void pairing_complete(struct pending_cmd *cmd, u8 status)
1907{
1908 struct mgmt_rp_pair_device rp;
1909 struct hci_conn *conn = cmd->user_data;
1910
Johan Hedbergba4e5642011-11-11 00:07:34 +02001911 bacpy(&rp.addr.bdaddr, &conn->dst);
1912 rp.addr.type = link_to_mgmt(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001913
Johan Hedbergaee9b2182012-02-18 15:07:59 +02001914 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, status,
1915 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001916
1917 /* So we don't get further callbacks for this connection */
1918 conn->connect_cfm_cb = NULL;
1919 conn->security_cfm_cb = NULL;
1920 conn->disconn_cfm_cb = NULL;
1921
1922 hci_conn_put(conn);
1923
Johan Hedberga664b5b2011-02-19 12:06:02 -03001924 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001925}
1926
1927static void pairing_complete_cb(struct hci_conn *conn, u8 status)
1928{
1929 struct pending_cmd *cmd;
1930
1931 BT_DBG("status %u", status);
1932
Johan Hedberg56e5cb82011-11-08 20:40:16 +02001933 cmd = find_pairing(conn);
1934 if (!cmd)
1935 BT_DBG("Unable to find a pending command");
1936 else
Johan Hedberge2113262012-02-18 15:20:03 +02001937 pairing_complete(cmd, mgmt_status(status));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001938}
1939
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001940static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
1941 u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001942{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001943 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02001944 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001945 struct pending_cmd *cmd;
1946 u8 sec_level, auth_type;
1947 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001948 int err;
1949
1950 BT_DBG("");
1951
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001952 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001953 return cmd_status(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02001954 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001955
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001956 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001957
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001958 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001959 err = cmd_status(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001960 MGMT_STATUS_NOT_POWERED);
1961 goto unlock;
1962 }
1963
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001964 sec_level = BT_SECURITY_MEDIUM;
1965 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001966 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001967 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03001968 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001969
Johan Hedbergba4e5642011-11-11 00:07:34 +02001970 if (cp->addr.type == MGMT_ADDR_BREDR)
1971 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr, sec_level,
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001972 auth_type);
1973 else
Johan Hedbergba4e5642011-11-11 00:07:34 +02001974 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr, sec_level,
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001975 auth_type);
1976
Johan Hedberg1425acb2011-11-11 00:07:35 +02001977 memset(&rp, 0, sizeof(rp));
1978 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1979 rp.addr.type = cp->addr.type;
1980
Ville Tervo30e76272011-02-22 16:10:53 -03001981 if (IS_ERR(conn)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001982 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Johan Hedberge2113262012-02-18 15:20:03 +02001983 MGMT_STATUS_CONNECT_FAILED,
1984 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001985 goto unlock;
1986 }
1987
1988 if (conn->connect_cfm_cb) {
1989 hci_conn_put(conn);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001990 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Johan Hedberge2113262012-02-18 15:20:03 +02001991 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001992 goto unlock;
1993 }
1994
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001995 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001996 if (!cmd) {
1997 err = -ENOMEM;
1998 hci_conn_put(conn);
1999 goto unlock;
2000 }
2001
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002002 /* For LE, just connecting isn't a proof that the pairing finished */
Johan Hedbergba4e5642011-11-11 00:07:34 +02002003 if (cp->addr.type == MGMT_ADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002004 conn->connect_cfm_cb = pairing_complete_cb;
2005
Johan Hedberge9a416b2011-02-19 12:05:56 -03002006 conn->security_cfm_cb = pairing_complete_cb;
2007 conn->disconn_cfm_cb = pairing_complete_cb;
2008 conn->io_capability = cp->io_cap;
2009 cmd->user_data = conn;
2010
2011 if (conn->state == BT_CONNECTED &&
2012 hci_conn_security(conn, sec_level, auth_type))
2013 pairing_complete(cmd, 0);
2014
2015 err = 0;
2016
2017unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002018 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002019 return err;
2020}
2021
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002022static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev,
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002023 void *data, u16 len)
Johan Hedberg28424702012-02-02 04:02:29 +02002024{
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002025 struct mgmt_addr_info *addr = data;
Johan Hedberg28424702012-02-02 04:02:29 +02002026 struct pending_cmd *cmd;
2027 struct hci_conn *conn;
2028 int err;
2029
2030 BT_DBG("");
2031
2032 if (len != sizeof(*addr))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002033 return cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Johan Hedberg28424702012-02-02 04:02:29 +02002034 MGMT_STATUS_INVALID_PARAMS);
2035
2036 hci_dev_lock(hdev);
2037
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002038 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002039 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002040 MGMT_STATUS_NOT_POWERED);
2041 goto unlock;
2042 }
2043
Johan Hedberg28424702012-02-02 04:02:29 +02002044 cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
2045 if (!cmd) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002046 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Johan Hedberg28424702012-02-02 04:02:29 +02002047 MGMT_STATUS_INVALID_PARAMS);
2048 goto unlock;
2049 }
2050
2051 conn = cmd->user_data;
2052
2053 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002054 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Johan Hedberg28424702012-02-02 04:02:29 +02002055 MGMT_STATUS_INVALID_PARAMS);
2056 goto unlock;
2057 }
2058
2059 pairing_complete(cmd, MGMT_STATUS_CANCELLED);
2060
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002061 err = cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0,
2062 addr, sizeof(*addr));
Johan Hedberg28424702012-02-02 04:02:29 +02002063unlock:
2064 hci_dev_unlock(hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02002065 return err;
2066}
2067
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002068static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
2069 bdaddr_t *bdaddr, u8 type, u16 mgmt_op,
2070 u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03002071{
Johan Hedberga5c29682011-02-19 12:05:57 -03002072 struct pending_cmd *cmd;
Brian Gix0df4c182011-11-16 13:53:13 -08002073 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03002074 int err;
2075
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002076 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02002077
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002078 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002079 err = cmd_status(sk, hdev->id, mgmt_op,
2080 MGMT_STATUS_NOT_POWERED);
Brian Gix0df4c182011-11-16 13:53:13 -08002081 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002082 }
2083
Johan Hedberg272d90d2012-02-09 15:26:12 +02002084 if (type == MGMT_ADDR_BREDR)
2085 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, bdaddr);
2086 else
Brian Gix47c15e22011-11-16 13:53:14 -08002087 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, bdaddr);
Brian Gix47c15e22011-11-16 13:53:14 -08002088
Johan Hedberg272d90d2012-02-09 15:26:12 +02002089 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002090 err = cmd_status(sk, hdev->id, mgmt_op,
Johan Hedberg272d90d2012-02-09 15:26:12 +02002091 MGMT_STATUS_NOT_CONNECTED);
2092 goto done;
2093 }
2094
2095 if (type == MGMT_ADDR_LE_PUBLIC || type == MGMT_ADDR_LE_RANDOM) {
Brian Gix47c15e22011-11-16 13:53:14 -08002096 /* Continue with pairing via SMP */
Brian Gix5fe57d92011-12-21 16:12:13 -08002097 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix47c15e22011-11-16 13:53:14 -08002098
Brian Gix5fe57d92011-12-21 16:12:13 -08002099 if (!err)
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002100 err = cmd_status(sk, hdev->id, mgmt_op,
Brian Gix5fe57d92011-12-21 16:12:13 -08002101 MGMT_STATUS_SUCCESS);
2102 else
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002103 err = cmd_status(sk, hdev->id, mgmt_op,
Brian Gix5fe57d92011-12-21 16:12:13 -08002104 MGMT_STATUS_FAILED);
2105
Brian Gix47c15e22011-11-16 13:53:14 -08002106 goto done;
2107 }
2108
Brian Gix0df4c182011-11-16 13:53:13 -08002109 cmd = mgmt_pending_add(sk, mgmt_op, hdev, bdaddr, sizeof(*bdaddr));
Johan Hedberga5c29682011-02-19 12:05:57 -03002110 if (!cmd) {
2111 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08002112 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002113 }
2114
Brian Gix0df4c182011-11-16 13:53:13 -08002115 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08002116 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
2117 struct hci_cp_user_passkey_reply cp;
2118
2119 bacpy(&cp.bdaddr, bdaddr);
2120 cp.passkey = passkey;
2121 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
2122 } else
2123 err = hci_send_cmd(hdev, hci_op, sizeof(*bdaddr), bdaddr);
2124
Johan Hedberga664b5b2011-02-19 12:06:02 -03002125 if (err < 0)
2126 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002127
Brian Gix0df4c182011-11-16 13:53:13 -08002128done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002129 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002130 return err;
2131}
2132
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002133static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev,
2134 void *data, u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002135{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002136 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002137
2138 BT_DBG("");
2139
2140 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002141 return cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY,
Brian Gix0df4c182011-11-16 13:53:13 -08002142 MGMT_STATUS_INVALID_PARAMS);
2143
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002144 return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
Johan Hedberg272d90d2012-02-09 15:26:12 +02002145 MGMT_OP_USER_CONFIRM_REPLY,
2146 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002147}
2148
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002149static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev,
2150 void *data, u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002151{
Johan Hedbergc9c26592011-12-15 00:47:41 +02002152 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002153
2154 BT_DBG("");
2155
2156 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002157 return cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_NEG_REPLY,
Brian Gix0df4c182011-11-16 13:53:13 -08002158 MGMT_STATUS_INVALID_PARAMS);
2159
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002160 return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
Johan Hedberg272d90d2012-02-09 15:26:12 +02002161 MGMT_OP_USER_CONFIRM_NEG_REPLY,
2162 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002163}
2164
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002165static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev,
2166 void *data, u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002167{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002168 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002169
2170 BT_DBG("");
2171
2172 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002173 return cmd_status(sk, hdev->id, MGMT_OP_USER_PASSKEY_REPLY,
Brian Gix604086b2011-11-23 08:28:33 -08002174 EINVAL);
2175
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002176 return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
Johan Hedberg272d90d2012-02-09 15:26:12 +02002177 MGMT_OP_USER_PASSKEY_REPLY,
2178 HCI_OP_USER_PASSKEY_REPLY,
2179 cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08002180}
2181
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002182static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
2183 void *data, u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002184{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002185 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002186
2187 BT_DBG("");
2188
2189 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002190 return cmd_status(sk, hdev->id, MGMT_OP_USER_PASSKEY_NEG_REPLY,
2191 EINVAL);
Brian Gix604086b2011-11-23 08:28:33 -08002192
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002193 return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
Johan Hedberg272d90d2012-02-09 15:26:12 +02002194 MGMT_OP_USER_PASSKEY_NEG_REPLY,
2195 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08002196}
2197
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002198static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
Johan Hedbergb312b1612011-03-16 14:29:37 +02002199 u16 len)
2200{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002201 struct mgmt_cp_set_local_name *mgmt_cp = data;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002202 struct hci_cp_write_local_name hci_cp;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002203 struct pending_cmd *cmd;
2204 int err;
2205
2206 BT_DBG("");
2207
2208 if (len != sizeof(*mgmt_cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002209 return cmd_status(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
Johan Hedbergca69b792011-11-11 18:10:00 +02002210 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002211
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002212 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002213
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002214 memcpy(hdev->short_name, mgmt_cp->short_name,
2215 sizeof(hdev->short_name));
2216
Johan Hedbergb5235a62012-02-21 14:32:24 +02002217 if (!hdev_is_powered(hdev)) {
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002218 memcpy(hdev->dev_name, mgmt_cp->name, sizeof(hdev->dev_name));
2219
2220 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
2221 data, len);
2222 if (err < 0)
2223 goto failed;
2224
2225 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data, len,
2226 sk);
2227
Johan Hedbergb5235a62012-02-21 14:32:24 +02002228 goto failed;
2229 }
2230
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002231 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002232 if (!cmd) {
2233 err = -ENOMEM;
2234 goto failed;
2235 }
2236
2237 memcpy(hci_cp.name, mgmt_cp->name, sizeof(hci_cp.name));
2238 err = hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(hci_cp),
2239 &hci_cp);
2240 if (err < 0)
2241 mgmt_pending_remove(cmd);
2242
2243failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002244 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002245 return err;
2246}
2247
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002248static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
2249 void *data, u16 data_len)
Szymon Jancc35938b2011-03-22 13:12:21 +01002250{
Szymon Jancc35938b2011-03-22 13:12:21 +01002251 struct pending_cmd *cmd;
2252 int err;
2253
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002254 BT_DBG("%s", hdev->name);
Szymon Jancc35938b2011-03-22 13:12:21 +01002255
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002256 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002257
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002258 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002259 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002260 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002261 goto unlock;
2262 }
2263
2264 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002265 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002266 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002267 goto unlock;
2268 }
2269
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002270 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002271 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002272 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01002273 goto unlock;
2274 }
2275
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002276 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01002277 if (!cmd) {
2278 err = -ENOMEM;
2279 goto unlock;
2280 }
2281
2282 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
2283 if (err < 0)
2284 mgmt_pending_remove(cmd);
2285
2286unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002287 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002288 return err;
2289}
2290
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002291static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
2292 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002293{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002294 struct mgmt_cp_add_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002295 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002296 int err;
2297
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002298 BT_DBG("%s ", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01002299
2300 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002301 return cmd_status(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002302 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01002303
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002304 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002305
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002306 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002307 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA,
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002308 MGMT_STATUS_NOT_POWERED,
2309 &cp->addr, sizeof(cp->addr));
2310 goto unlock;
2311 }
2312
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002313 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, cp->hash,
Szymon Janc2763eda2011-03-22 13:12:22 +01002314 cp->randomizer);
2315 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002316 status = MGMT_STATUS_FAILED;
Szymon Janc2763eda2011-03-22 13:12:22 +01002317 else
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002318 status = 0;
2319
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002320 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA, status,
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002321 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002322
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002323unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002324 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002325 return err;
2326}
2327
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002328static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002329 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002330{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002331 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002332 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002333 int err;
2334
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002335 BT_DBG("%s", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01002336
2337 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002338 return cmd_status(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002339 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01002340
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002341 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002342
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002343 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002344 err = cmd_complete(sk, hdev->id,
2345 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2346 MGMT_STATUS_NOT_POWERED,
2347 &cp->addr, sizeof(cp->addr));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002348 goto unlock;
2349 }
2350
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002351 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr);
Szymon Janc2763eda2011-03-22 13:12:22 +01002352 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002353 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01002354 else
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002355 status = 0;
2356
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002357 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2358 status, &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002359
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002360unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002361 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002362 return err;
2363}
2364
Andre Guedes5e0452c2012-02-17 20:39:38 -03002365int mgmt_interleaved_discovery(struct hci_dev *hdev)
2366{
2367 int err;
2368
2369 BT_DBG("%s", hdev->name);
2370
2371 hci_dev_lock(hdev);
2372
2373 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR_LE);
2374 if (err < 0)
2375 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2376
2377 hci_dev_unlock(hdev);
2378
2379 return err;
2380}
2381
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002382static int start_discovery(struct sock *sk, struct hci_dev *hdev,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002383 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002384{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002385 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002386 struct pending_cmd *cmd;
Johan Hedberg14a53662011-04-27 10:29:56 -04002387 int err;
2388
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002389 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04002390
Johan Hedberg450dfda2011-11-12 11:58:22 +02002391 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002392 return cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Johan Hedbergca69b792011-11-11 18:10:00 +02002393 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg14a53662011-04-27 10:29:56 -04002394
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002395 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002396
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002397 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002398 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Johan Hedbergca69b792011-11-11 18:10:00 +02002399 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02002400 goto failed;
2401 }
2402
Johan Hedbergff9ef572012-01-04 14:23:45 +02002403 if (hdev->discovery.state != DISCOVERY_STOPPED) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002404 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2405 MGMT_STATUS_BUSY);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002406 goto failed;
2407 }
2408
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002409 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002410 if (!cmd) {
2411 err = -ENOMEM;
2412 goto failed;
2413 }
2414
Andre Guedes4aab14e2012-02-17 20:39:36 -03002415 hdev->discovery.type = cp->type;
2416
2417 switch (hdev->discovery.type) {
Andre Guedesf39799f2012-02-17 20:39:35 -03002418 case DISCOV_TYPE_BREDR:
Andre Guedes8b901292012-02-23 18:09:27 -03002419 if (lmp_bredr_capable(hdev))
2420 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
2421 else
2422 err = -ENOTSUPP;
Andre Guedesf39799f2012-02-17 20:39:35 -03002423 break;
2424
2425 case DISCOV_TYPE_LE:
Andre Guedes8b901292012-02-23 18:09:27 -03002426 if (lmp_host_le_capable(hdev))
2427 err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT,
Andre Guedes3fd24152012-02-03 17:48:01 -03002428 LE_SCAN_WIN, LE_SCAN_TIMEOUT_LE_ONLY);
Andre Guedes8b901292012-02-23 18:09:27 -03002429 else
2430 err = -ENOTSUPP;
Andre Guedesf39799f2012-02-17 20:39:35 -03002431 break;
2432
Andre Guedes5e0452c2012-02-17 20:39:38 -03002433 case DISCOV_TYPE_INTERLEAVED:
Andre Guedes426c1892012-02-24 11:41:04 -03002434 if (lmp_host_le_capable(hdev) && lmp_bredr_capable(hdev))
2435 err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT,
2436 LE_SCAN_WIN, LE_SCAN_TIMEOUT_BREDR_LE);
2437 else
2438 err = -ENOTSUPP;
Andre Guedes5e0452c2012-02-17 20:39:38 -03002439 break;
2440
Andre Guedesf39799f2012-02-17 20:39:35 -03002441 default:
Andre Guedes3fd24152012-02-03 17:48:01 -03002442 err = -EINVAL;
Andre Guedesf39799f2012-02-17 20:39:35 -03002443 }
Andre Guedes3fd24152012-02-03 17:48:01 -03002444
Johan Hedberg14a53662011-04-27 10:29:56 -04002445 if (err < 0)
2446 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002447 else
2448 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002449
2450failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002451 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002452 return err;
2453}
2454
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002455static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
2456 u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002457{
Johan Hedbergd9306502012-02-20 23:25:18 +02002458 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002459 struct pending_cmd *cmd;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002460 struct hci_cp_remote_name_req_cancel cp;
2461 struct inquiry_entry *e;
Johan Hedberg14a53662011-04-27 10:29:56 -04002462 int err;
2463
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002464 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04002465
Johan Hedbergd9306502012-02-20 23:25:18 +02002466 if (len != sizeof(*mgmt_cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002467 return cmd_status(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Johan Hedbergca69b792011-11-11 18:10:00 +02002468 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg14a53662011-04-27 10:29:56 -04002469
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002470 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002471
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002472 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002473 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Johan Hedbergd9306502012-02-20 23:25:18 +02002474 MGMT_STATUS_REJECTED,
2475 &mgmt_cp->type, sizeof(mgmt_cp->type));
2476 goto unlock;
2477 }
2478
2479 if (hdev->discovery.type != mgmt_cp->type) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002480 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Johan Hedbergd9306502012-02-20 23:25:18 +02002481 MGMT_STATUS_INVALID_PARAMS,
2482 &mgmt_cp->type, sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002483 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02002484 }
2485
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002486 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002487 if (!cmd) {
2488 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002489 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04002490 }
2491
Andre Guedes343f9352012-02-17 20:39:37 -03002492 if (hdev->discovery.state == DISCOVERY_FINDING) {
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002493 err = hci_cancel_inquiry(hdev);
2494 if (err < 0)
2495 mgmt_pending_remove(cmd);
2496 else
2497 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
2498 goto unlock;
2499 }
2500
2501 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY, NAME_PENDING);
2502 if (!e) {
2503 mgmt_pending_remove(cmd);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002504 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY, 0,
Johan Hedbergd9306502012-02-20 23:25:18 +02002505 &mgmt_cp->type, sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002506 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2507 goto unlock;
2508 }
2509
2510 bacpy(&cp.bdaddr, &e->data.bdaddr);
2511 err = hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ_CANCEL,
2512 sizeof(cp), &cp);
Johan Hedberg14a53662011-04-27 10:29:56 -04002513 if (err < 0)
2514 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002515 else
2516 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002517
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002518unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002519 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002520 return err;
2521}
2522
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002523static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
2524 u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02002525{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002526 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002527 struct inquiry_entry *e;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002528 int err;
2529
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002530 BT_DBG("%s", hdev->name);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002531
2532 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002533 return cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
2534 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002535
2536 hci_dev_lock(hdev);
2537
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002538 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002539 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002540 MGMT_STATUS_FAILED);
2541 goto failed;
2542 }
2543
Johan Hedberga198e7b2012-02-17 14:27:06 +02002544 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002545 if (!e) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002546 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
2547 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002548 goto failed;
2549 }
2550
2551 if (cp->name_known) {
2552 e->name_state = NAME_KNOWN;
2553 list_del(&e->list);
2554 } else {
2555 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e202012-01-09 00:53:02 +02002556 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002557 }
2558
2559 err = 0;
2560
2561failed:
2562 hci_dev_unlock(hdev);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002563 return err;
2564}
2565
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002566static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
2567 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002568{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002569 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002570 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03002571 int err;
2572
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002573 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03002574
Antti Julku7fbec222011-06-15 12:01:15 +03002575 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002576 return cmd_status(sk, hdev->id, MGMT_OP_BLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002577 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002578
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002579 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002580
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002581 err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002582 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002583 status = MGMT_STATUS_FAILED;
Antti Julku7fbec222011-06-15 12:01:15 +03002584 else
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002585 status = 0;
2586
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002587 err = cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status,
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002588 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03002589
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002590 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002591
2592 return err;
2593}
2594
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002595static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
2596 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002597{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002598 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002599 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03002600 int err;
2601
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002602 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03002603
Antti Julku7fbec222011-06-15 12:01:15 +03002604 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002605 return cmd_status(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002606 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002607
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002608 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002609
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002610 err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002611 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002612 status = MGMT_STATUS_INVALID_PARAMS;
Antti Julku7fbec222011-06-15 12:01:15 +03002613 else
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002614 status = 0;
2615
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002616 err = cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status,
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002617 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03002618
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002619 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002620
2621 return err;
2622}
2623
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002624static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
2625 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03002626{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002627 struct mgmt_mode *cp = data;
Antti Julkuf6422ec2011-06-22 13:11:56 +03002628 struct hci_cp_write_page_scan_activity acp;
2629 u8 type;
2630 int err;
2631
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002632 BT_DBG("%s", hdev->name);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002633
2634 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002635 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002636 MGMT_STATUS_INVALID_PARAMS);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002637
Johan Hedberg5400c042012-02-21 16:40:33 +02002638 if (!hdev_is_powered(hdev))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002639 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedberg5400c042012-02-21 16:40:33 +02002640 MGMT_STATUS_NOT_POWERED);
2641
2642 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002643 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
2644 MGMT_STATUS_REJECTED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002645
2646 hci_dev_lock(hdev);
2647
Johan Hedbergf7c68692011-12-15 00:47:36 +02002648 if (cp->val) {
Antti Julkuf6422ec2011-06-22 13:11:56 +03002649 type = PAGE_SCAN_TYPE_INTERLACED;
2650 acp.interval = 0x0024; /* 22.5 msec page scan interval */
2651 } else {
2652 type = PAGE_SCAN_TYPE_STANDARD; /* default */
2653 acp.interval = 0x0800; /* default 1.28 sec page scan */
2654 }
2655
2656 acp.window = 0x0012; /* default 11.25 msec page scan window */
2657
2658 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
2659 sizeof(acp), &acp);
2660 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002661 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
2662 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002663 goto done;
2664 }
2665
2666 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
2667 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002668 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
2669 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002670 goto done;
2671 }
2672
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002673 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE, 0,
Johan Hedbergaee9b2182012-02-18 15:07:59 +02002674 NULL, 0);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002675done:
2676 hci_dev_unlock(hdev);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002677 return err;
2678}
2679
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002680static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002681 void *cp_data, u16 len)
2682{
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002683 struct mgmt_cp_load_long_term_keys *cp = cp_data;
2684 u16 key_count, expected_len;
2685 int i;
2686
2687 if (len < sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002688 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002689 EINVAL);
2690
2691 key_count = get_unaligned_le16(&cp->key_count);
2692
2693 expected_len = sizeof(*cp) + key_count *
2694 sizeof(struct mgmt_ltk_info);
2695 if (expected_len != len) {
2696 BT_ERR("load_keys: expected %u bytes, got %u bytes",
2697 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002698 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002699 EINVAL);
2700 }
2701
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002702 BT_DBG("%s key_count %u", hdev->name, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002703
2704 hci_dev_lock(hdev);
2705
2706 hci_smp_ltks_clear(hdev);
2707
2708 for (i = 0; i < key_count; i++) {
2709 struct mgmt_ltk_info *key = &cp->keys[i];
2710 u8 type;
2711
2712 if (key->master)
2713 type = HCI_SMP_LTK;
2714 else
2715 type = HCI_SMP_LTK_SLAVE;
2716
2717 hci_add_ltk(hdev, &key->addr.bdaddr, key->addr.type,
2718 type, 0, key->authenticated, key->val,
2719 key->enc_size, key->ediv, key->rand);
2720 }
2721
2722 hci_dev_unlock(hdev);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002723
2724 return 0;
2725}
2726
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002727struct mgmt_handler {
2728 int (*func) (struct sock *sk, struct hci_dev *hdev,
2729 void *data, u16 data_len);
2730} mgmt_handlers[] = {
2731 { NULL }, /* 0x0000 (no command) */
2732 { read_version, },
2733 { read_commands, },
2734 { read_index_list, },
2735 { read_controller_info, },
2736 { set_powered, },
2737 { set_discoverable, },
2738 { set_connectable, },
2739 { set_fast_connectable, },
2740 { set_pairable, },
2741 { set_link_security, },
2742 { set_ssp, },
2743 { set_hs, },
2744 { set_le, },
2745 { set_dev_class, },
2746 { set_local_name, },
2747 { add_uuid, },
2748 { remove_uuid, },
2749 { load_link_keys, },
2750 { load_long_term_keys, },
2751 { disconnect, },
2752 { get_connections, },
2753 { pin_code_reply, },
2754 { pin_code_neg_reply, },
2755 { set_io_capability, },
2756 { pair_device, },
2757 { cancel_pair_device, },
2758 { unpair_device, },
2759 { user_confirm_reply, },
2760 { user_confirm_neg_reply, },
2761 { user_passkey_reply, },
2762 { user_passkey_neg_reply, },
2763 { read_local_oob_data, },
2764 { add_remote_oob_data, },
2765 { remove_remote_oob_data, },
2766 { start_discovery, },
2767 { stop_discovery, },
2768 { confirm_name, },
2769 { block_device, },
2770 { unblock_device, },
2771};
2772
2773
Johan Hedberg03811012010-12-08 00:21:06 +02002774int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
2775{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002776 void *buf;
2777 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02002778 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002779 u16 opcode, index, len;
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002780 struct hci_dev *hdev = NULL;
Johan Hedberg03811012010-12-08 00:21:06 +02002781 int err;
2782
2783 BT_DBG("got %zu bytes", msglen);
2784
2785 if (msglen < sizeof(*hdr))
2786 return -EINVAL;
2787
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03002788 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02002789 if (!buf)
2790 return -ENOMEM;
2791
2792 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
2793 err = -EFAULT;
2794 goto done;
2795 }
2796
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002797 hdr = buf;
Johan Hedberg03811012010-12-08 00:21:06 +02002798 opcode = get_unaligned_le16(&hdr->opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002799 index = get_unaligned_le16(&hdr->index);
Johan Hedberg03811012010-12-08 00:21:06 +02002800 len = get_unaligned_le16(&hdr->len);
2801
2802 if (len != msglen - sizeof(*hdr)) {
2803 err = -EINVAL;
2804 goto done;
2805 }
2806
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002807 if (index != MGMT_INDEX_NONE) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002808 hdev = hci_dev_get(index);
2809 if (!hdev) {
2810 err = cmd_status(sk, index, opcode,
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002811 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002812 goto done;
2813 }
2814 }
2815
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002816 if (opcode >= ARRAY_SIZE(mgmt_handlers) ||
2817 mgmt_handlers[opcode].func == NULL) {
Johan Hedberg03811012010-12-08 00:21:06 +02002818 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02002819 err = cmd_status(sk, index, opcode,
2820 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002821 goto done;
Johan Hedberg03811012010-12-08 00:21:06 +02002822 }
2823
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002824 if ((hdev && opcode < MGMT_OP_READ_INFO) ||
2825 (!hdev && opcode >= MGMT_OP_READ_INFO)) {
2826 err = cmd_status(sk, index, opcode,
2827 MGMT_STATUS_INVALID_PARAMS);
2828 goto done;
2829 }
2830
2831 if (hdev)
2832 mgmt_init_hdev(sk, hdev);
2833
2834 cp = buf + sizeof(*hdr);
2835
2836 err = mgmt_handlers[opcode].func(sk, hdev, cp, len);
Johan Hedberge41d8b42010-12-13 21:07:03 +02002837 if (err < 0)
2838 goto done;
2839
Johan Hedberg03811012010-12-08 00:21:06 +02002840 err = msglen;
2841
2842done:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002843 if (hdev)
2844 hci_dev_put(hdev);
2845
Johan Hedberg03811012010-12-08 00:21:06 +02002846 kfree(buf);
2847 return err;
2848}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002849
Johan Hedbergb24752f2011-11-03 14:40:33 +02002850static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
2851{
2852 u8 *status = data;
2853
2854 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
2855 mgmt_pending_remove(cmd);
2856}
2857
Johan Hedberg744cf192011-11-08 20:40:14 +02002858int mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002859{
Johan Hedberg744cf192011-11-08 20:40:14 +02002860 return mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002861}
2862
Johan Hedberg744cf192011-11-08 20:40:14 +02002863int mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002864{
Johan Hedbergb24752f2011-11-03 14:40:33 +02002865 u8 status = ENODEV;
2866
Johan Hedberg744cf192011-11-08 20:40:14 +02002867 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002868
Johan Hedberg744cf192011-11-08 20:40:14 +02002869 return mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002870}
2871
Johan Hedberg73f22f62010-12-29 16:00:25 +02002872struct cmd_lookup {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002873 struct sock *sk;
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002874 struct hci_dev *hdev;
Johan Hedberg90e70452012-02-23 23:09:40 +02002875 u8 mgmt_status;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002876};
2877
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002878static void settings_rsp(struct pending_cmd *cmd, void *data)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002879{
Johan Hedberg73f22f62010-12-29 16:00:25 +02002880 struct cmd_lookup *match = data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002881
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002882 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002883
2884 list_del(&cmd->list);
2885
2886 if (match->sk == NULL) {
2887 match->sk = cmd->sk;
2888 sock_hold(match->sk);
2889 }
2890
2891 mgmt_pending_free(cmd);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002892}
Johan Hedberg5add6af2010-12-16 10:00:37 +02002893
Johan Hedberg744cf192011-11-08 20:40:14 +02002894int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg5add6af2010-12-16 10:00:37 +02002895{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002896 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002897 int err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002898
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002899 if (!test_bit(HCI_MGMT, &hdev->dev_flags))
2900 return 0;
2901
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002902 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
Johan Hedberg5add6af2010-12-16 10:00:37 +02002903
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002904 if (powered) {
2905 u8 scan = 0;
2906
2907 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
2908 scan |= SCAN_PAGE;
2909 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
2910 scan |= SCAN_INQUIRY;
2911
2912 if (scan)
2913 hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
Johan Hedberg504c8dc2012-02-23 13:30:41 +02002914
2915 update_class(hdev);
2916 update_eir(hdev);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002917 } else {
Johan Hedbergb24752f2011-11-03 14:40:33 +02002918 u8 status = ENETDOWN;
Johan Hedberg744cf192011-11-08 20:40:14 +02002919 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002920 }
2921
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02002922 err = new_settings(hdev, match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002923
2924 if (match.sk)
2925 sock_put(match.sk);
2926
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002927 return err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002928}
Johan Hedberg73f22f62010-12-29 16:00:25 +02002929
Johan Hedberg744cf192011-11-08 20:40:14 +02002930int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg73f22f62010-12-29 16:00:25 +02002931{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002932 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002933 bool changed = false;
2934 int err = 0;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002935
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002936 if (discoverable) {
2937 if (!test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
2938 changed = true;
2939 } else {
2940 if (test_and_clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
2941 changed = true;
2942 }
Johan Hedberg73f22f62010-12-29 16:00:25 +02002943
Johan Hedberged9b5f22012-02-21 20:47:06 +02002944 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp,
2945 &match);
2946
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02002947 if (changed)
2948 err = new_settings(hdev, match.sk);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002949
Johan Hedberg73f22f62010-12-29 16:00:25 +02002950 if (match.sk)
2951 sock_put(match.sk);
2952
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002953 return err;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002954}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002955
Johan Hedberg744cf192011-11-08 20:40:14 +02002956int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002957{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002958 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002959 bool changed = false;
2960 int err = 0;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002961
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002962 if (connectable) {
2963 if (!test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags))
2964 changed = true;
2965 } else {
2966 if (test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags))
2967 changed = true;
2968 }
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002969
Johan Hedberged9b5f22012-02-21 20:47:06 +02002970 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev, settings_rsp,
2971 &match);
2972
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02002973 if (changed)
2974 err = new_settings(hdev, match.sk);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002975
2976 if (match.sk)
2977 sock_put(match.sk);
2978
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002979 return err;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002980}
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002981
Johan Hedberg744cf192011-11-08 20:40:14 +02002982int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002983{
Johan Hedbergca69b792011-11-11 18:10:00 +02002984 u8 mgmt_err = mgmt_status(status);
2985
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002986 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02002987 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Johan Hedbergca69b792011-11-11 18:10:00 +02002988 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002989
2990 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02002991 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Johan Hedbergca69b792011-11-11 18:10:00 +02002992 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002993
2994 return 0;
2995}
2996
Johan Hedberg744cf192011-11-08 20:40:14 +02002997int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
2998 u8 persistent)
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002999{
Johan Hedberg86742e12011-11-07 23:13:38 +02003000 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02003001
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003002 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02003003
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003004 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02003005 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
3006 ev.key.addr.type = MGMT_ADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003007 ev.key.type = key->type;
3008 memcpy(ev.key.val, key->val, 16);
3009 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02003010
Johan Hedberg744cf192011-11-08 20:40:14 +02003011 return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02003012}
Johan Hedbergf7520542011-01-20 12:34:39 +02003013
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003014int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
3015{
3016 struct mgmt_ev_new_long_term_key ev;
3017
3018 memset(&ev, 0, sizeof(ev));
3019
3020 ev.store_hint = persistent;
3021 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
3022 ev.key.addr.type = key->bdaddr_type;
3023 ev.key.authenticated = key->authenticated;
3024 ev.key.enc_size = key->enc_size;
3025 ev.key.ediv = key->ediv;
3026
3027 if (key->type == HCI_SMP_LTK)
3028 ev.key.master = 1;
3029
3030 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
3031 memcpy(ev.key.val, key->val, sizeof(key->val));
3032
3033 return mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev,
3034 &ev, sizeof(ev), NULL);
3035}
3036
Johan Hedbergafc747a2012-01-15 18:11:07 +02003037int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Johan Hedberg08c79b62012-02-23 22:31:51 +02003038 u8 addr_type, u32 flags, u8 *name,
3039 u8 name_len, u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02003040{
Johan Hedbergb644ba32012-01-17 21:48:47 +02003041 char buf[512];
3042 struct mgmt_ev_device_connected *ev = (void *) buf;
3043 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02003044
Johan Hedbergb644ba32012-01-17 21:48:47 +02003045 bacpy(&ev->addr.bdaddr, bdaddr);
3046 ev->addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02003047
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02003048 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02003049
Johan Hedbergb644ba32012-01-17 21:48:47 +02003050 if (name_len > 0)
3051 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
3052 name, name_len);
3053
3054 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
3055 eir_len = eir_append_data(&ev->eir[eir_len], eir_len,
3056 EIR_CLASS_OF_DEV, dev_class, 3);
3057
3058 put_unaligned_le16(eir_len, &ev->eir_len);
3059
3060 return mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
3061 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02003062}
3063
Johan Hedberg8962ee72011-01-20 12:40:27 +02003064static void disconnect_rsp(struct pending_cmd *cmd, void *data)
3065{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01003066 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003067 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02003068 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003069
Johan Hedberg88c3df12012-02-09 14:27:38 +02003070 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3071 rp.addr.type = cp->addr.type;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003072
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003073 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, 0, &rp,
3074 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003075
3076 *sk = cmd->sk;
3077 sock_hold(*sk);
3078
Johan Hedberga664b5b2011-02-19 12:06:02 -03003079 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003080}
3081
Johan Hedberg124f6e32012-02-09 13:50:12 +02003082static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02003083{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003084 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02003085 struct mgmt_cp_unpair_device *cp = cmd->param;
3086 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02003087
3088 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02003089 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3090 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02003091
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003092 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
3093
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003094 cmd_complete(cmd->sk, cmd->index, cmd->opcode, 0, &rp, sizeof(rp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02003095
3096 mgmt_pending_remove(cmd);
3097}
3098
Johan Hedbergafc747a2012-01-15 18:11:07 +02003099int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
3100 u8 link_type, u8 addr_type)
Johan Hedbergf7520542011-01-20 12:34:39 +02003101{
Johan Hedberg4c659c32011-11-07 23:13:39 +02003102 struct mgmt_addr_info ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003103 struct sock *sk = NULL;
3104 int err;
3105
Johan Hedberg744cf192011-11-08 20:40:14 +02003106 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02003107
Johan Hedbergf7520542011-01-20 12:34:39 +02003108 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02003109 ev.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02003110
Johan Hedbergafc747a2012-01-15 18:11:07 +02003111 err = mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev),
3112 sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003113
3114 if (sk)
3115 sock_put(sk);
3116
Johan Hedberg124f6e32012-02-09 13:50:12 +02003117 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003118 hdev);
Johan Hedberga8a1d192011-11-10 15:54:38 +02003119
Johan Hedberg8962ee72011-01-20 12:40:27 +02003120 return err;
3121}
3122
Johan Hedberg88c3df12012-02-09 14:27:38 +02003123int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
3124 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02003125{
Johan Hedberg88c3df12012-02-09 14:27:38 +02003126 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003127 struct pending_cmd *cmd;
3128 int err;
3129
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003130 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003131 if (!cmd)
3132 return -ENOENT;
3133
Johan Hedberg88c3df12012-02-09 14:27:38 +02003134 bacpy(&rp.addr.bdaddr, bdaddr);
3135 rp.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02003136
Johan Hedberg88c3df12012-02-09 14:27:38 +02003137 err = cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003138 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003139
Johan Hedberga664b5b2011-02-19 12:06:02 -03003140 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003141
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003142 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
3143 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003144 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02003145}
Johan Hedberg17d5c042011-01-22 06:09:08 +02003146
Johan Hedberg48264f02011-11-09 13:58:58 +02003147int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
3148 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02003149{
3150 struct mgmt_ev_connect_failed ev;
3151
Johan Hedberg4c659c32011-11-07 23:13:39 +02003152 bacpy(&ev.addr.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02003153 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003154 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003155
Johan Hedberg744cf192011-11-08 20:40:14 +02003156 return mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003157}
Johan Hedberg980e1a52011-01-22 06:10:07 +02003158
Johan Hedberg744cf192011-11-08 20:40:14 +02003159int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003160{
3161 struct mgmt_ev_pin_code_request ev;
3162
Johan Hedbergd8457692012-02-17 14:24:57 +02003163 bacpy(&ev.addr.bdaddr, bdaddr);
3164 ev.addr.type = MGMT_ADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02003165 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003166
Johan Hedberg744cf192011-11-08 20:40:14 +02003167 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01003168 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003169}
3170
Johan Hedberg744cf192011-11-08 20:40:14 +02003171int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3172 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003173{
3174 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003175 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003176 int err;
3177
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003178 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003179 if (!cmd)
3180 return -ENOENT;
3181
Johan Hedbergd8457692012-02-17 14:24:57 +02003182 bacpy(&rp.addr.bdaddr, bdaddr);
3183 rp.addr.type = MGMT_ADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003184
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003185 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
3186 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003187
Johan Hedberga664b5b2011-02-19 12:06:02 -03003188 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003189
3190 return err;
3191}
3192
Johan Hedberg744cf192011-11-08 20:40:14 +02003193int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3194 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003195{
3196 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003197 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003198 int err;
3199
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003200 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003201 if (!cmd)
3202 return -ENOENT;
3203
Johan Hedbergd8457692012-02-17 14:24:57 +02003204 bacpy(&rp.addr.bdaddr, bdaddr);
3205 rp.addr.type = MGMT_ADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003206
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003207 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
3208 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003209
Johan Hedberga664b5b2011-02-19 12:06:02 -03003210 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003211
3212 return err;
3213}
Johan Hedberga5c29682011-02-19 12:05:57 -03003214
Johan Hedberg744cf192011-11-08 20:40:14 +02003215int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003216 u8 link_type, u8 addr_type, __le32 value,
3217 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03003218{
3219 struct mgmt_ev_user_confirm_request ev;
3220
Johan Hedberg744cf192011-11-08 20:40:14 +02003221 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03003222
Johan Hedberg272d90d2012-02-09 15:26:12 +02003223 bacpy(&ev.addr.bdaddr, bdaddr);
3224 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07003225 ev.confirm_hint = confirm_hint;
Johan Hedberga5c29682011-02-19 12:05:57 -03003226 put_unaligned_le32(value, &ev.value);
3227
Johan Hedberg744cf192011-11-08 20:40:14 +02003228 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01003229 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03003230}
3231
Johan Hedberg272d90d2012-02-09 15:26:12 +02003232int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
3233 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08003234{
3235 struct mgmt_ev_user_passkey_request ev;
3236
3237 BT_DBG("%s", hdev->name);
3238
Johan Hedberg272d90d2012-02-09 15:26:12 +02003239 bacpy(&ev.addr.bdaddr, bdaddr);
3240 ev.addr.type = link_to_mgmt(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08003241
3242 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
3243 NULL);
3244}
3245
Brian Gix0df4c182011-11-16 13:53:13 -08003246static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003247 u8 link_type, u8 addr_type, u8 status,
3248 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03003249{
3250 struct pending_cmd *cmd;
3251 struct mgmt_rp_user_confirm_reply rp;
3252 int err;
3253
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003254 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03003255 if (!cmd)
3256 return -ENOENT;
3257
Johan Hedberg272d90d2012-02-09 15:26:12 +02003258 bacpy(&rp.addr.bdaddr, bdaddr);
3259 rp.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003260 err = cmd_complete(cmd->sk, hdev->id, opcode, mgmt_status(status),
3261 &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03003262
Johan Hedberga664b5b2011-02-19 12:06:02 -03003263 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03003264
3265 return err;
3266}
3267
Johan Hedberg744cf192011-11-08 20:40:14 +02003268int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003269 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003270{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003271 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3272 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003273}
3274
Johan Hedberg272d90d2012-02-09 15:26:12 +02003275int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3276 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003277{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003278 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3279 status, MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003280}
Johan Hedberg2a611692011-02-19 12:06:00 -03003281
Brian Gix604086b2011-11-23 08:28:33 -08003282int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003283 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003284{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003285 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3286 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003287}
3288
Johan Hedberg272d90d2012-02-09 15:26:12 +02003289int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3290 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003291{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003292 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3293 status, MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003294}
3295
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003296int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
3297 u8 addr_type, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03003298{
3299 struct mgmt_ev_auth_failed ev;
3300
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003301 bacpy(&ev.addr.bdaddr, bdaddr);
3302 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003303 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03003304
Johan Hedberg744cf192011-11-08 20:40:14 +02003305 return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03003306}
Johan Hedbergb312b1612011-03-16 14:29:37 +02003307
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003308int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
3309{
3310 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg47990ea2012-02-22 11:58:37 +02003311 bool changed = false;
3312 int err = 0;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003313
3314 if (status) {
3315 u8 mgmt_err = mgmt_status(status);
3316 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
3317 cmd_status_rsp, &mgmt_err);
3318 return 0;
3319 }
3320
Johan Hedberg47990ea2012-02-22 11:58:37 +02003321 if (test_bit(HCI_AUTH, &hdev->flags)) {
3322 if (!test_and_set_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
3323 changed = true;
3324 } else {
3325 if (test_and_clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
3326 changed = true;
3327 }
3328
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003329 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
3330 &match);
3331
Johan Hedberg47990ea2012-02-22 11:58:37 +02003332 if (changed)
3333 err = new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003334
3335 if (match.sk)
3336 sock_put(match.sk);
3337
3338 return err;
3339}
3340
Johan Hedbergcacaf522012-02-21 00:52:42 +02003341static int clear_eir(struct hci_dev *hdev)
3342{
3343 struct hci_cp_write_eir cp;
3344
3345 if (!(hdev->features[6] & LMP_EXT_INQ))
3346 return 0;
3347
Johan Hedbergc80da272012-02-22 15:38:48 +02003348 memset(hdev->eir, 0, sizeof(hdev->eir));
3349
Johan Hedbergcacaf522012-02-21 00:52:42 +02003350 memset(&cp, 0, sizeof(cp));
3351
3352 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
3353}
3354
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003355int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003356{
3357 struct cmd_lookup match = { NULL, hdev };
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003358 bool changed = false;
3359 int err = 0;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003360
3361 if (status) {
3362 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003363
3364 if (enable && test_and_clear_bit(HCI_SSP_ENABLED,
3365 &hdev->dev_flags))
3366 err = new_settings(hdev, NULL);
3367
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003368 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev,
3369 cmd_status_rsp, &mgmt_err);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003370
3371 return err;
3372 }
3373
3374 if (enable) {
3375 if (!test_and_set_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3376 changed = true;
3377 } else {
3378 if (test_and_clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3379 changed = true;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003380 }
3381
3382 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
3383
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003384 if (changed)
3385 err = new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003386
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02003387 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003388 sock_put(match.sk);
3389
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02003390 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3391 update_eir(hdev);
3392 else
3393 clear_eir(hdev);
Johan Hedbergcacaf522012-02-21 00:52:42 +02003394
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003395 return err;
3396}
3397
Johan Hedberg90e70452012-02-23 23:09:40 +02003398static void class_rsp(struct pending_cmd *cmd, void *data)
3399{
3400 struct cmd_lookup *match = data;
3401
3402 cmd_complete(cmd->sk, cmd->index, cmd->opcode, match->mgmt_status,
3403 match->hdev->dev_class, 3);
3404
3405 list_del(&cmd->list);
3406
3407 if (match->sk == NULL) {
3408 match->sk = cmd->sk;
3409 sock_hold(match->sk);
3410 }
3411
3412 mgmt_pending_free(cmd);
3413}
3414
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003415int mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
3416 u8 status)
3417{
Johan Hedberg90e70452012-02-23 23:09:40 +02003418 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
3419 int err = 0;
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003420
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02003421 clear_bit(HCI_PENDING_CLASS, &hdev->dev_flags);
3422
Johan Hedberg90e70452012-02-23 23:09:40 +02003423 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, class_rsp, &match);
3424 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, class_rsp, &match);
3425 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, class_rsp, &match);
3426
3427 if (!status)
3428 err = mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
3429 dev_class, 3, NULL);
3430
3431 if (match.sk)
3432 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003433
3434 return err;
3435}
3436
Johan Hedberg744cf192011-11-08 20:40:14 +02003437int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02003438{
3439 struct pending_cmd *cmd;
3440 struct mgmt_cp_set_local_name ev;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003441 bool changed = false;
3442 int err = 0;
3443
3444 if (memcmp(name, hdev->dev_name, sizeof(hdev->dev_name)) != 0) {
3445 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
3446 changed = true;
3447 }
Johan Hedbergb312b1612011-03-16 14:29:37 +02003448
3449 memset(&ev, 0, sizeof(ev));
3450 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003451 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003452
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003453 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003454 if (!cmd)
3455 goto send_event;
3456
Johan Hedberg7bdaae42012-02-22 21:39:58 +02003457 /* Always assume that either the short or the complete name has
3458 * changed if there was a pending mgmt command */
3459 changed = true;
3460
Johan Hedbergb312b1612011-03-16 14:29:37 +02003461 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02003462 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
Johan Hedbergca69b792011-11-11 18:10:00 +02003463 mgmt_status(status));
Johan Hedbergb312b1612011-03-16 14:29:37 +02003464 goto failed;
3465 }
3466
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003467 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0, &ev,
Johan Hedbergb312b1612011-03-16 14:29:37 +02003468 sizeof(ev));
3469 if (err < 0)
3470 goto failed;
3471
3472send_event:
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003473 if (changed)
3474 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev,
3475 sizeof(ev), cmd ? cmd->sk : NULL);
3476
Johan Hedbergf51d5b22012-02-22 18:17:32 +02003477 update_eir(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003478
3479failed:
3480 if (cmd)
3481 mgmt_pending_remove(cmd);
3482 return err;
3483}
Szymon Jancc35938b2011-03-22 13:12:21 +01003484
Johan Hedberg744cf192011-11-08 20:40:14 +02003485int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
3486 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01003487{
3488 struct pending_cmd *cmd;
3489 int err;
3490
Johan Hedberg744cf192011-11-08 20:40:14 +02003491 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01003492
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003493 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003494 if (!cmd)
3495 return -ENOENT;
3496
3497 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02003498 err = cmd_status(cmd->sk, hdev->id,
Johan Hedbergca69b792011-11-11 18:10:00 +02003499 MGMT_OP_READ_LOCAL_OOB_DATA,
3500 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01003501 } else {
3502 struct mgmt_rp_read_local_oob_data rp;
3503
3504 memcpy(rp.hash, hash, sizeof(rp.hash));
3505 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
3506
Johan Hedberg744cf192011-11-08 20:40:14 +02003507 err = cmd_complete(cmd->sk, hdev->id,
3508 MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003509 0, &rp, sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01003510 }
3511
3512 mgmt_pending_remove(cmd);
3513
3514 return err;
3515}
Johan Hedberge17acd42011-03-30 23:57:16 +03003516
Johan Hedberg06199cf2012-02-22 16:37:11 +02003517int mgmt_le_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
3518{
3519 struct cmd_lookup match = { NULL, hdev };
3520 bool changed = false;
3521 int err = 0;
3522
3523 if (status) {
3524 u8 mgmt_err = mgmt_status(status);
3525
3526 if (enable && test_and_clear_bit(HCI_LE_ENABLED,
3527 &hdev->dev_flags))
3528 err = new_settings(hdev, NULL);
3529
3530 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev,
3531 cmd_status_rsp, &mgmt_err);
3532
3533 return err;
3534 }
3535
3536 if (enable) {
3537 if (!test_and_set_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3538 changed = true;
3539 } else {
3540 if (test_and_clear_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3541 changed = true;
3542 }
3543
3544 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
3545
3546 if (changed)
3547 err = new_settings(hdev, match.sk);
3548
3549 if (match.sk)
3550 sock_put(match.sk);
3551
3552 return err;
3553}
3554
Johan Hedberg48264f02011-11-09 13:58:58 +02003555int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Johan Hedberg561aafb2012-01-04 13:31:59 +02003556 u8 addr_type, u8 *dev_class, s8 rssi,
Johan Hedberg388fc8f2012-02-23 00:38:59 +02003557 u8 cfm_name, u8 ssp, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03003558{
Johan Hedberge319d2e2012-01-15 19:51:59 +02003559 char buf[512];
3560 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02003561 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03003562
Johan Hedberg1dc06092012-01-15 21:01:23 +02003563 /* Leave 5 bytes for a potential CoD field */
3564 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Andre Guedes7d262f82012-01-10 18:20:49 -03003565 return -EINVAL;
3566
Johan Hedberg1dc06092012-01-15 21:01:23 +02003567 memset(buf, 0, sizeof(buf));
3568
Johan Hedberge319d2e2012-01-15 19:51:59 +02003569 bacpy(&ev->addr.bdaddr, bdaddr);
3570 ev->addr.type = link_to_mgmt(link_type, addr_type);
3571 ev->rssi = rssi;
Johan Hedberg9a395a82012-02-23 00:00:32 +02003572 if (cfm_name)
3573 ev->flags[0] |= MGMT_DEV_FOUND_CONFIRM_NAME;
Johan Hedberg388fc8f2012-02-23 00:38:59 +02003574 if (!ssp)
3575 ev->flags[0] |= MGMT_DEV_FOUND_LEGACY_PAIRING;
Johan Hedberge17acd42011-03-30 23:57:16 +03003576
Johan Hedberg1dc06092012-01-15 21:01:23 +02003577 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02003578 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03003579
Johan Hedberg1dc06092012-01-15 21:01:23 +02003580 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
3581 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
3582 dev_class, 3);
3583
3584 put_unaligned_le16(eir_len, &ev->eir_len);
3585
3586 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03003587
Johan Hedberge319d2e2012-01-15 19:51:59 +02003588 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03003589}
Johan Hedberga88a9652011-03-30 13:18:12 +03003590
Johan Hedbergb644ba32012-01-17 21:48:47 +02003591int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
3592 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03003593{
Johan Hedbergb644ba32012-01-17 21:48:47 +02003594 struct mgmt_ev_device_found *ev;
3595 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
3596 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03003597
Johan Hedbergb644ba32012-01-17 21:48:47 +02003598 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03003599
Johan Hedbergb644ba32012-01-17 21:48:47 +02003600 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03003601
Johan Hedbergb644ba32012-01-17 21:48:47 +02003602 bacpy(&ev->addr.bdaddr, bdaddr);
3603 ev->addr.type = link_to_mgmt(link_type, addr_type);
3604 ev->rssi = rssi;
3605
3606 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
3607 name_len);
3608
3609 put_unaligned_le16(eir_len, &ev->eir_len);
3610
Johan Hedberg053c7e02012-02-04 00:06:00 +02003611 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev,
3612 sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03003613}
Johan Hedberg314b2382011-04-27 10:29:57 -04003614
Andre Guedes7a135102011-11-09 17:14:25 -03003615int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
Johan Hedberg164a6e72011-11-01 17:06:44 +02003616{
3617 struct pending_cmd *cmd;
Johan Hedbergf808e162012-02-19 12:52:07 +02003618 u8 type;
Johan Hedberg164a6e72011-11-01 17:06:44 +02003619 int err;
3620
Andre Guedes203159d2012-02-13 15:41:01 -03003621 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3622
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003623 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003624 if (!cmd)
3625 return -ENOENT;
3626
Johan Hedbergf808e162012-02-19 12:52:07 +02003627 type = hdev->discovery.type;
3628
3629 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
3630 &type, sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02003631 mgmt_pending_remove(cmd);
3632
3633 return err;
3634}
3635
Andre Guedese6d465c2011-11-09 17:14:26 -03003636int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
3637{
3638 struct pending_cmd *cmd;
3639 int err;
3640
3641 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
3642 if (!cmd)
3643 return -ENOENT;
3644
Johan Hedbergd9306502012-02-20 23:25:18 +02003645 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
3646 &hdev->discovery.type,
3647 sizeof(hdev->discovery.type));
Johan Hedberg03811012010-12-08 00:21:06 +02003648 mgmt_pending_remove(cmd);
3649
3650 return err;
3651}
Johan Hedberg314b2382011-04-27 10:29:57 -04003652
Johan Hedberg744cf192011-11-08 20:40:14 +02003653int mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04003654{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02003655 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02003656 struct pending_cmd *cmd;
3657
Andre Guedes343fb142011-11-22 17:14:19 -03003658 BT_DBG("%s discovering %u", hdev->name, discovering);
3659
Johan Hedberg164a6e72011-11-01 17:06:44 +02003660 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003661 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003662 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003663 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003664
3665 if (cmd != NULL) {
Johan Hedbergf808e162012-02-19 12:52:07 +02003666 u8 type = hdev->discovery.type;
3667
Johan Hedbergd9306502012-02-20 23:25:18 +02003668 cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0,
Johan Hedbergf808e162012-02-19 12:52:07 +02003669 &type, sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02003670 mgmt_pending_remove(cmd);
3671 }
3672
Johan Hedbergf963e8e2012-02-20 23:30:44 +02003673 memset(&ev, 0, sizeof(ev));
3674 ev.type = hdev->discovery.type;
3675 ev.discovering = discovering;
3676
3677 return mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04003678}
Antti Julku5e762442011-08-25 16:48:02 +03003679
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003680int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003681{
3682 struct pending_cmd *cmd;
3683 struct mgmt_ev_device_blocked ev;
3684
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003685 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003686
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003687 bacpy(&ev.addr.bdaddr, bdaddr);
3688 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003689
Johan Hedberg744cf192011-11-08 20:40:14 +02003690 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
3691 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003692}
3693
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003694int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003695{
3696 struct pending_cmd *cmd;
3697 struct mgmt_ev_device_unblocked ev;
3698
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003699 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003700
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003701 bacpy(&ev.addr.bdaddr, bdaddr);
3702 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003703
Johan Hedberg744cf192011-11-08 20:40:14 +02003704 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
3705 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003706}
Marcel Holtmannd7b7e792012-02-20 21:47:49 +01003707
3708module_param(enable_hs, bool, 0644);
3709MODULE_PARM_DESC(enable_hs, "Enable High Speed support");
3710
3711module_param(enable_le, bool, 0644);
3712MODULE_PARM_DESC(enable_le, "Enable Low Energy support");