blob: 8bc6a7a4873211d34bcdcf56634af0f549c25550 [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 Hedberga38528f2011-01-22 06:46:43 +0200270static int read_version(struct sock *sk)
271{
272 struct mgmt_rp_read_version rp;
273
274 BT_DBG("sock %p", sk);
275
276 rp.version = MGMT_VERSION;
277 put_unaligned_le16(MGMT_REVISION, &rp.revision);
278
Johan Hedbergaee9b2182012-02-18 15:07:59 +0200279 return cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, 0, &rp,
Szymon Janc4e51eae2011-02-25 19:05:48 +0100280 sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200281}
282
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200283static int read_commands(struct sock *sk)
284{
285 struct mgmt_rp_read_commands *rp;
286 u16 num_commands = ARRAY_SIZE(mgmt_commands);
287 u16 num_events = ARRAY_SIZE(mgmt_events);
288 u16 *opcode;
289 size_t rp_size;
290 int i, err;
291
292 BT_DBG("sock %p", sk);
293
294 rp_size = sizeof(*rp) + ((num_commands + num_events) * sizeof(u16));
295
296 rp = kmalloc(rp_size, GFP_KERNEL);
297 if (!rp)
298 return -ENOMEM;
299
300 put_unaligned_le16(num_commands, &rp->num_commands);
301 put_unaligned_le16(num_events, &rp->num_events);
302
303 for (i = 0, opcode = rp->opcodes; i < num_commands; i++, opcode++)
304 put_unaligned_le16(mgmt_commands[i], opcode);
305
306 for (i = 0; i < num_events; i++, opcode++)
307 put_unaligned_le16(mgmt_events[i], opcode);
308
Johan Hedbergaee9b2182012-02-18 15:07:59 +0200309 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_COMMANDS, 0, rp,
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200310 rp_size);
311 kfree(rp);
312
313 return err;
314}
315
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200316static int read_index_list(struct sock *sk)
317{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200318 struct mgmt_rp_read_index_list *rp;
319 struct list_head *p;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200320 struct hci_dev *d;
Johan Hedberga38528f2011-01-22 06:46:43 +0200321 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200322 u16 count;
Johan Hedberga38528f2011-01-22 06:46:43 +0200323 int i, err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200324
325 BT_DBG("sock %p", sk);
326
327 read_lock(&hci_dev_list_lock);
328
329 count = 0;
330 list_for_each(p, &hci_dev_list) {
331 count++;
332 }
333
Johan Hedberga38528f2011-01-22 06:46:43 +0200334 rp_len = sizeof(*rp) + (2 * count);
335 rp = kmalloc(rp_len, GFP_ATOMIC);
336 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100337 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200338 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100339 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200340
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200341 put_unaligned_le16(count, &rp->num_controllers);
342
343 i = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200344 list_for_each_entry(d, &hci_dev_list, list) {
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200345 if (test_bit(HCI_SETUP, &d->dev_flags))
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200346 continue;
347
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200348 put_unaligned_le16(d->id, &rp->index[i++]);
349 BT_DBG("Added hci%u", d->id);
350 }
351
352 read_unlock(&hci_dev_list_lock);
353
Johan Hedbergaee9b2182012-02-18 15:07:59 +0200354 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST, 0, rp,
Szymon Janc4e51eae2011-02-25 19:05:48 +0100355 rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200356
Johan Hedberga38528f2011-01-22 06:46:43 +0200357 kfree(rp);
358
359 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200360}
361
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200362static u32 get_supported_settings(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +0200363{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200364 u32 settings = 0;
Johan Hedberg03811012010-12-08 00:21:06 +0200365
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200366 settings |= MGMT_SETTING_POWERED;
367 settings |= MGMT_SETTING_CONNECTABLE;
368 settings |= MGMT_SETTING_FAST_CONNECTABLE;
369 settings |= MGMT_SETTING_DISCOVERABLE;
370 settings |= MGMT_SETTING_PAIRABLE;
Johan Hedberg03811012010-12-08 00:21:06 +0200371
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200372 if (hdev->features[6] & LMP_SIMPLE_PAIR)
373 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200374
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200375 if (!(hdev->features[4] & LMP_NO_BREDR)) {
376 settings |= MGMT_SETTING_BREDR;
377 settings |= MGMT_SETTING_LINK_SECURITY;
378 }
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200379
Marcel Holtmannd7b7e792012-02-20 21:47:49 +0100380 if (enable_hs)
381 settings |= MGMT_SETTING_HS;
382
383 if (enable_le) {
384 if (hdev->features[4] & LMP_LE)
385 settings |= MGMT_SETTING_LE;
386 }
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200387
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200388 return settings;
389}
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200390
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200391static u32 get_current_settings(struct hci_dev *hdev)
392{
393 u32 settings = 0;
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200394
Johan Hedbergf1f0eb02012-02-21 17:15:41 +0200395 if (hdev_is_powered(hdev))
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100396 settings |= MGMT_SETTING_POWERED;
397
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200398 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200399 settings |= MGMT_SETTING_CONNECTABLE;
400
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200401 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200402 settings |= MGMT_SETTING_DISCOVERABLE;
403
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200404 if (test_bit(HCI_PAIRABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200405 settings |= MGMT_SETTING_PAIRABLE;
406
407 if (!(hdev->features[4] & LMP_NO_BREDR))
408 settings |= MGMT_SETTING_BREDR;
409
Johan Hedberg06199cf2012-02-22 16:37:11 +0200410 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200411 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200412
Johan Hedberg47990ea2012-02-22 11:58:37 +0200413 if (test_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200414 settings |= MGMT_SETTING_LINK_SECURITY;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200415
Johan Hedberg84bde9d2012-01-25 14:21:06 +0200416 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200417 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200418
Johan Hedberg6d80dfd2012-02-20 23:50:38 +0200419 if (test_bit(HCI_HS_ENABLED, &hdev->dev_flags))
420 settings |= MGMT_SETTING_HS;
421
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200422 return settings;
Johan Hedbergc542a062011-01-26 13:11:03 +0200423}
424
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300425#define PNP_INFO_SVCLASS_ID 0x1200
426
427static u8 bluetooth_base_uuid[] = {
428 0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80,
429 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
430};
431
432static u16 get_uuid16(u8 *uuid128)
433{
434 u32 val;
435 int i;
436
437 for (i = 0; i < 12; i++) {
438 if (bluetooth_base_uuid[i] != uuid128[i])
439 return 0;
440 }
441
442 memcpy(&val, &uuid128[12], 4);
443
444 val = le32_to_cpu(val);
445 if (val > 0xffff)
446 return 0;
447
448 return (u16) val;
449}
450
451static void create_eir(struct hci_dev *hdev, u8 *data)
452{
453 u8 *ptr = data;
454 u16 eir_len = 0;
455 u16 uuid16_list[HCI_MAX_EIR_LENGTH / sizeof(u16)];
456 int i, truncated = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200457 struct bt_uuid *uuid;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300458 size_t name_len;
459
460 name_len = strlen(hdev->dev_name);
461
462 if (name_len > 0) {
463 /* EIR Data type */
464 if (name_len > 48) {
465 name_len = 48;
466 ptr[1] = EIR_NAME_SHORT;
467 } else
468 ptr[1] = EIR_NAME_COMPLETE;
469
470 /* EIR Data length */
471 ptr[0] = name_len + 1;
472
473 memcpy(ptr + 2, hdev->dev_name, name_len);
474
475 eir_len += (name_len + 2);
476 ptr += (name_len + 2);
477 }
478
479 memset(uuid16_list, 0, sizeof(uuid16_list));
480
481 /* Group all UUID16 types */
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200482 list_for_each_entry(uuid, &hdev->uuids, list) {
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300483 u16 uuid16;
484
485 uuid16 = get_uuid16(uuid->uuid);
486 if (uuid16 == 0)
487 return;
488
489 if (uuid16 < 0x1100)
490 continue;
491
492 if (uuid16 == PNP_INFO_SVCLASS_ID)
493 continue;
494
495 /* Stop if not enough space to put next UUID */
496 if (eir_len + 2 + sizeof(u16) > HCI_MAX_EIR_LENGTH) {
497 truncated = 1;
498 break;
499 }
500
501 /* Check for duplicates */
502 for (i = 0; uuid16_list[i] != 0; i++)
503 if (uuid16_list[i] == uuid16)
504 break;
505
506 if (uuid16_list[i] == 0) {
507 uuid16_list[i] = uuid16;
508 eir_len += sizeof(u16);
509 }
510 }
511
512 if (uuid16_list[0] != 0) {
513 u8 *length = ptr;
514
515 /* EIR Data type */
516 ptr[1] = truncated ? EIR_UUID16_SOME : EIR_UUID16_ALL;
517
518 ptr += 2;
519 eir_len += 2;
520
521 for (i = 0; uuid16_list[i] != 0; i++) {
522 *ptr++ = (uuid16_list[i] & 0x00ff);
523 *ptr++ = (uuid16_list[i] & 0xff00) >> 8;
524 }
525
526 /* EIR Data length */
527 *length = (i * sizeof(u16)) + 1;
528 }
529}
530
531static int update_eir(struct hci_dev *hdev)
532{
533 struct hci_cp_write_eir cp;
534
535 if (!(hdev->features[6] & LMP_EXT_INQ))
536 return 0;
537
Johan Hedberg84bde9d2012-01-25 14:21:06 +0200538 if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300539 return 0;
540
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200541 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300542 return 0;
543
544 memset(&cp, 0, sizeof(cp));
545
546 create_eir(hdev, cp.data);
547
548 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
549 return 0;
550
551 memcpy(hdev->eir, cp.data, sizeof(cp.data));
552
553 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
554}
555
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200556static u8 get_service_classes(struct hci_dev *hdev)
557{
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300558 struct bt_uuid *uuid;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200559 u8 val = 0;
560
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300561 list_for_each_entry(uuid, &hdev->uuids, list)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200562 val |= uuid->svc_hint;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200563
564 return val;
565}
566
567static int update_class(struct hci_dev *hdev)
568{
569 u8 cod[3];
570
571 BT_DBG("%s", hdev->name);
572
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200573 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200574 return 0;
575
576 cod[0] = hdev->minor_class;
577 cod[1] = hdev->major_class;
578 cod[2] = get_service_classes(hdev);
579
580 if (memcmp(cod, hdev->dev_class, 3) == 0)
581 return 0;
582
583 return hci_send_cmd(hdev, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
584}
585
Johan Hedberg7d785252011-12-15 00:47:39 +0200586static void service_cache_off(struct work_struct *work)
587{
588 struct hci_dev *hdev = container_of(work, struct hci_dev,
589 service_cache.work);
590
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200591 if (!test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200592 return;
593
594 hci_dev_lock(hdev);
595
596 update_eir(hdev);
597 update_class(hdev);
598
599 hci_dev_unlock(hdev);
600}
601
602static void mgmt_init_hdev(struct hci_dev *hdev)
603{
Johan Hedberg0cbf4ed62012-02-21 17:25:22 +0200604 if (!test_and_set_bit(HCI_MGMT, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +0200605 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
606
Johan Hedberg0cbf4ed62012-02-21 17:25:22 +0200607 /* Non-mgmt controlled devices get this bit set
608 * implicitly so that pairing works for them, however
609 * for mgmt we require user-space to explicitly enable
610 * it
611 */
612 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
613 }
614
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200615 if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200616 schedule_delayed_work(&hdev->service_cache,
617 msecs_to_jiffies(SERVICE_CACHE_TIMEOUT));
618}
619
Johan Hedberg03811012010-12-08 00:21:06 +0200620static int read_controller_info(struct sock *sk, u16 index)
621{
622 struct mgmt_rp_read_info rp;
623 struct hci_dev *hdev;
624
625 BT_DBG("sock %p hci%u", sk, index);
626
627 hdev = hci_dev_get(index);
628 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200629 return cmd_status(sk, index, MGMT_OP_READ_INFO,
630 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200631
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300632 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200633
Johan Hedberg7d785252011-12-15 00:47:39 +0200634 if (test_and_clear_bit(HCI_PI_MGMT_INIT, &hci_pi(sk)->flags))
635 mgmt_init_hdev(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200636
637 memset(&rp, 0, sizeof(rp));
638
Johan Hedberg03811012010-12-08 00:21:06 +0200639 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200640
641 rp.version = hdev->hci_ver;
642
Johan Hedberg03811012010-12-08 00:21:06 +0200643 put_unaligned_le16(hdev->manufacturer, &rp.manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200644
645 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
646 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
647
648 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedberg03811012010-12-08 00:21:06 +0200649
650 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
651
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300652 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200653 hci_dev_put(hdev);
654
Johan Hedbergaee9b2182012-02-18 15:07:59 +0200655 return cmd_complete(sk, index, MGMT_OP_READ_INFO, 0, &rp, sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +0200656}
657
658static void mgmt_pending_free(struct pending_cmd *cmd)
659{
660 sock_put(cmd->sk);
661 kfree(cmd->param);
662 kfree(cmd);
663}
664
665static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
666 struct hci_dev *hdev,
667 void *data, u16 len)
668{
669 struct pending_cmd *cmd;
670
671 cmd = kmalloc(sizeof(*cmd), GFP_ATOMIC);
672 if (!cmd)
673 return NULL;
674
675 cmd->opcode = opcode;
676 cmd->index = hdev->id;
677
678 cmd->param = kmalloc(len, GFP_ATOMIC);
679 if (!cmd->param) {
680 kfree(cmd);
681 return NULL;
682 }
683
684 if (data)
685 memcpy(cmd->param, data, len);
686
687 cmd->sk = sk;
688 sock_hold(sk);
689
690 list_add(&cmd->list, &hdev->mgmt_pending);
691
692 return cmd;
693}
694
695static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
696 void (*cb)(struct pending_cmd *cmd, void *data),
697 void *data)
698{
699 struct list_head *p, *n;
700
701 list_for_each_safe(p, n, &hdev->mgmt_pending) {
702 struct pending_cmd *cmd;
703
704 cmd = list_entry(p, struct pending_cmd, list);
705
706 if (opcode > 0 && cmd->opcode != opcode)
707 continue;
708
709 cb(cmd, data);
710 }
711}
712
713static struct pending_cmd *mgmt_pending_find(u16 opcode, struct hci_dev *hdev)
714{
715 struct pending_cmd *cmd;
716
717 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
718 if (cmd->opcode == opcode)
719 return cmd;
720 }
721
722 return NULL;
723}
724
725static void mgmt_pending_remove(struct pending_cmd *cmd)
726{
727 list_del(&cmd->list);
728 mgmt_pending_free(cmd);
729}
730
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200731static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +0200732{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200733 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +0200734
Johan Hedbergaee9b2182012-02-18 15:07:59 +0200735 return cmd_complete(sk, hdev->id, opcode, 0, &settings,
736 sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +0200737}
738
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300739static int set_powered(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200740{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300741 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200742 struct hci_dev *hdev;
743 struct pending_cmd *cmd;
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200744 int err;
Johan Hedberg03811012010-12-08 00:21:06 +0200745
Johan Hedberg03811012010-12-08 00:21:06 +0200746 BT_DBG("request for hci%u", index);
747
748 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200749 return cmd_status(sk, index, MGMT_OP_SET_POWERED,
750 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200751
752 hdev = hci_dev_get(index);
753 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200754 return cmd_status(sk, index, MGMT_OP_SET_POWERED,
755 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200756
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300757 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200758
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100759 if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) {
760 cancel_delayed_work(&hdev->power_off);
761
762 if (cp->val) {
763 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
764 mgmt_powered(hdev, 1);
765 goto failed;
766 }
767 }
768
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200769 if (!!cp->val == hdev_is_powered(hdev)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200770 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200771 goto failed;
772 }
773
774 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200775 err = cmd_status(sk, index, MGMT_OP_SET_POWERED,
776 MGMT_STATUS_BUSY);
Johan Hedberg03811012010-12-08 00:21:06 +0200777 goto failed;
778 }
779
780 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
781 if (!cmd) {
782 err = -ENOMEM;
783 goto failed;
784 }
785
786 if (cp->val)
Gustavo F. Padovan7f971042011-12-18 12:40:32 -0200787 schedule_work(&hdev->power_on);
Johan Hedberg03811012010-12-08 00:21:06 +0200788 else
Gustavo F. Padovan80b7ab32011-12-17 14:52:27 -0200789 schedule_work(&hdev->power_off.work);
Johan Hedberg03811012010-12-08 00:21:06 +0200790
791 err = 0;
792
793failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300794 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200795 hci_dev_put(hdev);
796 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
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300838static int set_discoverable(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200839{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300840 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberge41d8b42010-12-13 21:07:03 +0200841 struct hci_dev *hdev;
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 Hedberg03811012010-12-08 00:21:06 +0200847 BT_DBG("request for hci%u", index);
848
849 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200850 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
851 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200852
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200853 hdev = hci_dev_get(index);
854 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200855 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
856 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200857
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200858 timeout = get_unaligned_le16(&cp->timeout);
859
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300860 hci_dev_lock(hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200861
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200862 if (!hdev_is_powered(hdev) && timeout > 0) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200863 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
864 MGMT_STATUS_NOT_POWERED);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200865 goto failed;
866 }
867
868 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
869 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200870 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
871 MGMT_STATUS_BUSY);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200872 goto failed;
873 }
874
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200875 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) {
876 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
877 MGMT_STATUS_REJECTED);
878 goto failed;
879 }
880
881 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200882 bool changed = false;
883
884 if (!!cp->val != test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
885 change_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
886 changed = true;
887 }
888
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200889 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200890 if (err < 0)
891 goto failed;
892
893 if (changed)
894 err = new_settings(hdev, sk);
895
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200896 goto failed;
897 }
898
899 if (!!cp->val == test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200900 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200901 goto failed;
902 }
903
904 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
905 if (!cmd) {
906 err = -ENOMEM;
907 goto failed;
908 }
909
910 scan = SCAN_PAGE;
911
912 if (cp->val)
913 scan |= SCAN_INQUIRY;
914 else
915 cancel_delayed_work(&hdev->discov_off);
916
917 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
918 if (err < 0)
919 mgmt_pending_remove(cmd);
920
Johan Hedberg03811012010-12-08 00:21:06 +0200921 if (cp->val)
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200922 hdev->discov_timeout = timeout;
Johan Hedberg03811012010-12-08 00:21:06 +0200923
924failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300925 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200926 hci_dev_put(hdev);
927
928 return err;
929}
930
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300931static int set_connectable(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200932{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300933 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200934 struct hci_dev *hdev;
935 struct pending_cmd *cmd;
936 u8 scan;
937 int err;
938
Johan Hedberge41d8b42010-12-13 21:07:03 +0200939 BT_DBG("request for hci%u", index);
940
Johan Hedberg03811012010-12-08 00:21:06 +0200941 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200942 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
943 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200944
945 hdev = hci_dev_get(index);
946 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200947 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
948 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200949
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300950 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200951
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200952 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200953 bool changed = false;
954
955 if (!!cp->val != test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
956 changed = true;
957
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +0200958 if (cp->val) {
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200959 set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +0200960 } else {
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200961 clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
962 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
963 }
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200964
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200965 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200966 if (err < 0)
967 goto failed;
968
969 if (changed)
970 err = new_settings(hdev, sk);
971
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200972 goto failed;
973 }
974
975 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
976 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200977 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
978 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200979 goto failed;
980 }
981
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200982 if (!!cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200983 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200984 goto failed;
985 }
986
987 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
988 if (!cmd) {
989 err = -ENOMEM;
990 goto failed;
991 }
992
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +0200993 if (cp->val) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200994 scan = SCAN_PAGE;
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +0200995 } else {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200996 scan = 0;
997
Johan Hedbergdf2c6c52012-02-21 19:15:49 +0200998 if (test_bit(HCI_ISCAN, &hdev->flags) &&
999 hdev->discov_timeout > 0)
1000 cancel_delayed_work(&hdev->discov_off);
1001 }
1002
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001003 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1004 if (err < 0)
1005 mgmt_pending_remove(cmd);
1006
1007failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001008 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001009 hci_dev_put(hdev);
1010
1011 return err;
1012}
1013
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001014static int set_pairable(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001015{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001016 struct mgmt_mode *cp = data;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001017 struct hci_dev *hdev;
1018 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001019
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001020 BT_DBG("request for hci%u", index);
1021
1022 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001023 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE,
1024 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001025
1026 hdev = hci_dev_get(index);
1027 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001028 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE,
1029 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001030
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001031 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001032
1033 if (cp->val)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001034 set_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001035 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001036 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001037
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001038 err = send_settings_rsp(sk, MGMT_OP_SET_PAIRABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001039 if (err < 0)
1040 goto failed;
1041
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001042 err = new_settings(hdev, sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001043
1044failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001045 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001046 hci_dev_put(hdev);
1047
1048 return err;
1049}
Johan Hedberg72a734e2010-12-30 00:38:22 +02001050
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001051static int set_link_security(struct sock *sk, u16 index, void *data, u16 len)
1052{
1053 struct mgmt_mode *cp = data;
1054 struct pending_cmd *cmd;
1055 struct hci_dev *hdev;
1056 uint8_t val;
1057 int err;
1058
1059 BT_DBG("request for hci%u", index);
1060
1061 if (len != sizeof(*cp))
1062 return cmd_status(sk, index, MGMT_OP_SET_LINK_SECURITY,
1063 MGMT_STATUS_INVALID_PARAMS);
1064
1065 hdev = hci_dev_get(index);
1066 if (!hdev)
1067 return cmd_status(sk, index, MGMT_OP_SET_LINK_SECURITY,
1068 MGMT_STATUS_INVALID_PARAMS);
1069
1070 hci_dev_lock(hdev);
1071
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001072 if (!hdev_is_powered(hdev)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001073 bool changed = false;
1074
1075 if (!!cp->val != test_bit(HCI_LINK_SECURITY,
1076 &hdev->dev_flags)) {
1077 change_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
1078 changed = true;
1079 }
1080
1081 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1082 if (err < 0)
1083 goto failed;
1084
1085 if (changed)
1086 err = new_settings(hdev, sk);
1087
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001088 goto failed;
1089 }
1090
1091 if (mgmt_pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
1092 err = cmd_status(sk, index, MGMT_OP_SET_LINK_SECURITY,
1093 MGMT_STATUS_BUSY);
1094 goto failed;
1095 }
1096
1097 val = !!cp->val;
1098
1099 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1100 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1101 goto failed;
1102 }
1103
1104 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1105 if (!cmd) {
1106 err = -ENOMEM;
1107 goto failed;
1108 }
1109
1110 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1111 if (err < 0) {
1112 mgmt_pending_remove(cmd);
1113 goto failed;
1114 }
1115
1116failed:
1117 hci_dev_unlock(hdev);
1118 hci_dev_put(hdev);
1119
1120 return err;
1121}
1122
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001123static int set_ssp(struct sock *sk, u16 index, void *data, u16 len)
1124{
1125 struct mgmt_mode *cp = data;
1126 struct pending_cmd *cmd;
1127 struct hci_dev *hdev;
1128 uint8_t val;
1129 int err;
1130
1131 BT_DBG("request for hci%u", index);
1132
1133 if (len != sizeof(*cp))
1134 return cmd_status(sk, index, MGMT_OP_SET_SSP,
1135 MGMT_STATUS_INVALID_PARAMS);
1136
1137 hdev = hci_dev_get(index);
1138 if (!hdev)
1139 return cmd_status(sk, index, MGMT_OP_SET_SSP,
1140 MGMT_STATUS_INVALID_PARAMS);
1141
1142 hci_dev_lock(hdev);
1143
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001144 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
1145 err = cmd_status(sk, index, MGMT_OP_SET_SSP,
1146 MGMT_STATUS_NOT_SUPPORTED);
1147 goto failed;
1148 }
1149
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001150 val = !!cp->val;
1151
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001152 if (!hdev_is_powered(hdev)) {
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001153 bool changed = false;
1154
1155 if (val != test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) {
1156 change_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
1157 changed = true;
1158 }
1159
1160 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1161 if (err < 0)
1162 goto failed;
1163
1164 if (changed)
1165 err = new_settings(hdev, sk);
1166
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001167 goto failed;
1168 }
1169
1170 if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev)) {
1171 err = cmd_status(sk, index, MGMT_OP_SET_SSP, MGMT_STATUS_BUSY);
1172 goto failed;
1173 }
1174
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001175 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) == val) {
1176 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1177 goto failed;
1178 }
1179
1180 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1181 if (!cmd) {
1182 err = -ENOMEM;
1183 goto failed;
1184 }
1185
1186 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, sizeof(val), &val);
1187 if (err < 0) {
1188 mgmt_pending_remove(cmd);
1189 goto failed;
1190 }
1191
1192failed:
1193 hci_dev_unlock(hdev);
1194 hci_dev_put(hdev);
1195
1196 return err;
1197}
1198
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001199static int set_hs(struct sock *sk, u16 index, void *data, u16 len)
1200{
1201 struct mgmt_mode *cp = data;
1202 struct hci_dev *hdev;
1203 int err;
1204
1205 BT_DBG("request for hci%u", index);
1206
1207 if (len != sizeof(*cp))
1208 return cmd_status(sk, index, MGMT_OP_SET_HS,
1209 MGMT_STATUS_INVALID_PARAMS);
1210
1211 hdev = hci_dev_get(index);
1212 if (!hdev)
1213 return cmd_status(sk, index, MGMT_OP_SET_HS,
1214 MGMT_STATUS_INVALID_PARAMS);
1215
1216 if (!enable_hs) {
1217 err = cmd_status(sk, index, MGMT_OP_SET_HS,
1218 MGMT_STATUS_NOT_SUPPORTED);
1219 goto failed;
1220 }
1221
1222 if (cp->val)
1223 set_bit(HCI_HS_ENABLED, &hdev->dev_flags);
1224 else
1225 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
1226
1227 err = send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
1228
1229failed:
1230 hci_dev_put(hdev);
1231 return err;
1232}
1233
Johan Hedberg06199cf2012-02-22 16:37:11 +02001234static int set_le(struct sock *sk, u16 index, void *data, u16 len)
1235{
1236 struct mgmt_mode *cp = data;
1237 struct hci_cp_write_le_host_supported hci_cp;
1238 struct pending_cmd *cmd;
1239 struct hci_dev *hdev;
1240 int err;
1241 u8 val;
1242
1243 BT_DBG("request for hci%u", index);
1244
1245 if (len != sizeof(*cp))
1246 return cmd_status(sk, index, MGMT_OP_SET_LE,
1247 MGMT_STATUS_INVALID_PARAMS);
1248
1249 hdev = hci_dev_get(index);
1250 if (!hdev)
1251 return cmd_status(sk, index, MGMT_OP_SET_LE,
1252 MGMT_STATUS_INVALID_PARAMS);
1253
1254 if (!enable_le || !(hdev->features[4] & LMP_LE)) {
1255 err = cmd_status(sk, index, MGMT_OP_SET_LE,
1256 MGMT_STATUS_NOT_SUPPORTED);
1257 goto failed;
1258 }
1259
1260 val = !!cp->val;
1261
1262 if (!hdev_is_powered(hdev)) {
1263 bool changed = false;
1264
1265 if (val != test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
1266 change_bit(HCI_LE_ENABLED, &hdev->dev_flags);
1267 changed = true;
1268 }
1269
1270 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1271 if (err < 0)
1272 goto failed;
1273
1274 if (changed)
1275 err = new_settings(hdev, sk);
1276
1277 goto failed;
1278 }
1279
1280 if (mgmt_pending_find(MGMT_OP_SET_LE, hdev)) {
1281 err = cmd_status(sk, index, MGMT_OP_SET_LE, MGMT_STATUS_BUSY);
1282 goto failed;
1283 }
1284
1285 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
1286 if (!cmd) {
1287 err = -ENOMEM;
1288 goto failed;
1289 }
1290
1291 memset(&hci_cp, 0, sizeof(hci_cp));
1292
1293 if (val) {
1294 hci_cp.le = val;
1295 hci_cp.simul = !!(hdev->features[6] & LMP_SIMUL_LE_BR);
1296 }
1297
1298 err = hci_send_cmd(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED,
1299 sizeof(hci_cp), &hci_cp);
1300 if (err < 0) {
1301 mgmt_pending_remove(cmd);
1302 goto failed;
1303 }
1304
1305failed:
1306 hci_dev_put(hdev);
1307 return err;
1308}
1309
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001310static int add_uuid(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001311{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001312 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001313 struct hci_dev *hdev;
1314 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001315 int err;
1316
Szymon Janc4e51eae2011-02-25 19:05:48 +01001317 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001318
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001319 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001320 return cmd_status(sk, index, MGMT_OP_ADD_UUID,
1321 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001322
Szymon Janc4e51eae2011-02-25 19:05:48 +01001323 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001324 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001325 return cmd_status(sk, index, MGMT_OP_ADD_UUID,
1326 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001327
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001328 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001329
1330 uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC);
1331 if (!uuid) {
1332 err = -ENOMEM;
1333 goto failed;
1334 }
1335
1336 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001337 uuid->svc_hint = cp->svc_hint;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001338
1339 list_add(&uuid->list, &hdev->uuids);
1340
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001341 err = update_class(hdev);
1342 if (err < 0)
1343 goto failed;
1344
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001345 err = update_eir(hdev);
1346 if (err < 0)
1347 goto failed;
1348
Johan Hedbergaee9b2182012-02-18 15:07:59 +02001349 err = cmd_complete(sk, index, MGMT_OP_ADD_UUID, 0, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001350
1351failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001352 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001353 hci_dev_put(hdev);
1354
1355 return err;
1356}
1357
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001358static int remove_uuid(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001359{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001360 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001361 struct list_head *p, *n;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001362 struct hci_dev *hdev;
1363 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 +02001364 int err, found;
1365
Szymon Janc4e51eae2011-02-25 19:05:48 +01001366 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001367
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001368 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001369 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
1370 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001371
Szymon Janc4e51eae2011-02-25 19:05:48 +01001372 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001373 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001374 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
1375 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001376
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001377 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001378
1379 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
1380 err = hci_uuids_clear(hdev);
1381 goto unlock;
1382 }
1383
1384 found = 0;
1385
1386 list_for_each_safe(p, n, &hdev->uuids) {
1387 struct bt_uuid *match = list_entry(p, struct bt_uuid, list);
1388
1389 if (memcmp(match->uuid, cp->uuid, 16) != 0)
1390 continue;
1391
1392 list_del(&match->list);
1393 found++;
1394 }
1395
1396 if (found == 0) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001397 err = cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
1398 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001399 goto unlock;
1400 }
1401
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001402 err = update_class(hdev);
1403 if (err < 0)
1404 goto unlock;
1405
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001406 err = update_eir(hdev);
1407 if (err < 0)
1408 goto unlock;
1409
Johan Hedbergaee9b2182012-02-18 15:07:59 +02001410 err = cmd_complete(sk, index, MGMT_OP_REMOVE_UUID, 0, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001411
1412unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001413 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001414 hci_dev_put(hdev);
1415
1416 return err;
1417}
1418
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001419static int set_dev_class(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001420{
1421 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001422 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001423 int err;
1424
Szymon Janc4e51eae2011-02-25 19:05:48 +01001425 BT_DBG("request for hci%u", index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001426
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001427 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001428 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS,
1429 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001430
Szymon Janc4e51eae2011-02-25 19:05:48 +01001431 hdev = hci_dev_get(index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001432 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001433 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS,
1434 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001435
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001436 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001437
Johan Hedbergb5235a62012-02-21 14:32:24 +02001438 if (!hdev_is_powered(hdev)) {
1439 err = cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS,
1440 MGMT_STATUS_NOT_POWERED);
1441 goto unlock;
1442 }
1443
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001444 hdev->major_class = cp->major;
1445 hdev->minor_class = cp->minor;
1446
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001447 if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02001448 hci_dev_unlock(hdev);
1449 cancel_delayed_work_sync(&hdev->service_cache);
1450 hci_dev_lock(hdev);
Johan Hedberg14c0b602011-12-15 00:47:37 +02001451 update_eir(hdev);
Johan Hedberg7d785252011-12-15 00:47:39 +02001452 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02001453
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001454 err = update_class(hdev);
1455
1456 if (err == 0)
Johan Hedbergaee9b2182012-02-18 15:07:59 +02001457 err = cmd_complete(sk, index, MGMT_OP_SET_DEV_CLASS, 0,
1458 NULL, 0);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001459
Johan Hedbergb5235a62012-02-21 14:32:24 +02001460unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001461 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001462 hci_dev_put(hdev);
1463
1464 return err;
1465}
1466
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001467static int load_link_keys(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001468{
1469 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001470 struct mgmt_cp_load_link_keys *cp = data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001471 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001472 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001473
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001474 if (len < sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001475 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1476 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001477
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001478 key_count = get_unaligned_le16(&cp->key_count);
1479
Johan Hedberg86742e12011-11-07 23:13:38 +02001480 expected_len = sizeof(*cp) + key_count *
1481 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001482 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001483 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001484 len, expected_len);
Johan Hedbergca69b792011-11-11 18:10:00 +02001485 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1486 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001487 }
1488
Szymon Janc4e51eae2011-02-25 19:05:48 +01001489 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001490 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001491 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1492 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001493
Szymon Janc4e51eae2011-02-25 19:05:48 +01001494 BT_DBG("hci%u debug_keys %u key_count %u", index, cp->debug_keys,
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001495 key_count);
1496
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001497 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001498
1499 hci_link_keys_clear(hdev);
1500
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001501 set_bit(HCI_LINK_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001502
1503 if (cp->debug_keys)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001504 set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001505 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001506 clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001507
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001508 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001509 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001510
Johan Hedbergd753fdc2012-02-17 14:06:34 +02001511 hci_add_link_key(hdev, NULL, 0, &key->addr.bdaddr, key->val,
1512 key->type, key->pin_len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001513 }
1514
Johan Hedbergaee9b2182012-02-18 15:07:59 +02001515 cmd_complete(sk, index, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02001516
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001517 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001518 hci_dev_put(hdev);
1519
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001520 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001521}
1522
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001523static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
1524 u8 addr_type, struct sock *skip_sk)
1525{
1526 struct mgmt_ev_device_unpaired ev;
1527
1528 bacpy(&ev.addr.bdaddr, bdaddr);
1529 ev.addr.type = addr_type;
1530
1531 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
1532 skip_sk);
1533}
1534
Johan Hedberg124f6e32012-02-09 13:50:12 +02001535static int unpair_device(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001536{
1537 struct hci_dev *hdev;
Johan Hedberg124f6e32012-02-09 13:50:12 +02001538 struct mgmt_cp_unpair_device *cp = data;
1539 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001540 struct hci_cp_disconnect dc;
1541 struct pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001542 struct hci_conn *conn;
Johan Hedbergaee9b2182012-02-18 15:07:59 +02001543 u8 status = 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001544 int err;
1545
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001546 if (len != sizeof(*cp))
Johan Hedberg124f6e32012-02-09 13:50:12 +02001547 return cmd_status(sk, index, MGMT_OP_UNPAIR_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02001548 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001549
Szymon Janc4e51eae2011-02-25 19:05:48 +01001550 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001551 if (!hdev)
Johan Hedberg124f6e32012-02-09 13:50:12 +02001552 return cmd_status(sk, index, MGMT_OP_UNPAIR_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02001553 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001554
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001555 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001556
Johan Hedberga8a1d192011-11-10 15:54:38 +02001557 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02001558 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1559 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001560
Johan Hedberg124f6e32012-02-09 13:50:12 +02001561 if (cp->addr.type == MGMT_ADDR_BREDR)
1562 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
1563 else
1564 err = hci_remove_ltk(hdev, &cp->addr.bdaddr);
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03001565
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001566 if (err < 0) {
Johan Hedbergaee9b2182012-02-18 15:07:59 +02001567 status = MGMT_STATUS_NOT_PAIRED;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001568 goto unlock;
1569 }
1570
Johan Hedberga8a1d192011-11-10 15:54:38 +02001571 if (!test_bit(HCI_UP, &hdev->flags) || !cp->disconnect) {
Johan Hedbergaee9b2182012-02-18 15:07:59 +02001572 err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE, status,
1573 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001574 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001575 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001576 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001577
Johan Hedberg124f6e32012-02-09 13:50:12 +02001578 if (cp->addr.type == MGMT_ADDR_BREDR)
1579 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
1580 &cp->addr.bdaddr);
1581 else
1582 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
1583 &cp->addr.bdaddr);
1584
Johan Hedberga8a1d192011-11-10 15:54:38 +02001585 if (!conn) {
Johan Hedbergaee9b2182012-02-18 15:07:59 +02001586 err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE, status,
1587 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001588 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001589 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001590 }
1591
Johan Hedberg124f6e32012-02-09 13:50:12 +02001592 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
1593 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02001594 if (!cmd) {
1595 err = -ENOMEM;
1596 goto unlock;
1597 }
1598
1599 put_unaligned_le16(conn->handle, &dc.handle);
1600 dc.reason = 0x13; /* Remote User Terminated Connection */
1601 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1602 if (err < 0)
1603 mgmt_pending_remove(cmd);
1604
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001605unlock:
Johan Hedbergca69b792011-11-11 18:10:00 +02001606 if (err < 0)
Johan Hedbergaee9b2182012-02-18 15:07:59 +02001607 err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE, status,
1608 &rp, sizeof(rp));
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001609 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001610 hci_dev_put(hdev);
1611
1612 return err;
1613}
1614
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001615static int disconnect(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02001616{
1617 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001618 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001619 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03001620 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001621 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001622 int err;
1623
1624 BT_DBG("");
1625
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001626 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001627 return cmd_status(sk, index, MGMT_OP_DISCONNECT,
1628 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001629
Szymon Janc4e51eae2011-02-25 19:05:48 +01001630 hdev = hci_dev_get(index);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001631 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001632 return cmd_status(sk, index, MGMT_OP_DISCONNECT,
1633 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001634
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001635 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001636
1637 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001638 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1639 MGMT_STATUS_NOT_POWERED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001640 goto failed;
1641 }
1642
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001643 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001644 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1645 MGMT_STATUS_BUSY);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001646 goto failed;
1647 }
1648
Johan Hedberg88c3df12012-02-09 14:27:38 +02001649 if (cp->addr.type == MGMT_ADDR_BREDR)
1650 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
1651 else
1652 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03001653
Johan Hedberg8962ee72011-01-20 12:40:27 +02001654 if (!conn) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001655 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1656 MGMT_STATUS_NOT_CONNECTED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001657 goto failed;
1658 }
1659
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001660 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001661 if (!cmd) {
1662 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001663 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001664 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001665
1666 put_unaligned_le16(conn->handle, &dc.handle);
1667 dc.reason = 0x13; /* Remote User Terminated Connection */
1668
1669 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1670 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001671 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001672
1673failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001674 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001675 hci_dev_put(hdev);
1676
1677 return err;
1678}
1679
Johan Hedberg48264f02011-11-09 13:58:58 +02001680static u8 link_to_mgmt(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02001681{
1682 switch (link_type) {
1683 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02001684 switch (addr_type) {
1685 case ADDR_LE_DEV_PUBLIC:
1686 return MGMT_ADDR_LE_PUBLIC;
1687 case ADDR_LE_DEV_RANDOM:
1688 return MGMT_ADDR_LE_RANDOM;
1689 default:
1690 return MGMT_ADDR_INVALID;
1691 }
Johan Hedberg4c659c32011-11-07 23:13:39 +02001692 case ACL_LINK:
1693 return MGMT_ADDR_BREDR;
1694 default:
1695 return MGMT_ADDR_INVALID;
1696 }
1697}
1698
Szymon Janc8ce62842011-03-01 16:55:32 +01001699static int get_connections(struct sock *sk, u16 index)
Johan Hedberg2784eb42011-01-21 13:56:35 +02001700{
Johan Hedberg2784eb42011-01-21 13:56:35 +02001701 struct mgmt_rp_get_connections *rp;
1702 struct hci_dev *hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001703 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02001704 size_t rp_len;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001705 u16 count;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001706 int i, err;
1707
1708 BT_DBG("");
1709
Szymon Janc4e51eae2011-02-25 19:05:48 +01001710 hdev = hci_dev_get(index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001711 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001712 return cmd_status(sk, index, MGMT_OP_GET_CONNECTIONS,
1713 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001714
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001715 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001716
1717 count = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02001718 list_for_each_entry(c, &hdev->conn_hash.list, list) {
1719 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
1720 count++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001721 }
1722
Johan Hedberg4c659c32011-11-07 23:13:39 +02001723 rp_len = sizeof(*rp) + (count * sizeof(struct mgmt_addr_info));
Johan Hedberga38528f2011-01-22 06:46:43 +02001724 rp = kmalloc(rp_len, GFP_ATOMIC);
1725 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02001726 err = -ENOMEM;
1727 goto unlock;
1728 }
1729
Johan Hedberg2784eb42011-01-21 13:56:35 +02001730 put_unaligned_le16(count, &rp->conn_count);
1731
Johan Hedberg2784eb42011-01-21 13:56:35 +02001732 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001733 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02001734 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
1735 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001736 bacpy(&rp->addr[i].bdaddr, &c->dst);
Johan Hedberg48264f02011-11-09 13:58:58 +02001737 rp->addr[i].type = link_to_mgmt(c->type, c->dst_type);
Johan Hedberg4c659c32011-11-07 23:13:39 +02001738 if (rp->addr[i].type == MGMT_ADDR_INVALID)
1739 continue;
1740 i++;
1741 }
1742
1743 /* Recalculate length in case of filtered SCO connections, etc */
1744 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02001745
Johan Hedbergaee9b2182012-02-18 15:07:59 +02001746 err = cmd_complete(sk, index, MGMT_OP_GET_CONNECTIONS, 0, rp, rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001747
1748unlock:
Johan Hedberga38528f2011-01-22 06:46:43 +02001749 kfree(rp);
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001750 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001751 hci_dev_put(hdev);
1752 return err;
1753}
1754
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001755static int send_pin_code_neg_reply(struct sock *sk, u16 index,
1756 struct hci_dev *hdev, struct mgmt_cp_pin_code_neg_reply *cp)
1757{
1758 struct pending_cmd *cmd;
1759 int err;
1760
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001761 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001762 sizeof(*cp));
1763 if (!cmd)
1764 return -ENOMEM;
1765
Johan Hedbergd8457692012-02-17 14:24:57 +02001766 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
1767 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001768 if (err < 0)
1769 mgmt_pending_remove(cmd);
1770
1771 return err;
1772}
1773
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001774static int pin_code_reply(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001775{
1776 struct hci_dev *hdev;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001777 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001778 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001779 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03001780 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001781 int err;
1782
1783 BT_DBG("");
1784
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001785 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001786 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1787 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001788
Szymon Janc4e51eae2011-02-25 19:05:48 +01001789 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001790 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001791 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1792 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001793
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001794 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001795
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001796 if (!hdev_is_powered(hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001797 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1798 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001799 goto failed;
1800 }
1801
Johan Hedbergd8457692012-02-17 14:24:57 +02001802 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001803 if (!conn) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001804 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1805 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001806 goto failed;
1807 }
1808
1809 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02001810 struct mgmt_cp_pin_code_neg_reply ncp;
1811
1812 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001813
1814 BT_ERR("PIN code is not 16 bytes long");
1815
1816 err = send_pin_code_neg_reply(sk, index, hdev, &ncp);
1817 if (err >= 0)
1818 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001819 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001820
1821 goto failed;
1822 }
1823
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001824 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data,
1825 len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001826 if (!cmd) {
1827 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001828 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001829 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02001830
Johan Hedbergd8457692012-02-17 14:24:57 +02001831 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001832 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02001833 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02001834
1835 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
1836 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001837 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001838
1839failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001840 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001841 hci_dev_put(hdev);
1842
1843 return err;
1844}
1845
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001846static int pin_code_neg_reply(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001847{
1848 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001849 struct mgmt_cp_pin_code_neg_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001850 int err;
1851
1852 BT_DBG("");
1853
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001854 if (len != sizeof(*cp))
1855 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001856 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001857
Szymon Janc4e51eae2011-02-25 19:05:48 +01001858 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001859 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001860 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001861 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001862
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001863 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001864
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001865 if (!hdev_is_powered(hdev)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001866 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001867 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001868 goto failed;
1869 }
1870
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001871 err = send_pin_code_neg_reply(sk, index, hdev, cp);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001872
1873failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001874 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001875 hci_dev_put(hdev);
1876
1877 return err;
1878}
1879
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001880static int set_io_capability(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001881{
1882 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001883 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001884
1885 BT_DBG("");
1886
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001887 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001888 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY,
1889 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001890
Szymon Janc4e51eae2011-02-25 19:05:48 +01001891 hdev = hci_dev_get(index);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001892 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001893 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY,
1894 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001895
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001896 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001897
1898 hdev->io_capability = cp->io_capability;
1899
1900 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Szymon Jancb8534e02011-03-01 16:55:34 +01001901 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001902
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001903 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001904 hci_dev_put(hdev);
1905
Johan Hedbergaee9b2182012-02-18 15:07:59 +02001906 return cmd_complete(sk, index, MGMT_OP_SET_IO_CAPABILITY, 0, NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001907}
1908
Johan Hedberge9a416b2011-02-19 12:05:56 -03001909static inline struct pending_cmd *find_pairing(struct hci_conn *conn)
1910{
1911 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001912 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001913
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001914 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03001915 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
1916 continue;
1917
Johan Hedberge9a416b2011-02-19 12:05:56 -03001918 if (cmd->user_data != conn)
1919 continue;
1920
1921 return cmd;
1922 }
1923
1924 return NULL;
1925}
1926
1927static void pairing_complete(struct pending_cmd *cmd, u8 status)
1928{
1929 struct mgmt_rp_pair_device rp;
1930 struct hci_conn *conn = cmd->user_data;
1931
Johan Hedbergba4e5642011-11-11 00:07:34 +02001932 bacpy(&rp.addr.bdaddr, &conn->dst);
1933 rp.addr.type = link_to_mgmt(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001934
Johan Hedbergaee9b2182012-02-18 15:07:59 +02001935 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, status,
1936 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001937
1938 /* So we don't get further callbacks for this connection */
1939 conn->connect_cfm_cb = NULL;
1940 conn->security_cfm_cb = NULL;
1941 conn->disconn_cfm_cb = NULL;
1942
1943 hci_conn_put(conn);
1944
Johan Hedberga664b5b2011-02-19 12:06:02 -03001945 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001946}
1947
1948static void pairing_complete_cb(struct hci_conn *conn, u8 status)
1949{
1950 struct pending_cmd *cmd;
1951
1952 BT_DBG("status %u", status);
1953
Johan Hedberg56e5cb82011-11-08 20:40:16 +02001954 cmd = find_pairing(conn);
1955 if (!cmd)
1956 BT_DBG("Unable to find a pending command");
1957 else
Johan Hedberge2113262012-02-18 15:20:03 +02001958 pairing_complete(cmd, mgmt_status(status));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001959}
1960
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001961static int pair_device(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001962{
1963 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001964 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02001965 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001966 struct pending_cmd *cmd;
1967 u8 sec_level, auth_type;
1968 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001969 int err;
1970
1971 BT_DBG("");
1972
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001973 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001974 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE,
1975 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001976
Szymon Janc4e51eae2011-02-25 19:05:48 +01001977 hdev = hci_dev_get(index);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001978 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001979 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE,
1980 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001981
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001982 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001983
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001984 sec_level = BT_SECURITY_MEDIUM;
1985 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001986 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001987 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03001988 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001989
Johan Hedbergba4e5642011-11-11 00:07:34 +02001990 if (cp->addr.type == MGMT_ADDR_BREDR)
1991 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr, sec_level,
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001992 auth_type);
1993 else
Johan Hedbergba4e5642011-11-11 00:07:34 +02001994 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr, sec_level,
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001995 auth_type);
1996
Johan Hedberg1425acb2011-11-11 00:07:35 +02001997 memset(&rp, 0, sizeof(rp));
1998 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1999 rp.addr.type = cp->addr.type;
2000
Ville Tervo30e76272011-02-22 16:10:53 -03002001 if (IS_ERR(conn)) {
Johan Hedberge2113262012-02-18 15:20:03 +02002002 err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE,
2003 MGMT_STATUS_CONNECT_FAILED,
2004 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002005 goto unlock;
2006 }
2007
2008 if (conn->connect_cfm_cb) {
2009 hci_conn_put(conn);
Johan Hedberge2113262012-02-18 15:20:03 +02002010 err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE,
2011 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002012 goto unlock;
2013 }
2014
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002015 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002016 if (!cmd) {
2017 err = -ENOMEM;
2018 hci_conn_put(conn);
2019 goto unlock;
2020 }
2021
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002022 /* For LE, just connecting isn't a proof that the pairing finished */
Johan Hedbergba4e5642011-11-11 00:07:34 +02002023 if (cp->addr.type == MGMT_ADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002024 conn->connect_cfm_cb = pairing_complete_cb;
2025
Johan Hedberge9a416b2011-02-19 12:05:56 -03002026 conn->security_cfm_cb = pairing_complete_cb;
2027 conn->disconn_cfm_cb = pairing_complete_cb;
2028 conn->io_capability = cp->io_cap;
2029 cmd->user_data = conn;
2030
2031 if (conn->state == BT_CONNECTED &&
2032 hci_conn_security(conn, sec_level, auth_type))
2033 pairing_complete(cmd, 0);
2034
2035 err = 0;
2036
2037unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002038 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002039 hci_dev_put(hdev);
2040
2041 return err;
2042}
2043
Johan Hedberg28424702012-02-02 04:02:29 +02002044static int cancel_pair_device(struct sock *sk, u16 index,
2045 unsigned char *data, u16 len)
2046{
2047 struct mgmt_addr_info *addr = (void *) data;
2048 struct hci_dev *hdev;
2049 struct pending_cmd *cmd;
2050 struct hci_conn *conn;
2051 int err;
2052
2053 BT_DBG("");
2054
2055 if (len != sizeof(*addr))
2056 return cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
2057 MGMT_STATUS_INVALID_PARAMS);
2058
2059 hdev = hci_dev_get(index);
2060 if (!hdev)
2061 return cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
2062 MGMT_STATUS_INVALID_PARAMS);
2063
2064 hci_dev_lock(hdev);
2065
2066 cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
2067 if (!cmd) {
2068 err = cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
2069 MGMT_STATUS_INVALID_PARAMS);
2070 goto unlock;
2071 }
2072
2073 conn = cmd->user_data;
2074
2075 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
2076 err = cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
2077 MGMT_STATUS_INVALID_PARAMS);
2078 goto unlock;
2079 }
2080
2081 pairing_complete(cmd, MGMT_STATUS_CANCELLED);
2082
Johan Hedbergaee9b2182012-02-18 15:07:59 +02002083 err = cmd_complete(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE, 0, addr,
Johan Hedberg28424702012-02-02 04:02:29 +02002084 sizeof(*addr));
2085unlock:
2086 hci_dev_unlock(hdev);
2087 hci_dev_put(hdev);
2088
2089 return err;
2090}
2091
Brian Gix0df4c182011-11-16 13:53:13 -08002092static int user_pairing_resp(struct sock *sk, u16 index, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02002093 u8 type, u16 mgmt_op, u16 hci_op,
2094 __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03002095{
Johan Hedberga5c29682011-02-19 12:05:57 -03002096 struct pending_cmd *cmd;
2097 struct hci_dev *hdev;
Brian Gix0df4c182011-11-16 13:53:13 -08002098 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03002099 int err;
2100
Szymon Janc4e51eae2011-02-25 19:05:48 +01002101 hdev = hci_dev_get(index);
Johan Hedberga5c29682011-02-19 12:05:57 -03002102 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002103 return cmd_status(sk, index, mgmt_op,
2104 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga5c29682011-02-19 12:05:57 -03002105
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002106 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02002107
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002108 if (!hdev_is_powered(hdev)) {
Brian Gix0df4c182011-11-16 13:53:13 -08002109 err = cmd_status(sk, index, mgmt_op, MGMT_STATUS_NOT_POWERED);
2110 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002111 }
2112
Johan Hedberg272d90d2012-02-09 15:26:12 +02002113 if (type == MGMT_ADDR_BREDR)
2114 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, bdaddr);
2115 else
Brian Gix47c15e22011-11-16 13:53:14 -08002116 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, bdaddr);
Brian Gix47c15e22011-11-16 13:53:14 -08002117
Johan Hedberg272d90d2012-02-09 15:26:12 +02002118 if (!conn) {
2119 err = cmd_status(sk, index, mgmt_op,
2120 MGMT_STATUS_NOT_CONNECTED);
2121 goto done;
2122 }
2123
2124 if (type == MGMT_ADDR_LE_PUBLIC || type == MGMT_ADDR_LE_RANDOM) {
Brian Gix47c15e22011-11-16 13:53:14 -08002125 /* Continue with pairing via SMP */
Brian Gix5fe57d92011-12-21 16:12:13 -08002126 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix47c15e22011-11-16 13:53:14 -08002127
Brian Gix5fe57d92011-12-21 16:12:13 -08002128 if (!err)
2129 err = cmd_status(sk, index, mgmt_op,
2130 MGMT_STATUS_SUCCESS);
2131 else
2132 err = cmd_status(sk, index, mgmt_op,
2133 MGMT_STATUS_FAILED);
2134
Brian Gix47c15e22011-11-16 13:53:14 -08002135 goto done;
2136 }
2137
Brian Gix0df4c182011-11-16 13:53:13 -08002138 cmd = mgmt_pending_add(sk, mgmt_op, hdev, bdaddr, sizeof(*bdaddr));
Johan Hedberga5c29682011-02-19 12:05:57 -03002139 if (!cmd) {
2140 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08002141 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002142 }
2143
Brian Gix0df4c182011-11-16 13:53:13 -08002144 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08002145 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
2146 struct hci_cp_user_passkey_reply cp;
2147
2148 bacpy(&cp.bdaddr, bdaddr);
2149 cp.passkey = passkey;
2150 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
2151 } else
2152 err = hci_send_cmd(hdev, hci_op, sizeof(*bdaddr), bdaddr);
2153
Johan Hedberga664b5b2011-02-19 12:06:02 -03002154 if (err < 0)
2155 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002156
Brian Gix0df4c182011-11-16 13:53:13 -08002157done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002158 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002159 hci_dev_put(hdev);
2160
2161 return err;
2162}
2163
Brian Gix0df4c182011-11-16 13:53:13 -08002164static int user_confirm_reply(struct sock *sk, u16 index, void *data, u16 len)
2165{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002166 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002167
2168 BT_DBG("");
2169
2170 if (len != sizeof(*cp))
2171 return cmd_status(sk, index, MGMT_OP_USER_CONFIRM_REPLY,
2172 MGMT_STATUS_INVALID_PARAMS);
2173
Johan Hedberg272d90d2012-02-09 15:26:12 +02002174 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
2175 MGMT_OP_USER_CONFIRM_REPLY,
2176 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002177}
2178
2179static int user_confirm_neg_reply(struct sock *sk, u16 index, void *data,
2180 u16 len)
2181{
Johan Hedbergc9c26592011-12-15 00:47:41 +02002182 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002183
2184 BT_DBG("");
2185
2186 if (len != sizeof(*cp))
2187 return cmd_status(sk, index, MGMT_OP_USER_CONFIRM_NEG_REPLY,
2188 MGMT_STATUS_INVALID_PARAMS);
2189
Johan Hedberg272d90d2012-02-09 15:26:12 +02002190 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
2191 MGMT_OP_USER_CONFIRM_NEG_REPLY,
2192 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002193}
2194
Brian Gix604086b2011-11-23 08:28:33 -08002195static int user_passkey_reply(struct sock *sk, u16 index, void *data, u16 len)
2196{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002197 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002198
2199 BT_DBG("");
2200
2201 if (len != sizeof(*cp))
2202 return cmd_status(sk, index, MGMT_OP_USER_PASSKEY_REPLY,
2203 EINVAL);
2204
Johan Hedberg272d90d2012-02-09 15:26:12 +02002205 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
2206 MGMT_OP_USER_PASSKEY_REPLY,
2207 HCI_OP_USER_PASSKEY_REPLY,
2208 cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08002209}
2210
2211static int user_passkey_neg_reply(struct sock *sk, u16 index, void *data,
2212 u16 len)
2213{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002214 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002215
2216 BT_DBG("");
2217
2218 if (len != sizeof(*cp))
2219 return cmd_status(sk, index, MGMT_OP_USER_PASSKEY_NEG_REPLY,
2220 EINVAL);
2221
Johan Hedberg272d90d2012-02-09 15:26:12 +02002222 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
2223 MGMT_OP_USER_PASSKEY_NEG_REPLY,
2224 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08002225}
2226
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002227static int set_local_name(struct sock *sk, u16 index, void *data,
Johan Hedbergb312b1612011-03-16 14:29:37 +02002228 u16 len)
2229{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002230 struct mgmt_cp_set_local_name *mgmt_cp = data;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002231 struct hci_cp_write_local_name hci_cp;
2232 struct hci_dev *hdev;
2233 struct pending_cmd *cmd;
2234 int err;
2235
2236 BT_DBG("");
2237
2238 if (len != sizeof(*mgmt_cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02002239 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME,
2240 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002241
2242 hdev = hci_dev_get(index);
2243 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002244 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME,
2245 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002246
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002247 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002248
Johan Hedbergb5235a62012-02-21 14:32:24 +02002249 if (!hdev_is_powered(hdev)) {
2250 err = cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME,
2251 MGMT_STATUS_NOT_POWERED);
2252 goto failed;
2253 }
2254
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002255 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data,
2256 len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002257 if (!cmd) {
2258 err = -ENOMEM;
2259 goto failed;
2260 }
2261
2262 memcpy(hci_cp.name, mgmt_cp->name, sizeof(hci_cp.name));
2263 err = hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(hci_cp),
2264 &hci_cp);
2265 if (err < 0)
2266 mgmt_pending_remove(cmd);
2267
2268failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002269 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002270 hci_dev_put(hdev);
2271
2272 return err;
2273}
2274
Szymon Jancc35938b2011-03-22 13:12:21 +01002275static int read_local_oob_data(struct sock *sk, u16 index)
2276{
2277 struct hci_dev *hdev;
2278 struct pending_cmd *cmd;
2279 int err;
2280
2281 BT_DBG("hci%u", index);
2282
2283 hdev = hci_dev_get(index);
2284 if (!hdev)
2285 return cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002286 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancc35938b2011-03-22 13:12:21 +01002287
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002288 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002289
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002290 if (!hdev_is_powered(hdev)) {
Szymon Jancc35938b2011-03-22 13:12:21 +01002291 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002292 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002293 goto unlock;
2294 }
2295
2296 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
2297 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002298 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002299 goto unlock;
2300 }
2301
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002302 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02002303 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2304 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01002305 goto unlock;
2306 }
2307
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002308 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01002309 if (!cmd) {
2310 err = -ENOMEM;
2311 goto unlock;
2312 }
2313
2314 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
2315 if (err < 0)
2316 mgmt_pending_remove(cmd);
2317
2318unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002319 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002320 hci_dev_put(hdev);
2321
2322 return err;
2323}
2324
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002325static int add_remote_oob_data(struct sock *sk, u16 index, void *data,
2326 u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002327{
2328 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002329 struct mgmt_cp_add_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002330 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002331 int err;
2332
2333 BT_DBG("hci%u ", index);
2334
2335 if (len != sizeof(*cp))
2336 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002337 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01002338
2339 hdev = hci_dev_get(index);
2340 if (!hdev)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002341 return cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
2342 MGMT_STATUS_INVALID_PARAMS,
2343 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002344
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002345 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002346
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002347 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, cp->hash,
Szymon Janc2763eda2011-03-22 13:12:22 +01002348 cp->randomizer);
2349 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002350 status = MGMT_STATUS_FAILED;
Szymon Janc2763eda2011-03-22 13:12:22 +01002351 else
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002352 status = 0;
2353
2354 err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, status,
2355 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002356
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002357 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002358 hci_dev_put(hdev);
2359
2360 return err;
2361}
2362
2363static int remove_remote_oob_data(struct sock *sk, u16 index,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002364 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002365{
2366 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002367 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002368 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002369 int err;
2370
2371 BT_DBG("hci%u ", index);
2372
2373 if (len != sizeof(*cp))
2374 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002375 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01002376
2377 hdev = hci_dev_get(index);
2378 if (!hdev)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002379 return cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2380 MGMT_STATUS_INVALID_PARAMS,
2381 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002382
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002383 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002384
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002385 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr);
Szymon Janc2763eda2011-03-22 13:12:22 +01002386 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002387 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01002388 else
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002389 status = 0;
2390
2391 err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA, status,
2392 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002393
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002394 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002395 hci_dev_put(hdev);
2396
2397 return err;
2398}
2399
Andre Guedes5e0452c2012-02-17 20:39:38 -03002400static int discovery(struct hci_dev *hdev)
2401{
2402 int err;
2403
2404 if (lmp_host_le_capable(hdev)) {
2405 if (lmp_bredr_capable(hdev)) {
2406 err = hci_le_scan(hdev, LE_SCAN_TYPE,
2407 LE_SCAN_INT, LE_SCAN_WIN,
2408 LE_SCAN_TIMEOUT_BREDR_LE);
2409 } else {
2410 hdev->discovery.type = DISCOV_TYPE_LE;
2411 err = hci_le_scan(hdev, LE_SCAN_TYPE,
2412 LE_SCAN_INT, LE_SCAN_WIN,
2413 LE_SCAN_TIMEOUT_LE_ONLY);
2414 }
2415 } else {
2416 hdev->discovery.type = DISCOV_TYPE_BREDR;
2417 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
2418 }
2419
2420 return err;
2421}
2422
2423int mgmt_interleaved_discovery(struct hci_dev *hdev)
2424{
2425 int err;
2426
2427 BT_DBG("%s", hdev->name);
2428
2429 hci_dev_lock(hdev);
2430
2431 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR_LE);
2432 if (err < 0)
2433 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2434
2435 hci_dev_unlock(hdev);
2436
2437 return err;
2438}
2439
Johan Hedberg450dfda2011-11-12 11:58:22 +02002440static int start_discovery(struct sock *sk, u16 index,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002441 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002442{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002443 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002444 struct pending_cmd *cmd;
2445 struct hci_dev *hdev;
2446 int err;
2447
2448 BT_DBG("hci%u", index);
2449
Johan Hedberg450dfda2011-11-12 11:58:22 +02002450 if (len != sizeof(*cp))
2451 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2452 MGMT_STATUS_INVALID_PARAMS);
2453
Johan Hedberg14a53662011-04-27 10:29:56 -04002454 hdev = hci_dev_get(index);
2455 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002456 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2457 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg14a53662011-04-27 10:29:56 -04002458
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002459 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002460
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002461 if (!hdev_is_powered(hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02002462 err = cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2463 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02002464 goto failed;
2465 }
2466
Johan Hedbergff9ef572012-01-04 14:23:45 +02002467 if (hdev->discovery.state != DISCOVERY_STOPPED) {
2468 err = cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2469 MGMT_STATUS_BUSY);
2470 goto failed;
2471 }
2472
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002473 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002474 if (!cmd) {
2475 err = -ENOMEM;
2476 goto failed;
2477 }
2478
Andre Guedes4aab14e2012-02-17 20:39:36 -03002479 hdev->discovery.type = cp->type;
2480
2481 switch (hdev->discovery.type) {
Andre Guedesf39799f2012-02-17 20:39:35 -03002482 case DISCOV_TYPE_BREDR:
Andre Guedes3fd24152012-02-03 17:48:01 -03002483 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
Andre Guedesf39799f2012-02-17 20:39:35 -03002484 break;
2485
2486 case DISCOV_TYPE_LE:
Andre Guedes3fd24152012-02-03 17:48:01 -03002487 err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT,
2488 LE_SCAN_WIN, LE_SCAN_TIMEOUT_LE_ONLY);
Andre Guedesf39799f2012-02-17 20:39:35 -03002489 break;
2490
Andre Guedes5e0452c2012-02-17 20:39:38 -03002491 case DISCOV_TYPE_INTERLEAVED:
2492 err = discovery(hdev);
2493 break;
2494
Andre Guedesf39799f2012-02-17 20:39:35 -03002495 default:
Andre Guedes3fd24152012-02-03 17:48:01 -03002496 err = -EINVAL;
Andre Guedesf39799f2012-02-17 20:39:35 -03002497 }
Andre Guedes3fd24152012-02-03 17:48:01 -03002498
Johan Hedberg14a53662011-04-27 10:29:56 -04002499 if (err < 0)
2500 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002501 else
2502 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002503
2504failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002505 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002506 hci_dev_put(hdev);
2507
2508 return err;
2509}
2510
Johan Hedbergd9306502012-02-20 23:25:18 +02002511static int stop_discovery(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002512{
Johan Hedbergd9306502012-02-20 23:25:18 +02002513 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002514 struct hci_dev *hdev;
2515 struct pending_cmd *cmd;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002516 struct hci_cp_remote_name_req_cancel cp;
2517 struct inquiry_entry *e;
Johan Hedberg14a53662011-04-27 10:29:56 -04002518 int err;
2519
2520 BT_DBG("hci%u", index);
2521
Johan Hedbergd9306502012-02-20 23:25:18 +02002522 if (len != sizeof(*mgmt_cp))
2523 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY,
2524 MGMT_STATUS_INVALID_PARAMS);
2525
Johan Hedberg14a53662011-04-27 10:29:56 -04002526 hdev = hci_dev_get(index);
2527 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002528 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY,
2529 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg14a53662011-04-27 10:29:56 -04002530
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002531 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002532
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002533 if (!hci_discovery_active(hdev)) {
Johan Hedbergd9306502012-02-20 23:25:18 +02002534 err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY,
2535 MGMT_STATUS_REJECTED,
2536 &mgmt_cp->type, sizeof(mgmt_cp->type));
2537 goto unlock;
2538 }
2539
2540 if (hdev->discovery.type != mgmt_cp->type) {
2541 err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY,
2542 MGMT_STATUS_INVALID_PARAMS,
2543 &mgmt_cp->type, sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002544 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02002545 }
2546
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002547 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002548 if (!cmd) {
2549 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002550 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04002551 }
2552
Andre Guedes343f9352012-02-17 20:39:37 -03002553 if (hdev->discovery.state == DISCOVERY_FINDING) {
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002554 err = hci_cancel_inquiry(hdev);
2555 if (err < 0)
2556 mgmt_pending_remove(cmd);
2557 else
2558 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
2559 goto unlock;
2560 }
2561
2562 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY, NAME_PENDING);
2563 if (!e) {
2564 mgmt_pending_remove(cmd);
Johan Hedbergaee9b2182012-02-18 15:07:59 +02002565 err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY, 0,
Johan Hedbergd9306502012-02-20 23:25:18 +02002566 &mgmt_cp->type, sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002567 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2568 goto unlock;
2569 }
2570
2571 bacpy(&cp.bdaddr, &e->data.bdaddr);
2572 err = hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ_CANCEL,
2573 sizeof(cp), &cp);
Johan Hedberg14a53662011-04-27 10:29:56 -04002574 if (err < 0)
2575 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002576 else
2577 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002578
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002579unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002580 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002581 hci_dev_put(hdev);
2582
2583 return err;
2584}
2585
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002586static int confirm_name(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02002587{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002588 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002589 struct inquiry_entry *e;
2590 struct hci_dev *hdev;
2591 int err;
2592
2593 BT_DBG("hci%u", index);
2594
2595 if (len != sizeof(*cp))
2596 return cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2597 MGMT_STATUS_INVALID_PARAMS);
2598
2599 hdev = hci_dev_get(index);
2600 if (!hdev)
2601 return cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2602 MGMT_STATUS_INVALID_PARAMS);
2603
2604 hci_dev_lock(hdev);
2605
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002606 if (!hci_discovery_active(hdev)) {
2607 err = cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2608 MGMT_STATUS_FAILED);
2609 goto failed;
2610 }
2611
Johan Hedberga198e7b2012-02-17 14:27:06 +02002612 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002613 if (!e) {
Marcel Holtmanne5f0e152012-02-22 11:59:01 +01002614 err = cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
Johan Hedberg561aafb2012-01-04 13:31:59 +02002615 MGMT_STATUS_INVALID_PARAMS);
2616 goto failed;
2617 }
2618
2619 if (cp->name_known) {
2620 e->name_state = NAME_KNOWN;
2621 list_del(&e->list);
2622 } else {
2623 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e202012-01-09 00:53:02 +02002624 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002625 }
2626
2627 err = 0;
2628
2629failed:
2630 hci_dev_unlock(hdev);
2631
2632 return err;
2633}
2634
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002635static int block_device(struct sock *sk, u16 index, void *data, u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002636{
2637 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002638 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002639 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03002640 int err;
2641
2642 BT_DBG("hci%u", index);
2643
Antti Julku7fbec222011-06-15 12:01:15 +03002644 if (len != sizeof(*cp))
2645 return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002646 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002647
2648 hdev = hci_dev_get(index);
2649 if (!hdev)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002650 return cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE,
2651 MGMT_STATUS_INVALID_PARAMS,
2652 &cp->addr, sizeof(cp->addr));
Antti Julku7fbec222011-06-15 12:01:15 +03002653
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002654 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002655
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002656 err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002657 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002658 status = MGMT_STATUS_FAILED;
Antti Julku7fbec222011-06-15 12:01:15 +03002659 else
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002660 status = 0;
2661
2662 err = cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE, status,
2663 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03002664
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002665 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002666 hci_dev_put(hdev);
2667
2668 return err;
2669}
2670
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002671static int unblock_device(struct sock *sk, u16 index, void *data, u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002672{
2673 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002674 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002675 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03002676 int err;
2677
2678 BT_DBG("hci%u", index);
2679
Antti Julku7fbec222011-06-15 12:01:15 +03002680 if (len != sizeof(*cp))
2681 return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002682 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002683
2684 hdev = hci_dev_get(index);
2685 if (!hdev)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002686 return cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE,
2687 MGMT_STATUS_INVALID_PARAMS,
2688 &cp->addr, sizeof(cp->addr));
Antti Julku7fbec222011-06-15 12:01:15 +03002689
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002690 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002691
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002692 err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002693 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002694 status = MGMT_STATUS_INVALID_PARAMS;
Antti Julku7fbec222011-06-15 12:01:15 +03002695 else
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002696 status = 0;
2697
2698 err = cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE, status,
2699 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03002700
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002701 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002702 hci_dev_put(hdev);
2703
2704 return err;
2705}
2706
Antti Julkuf6422ec2011-06-22 13:11:56 +03002707static int set_fast_connectable(struct sock *sk, u16 index,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002708 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03002709{
2710 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002711 struct mgmt_mode *cp = data;
Antti Julkuf6422ec2011-06-22 13:11:56 +03002712 struct hci_cp_write_page_scan_activity acp;
2713 u8 type;
2714 int err;
2715
2716 BT_DBG("hci%u", index);
2717
2718 if (len != sizeof(*cp))
2719 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002720 MGMT_STATUS_INVALID_PARAMS);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002721
2722 hdev = hci_dev_get(index);
2723 if (!hdev)
2724 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002725 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg5400c042012-02-21 16:40:33 +02002726 if (!hdev_is_powered(hdev))
2727 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
2728 MGMT_STATUS_NOT_POWERED);
2729
2730 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
2731 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
2732 MGMT_STATUS_REJECTED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002733
2734 hci_dev_lock(hdev);
2735
Johan Hedbergf7c68692011-12-15 00:47:36 +02002736 if (cp->val) {
Antti Julkuf6422ec2011-06-22 13:11:56 +03002737 type = PAGE_SCAN_TYPE_INTERLACED;
2738 acp.interval = 0x0024; /* 22.5 msec page scan interval */
2739 } else {
2740 type = PAGE_SCAN_TYPE_STANDARD; /* default */
2741 acp.interval = 0x0800; /* default 1.28 sec page scan */
2742 }
2743
2744 acp.window = 0x0012; /* default 11.25 msec page scan window */
2745
2746 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
2747 sizeof(acp), &acp);
2748 if (err < 0) {
2749 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002750 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002751 goto done;
2752 }
2753
2754 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
2755 if (err < 0) {
2756 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002757 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002758 goto done;
2759 }
2760
Johan Hedbergaee9b2182012-02-18 15:07:59 +02002761 err = cmd_complete(sk, index, MGMT_OP_SET_FAST_CONNECTABLE, 0,
2762 NULL, 0);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002763done:
2764 hci_dev_unlock(hdev);
2765 hci_dev_put(hdev);
2766
2767 return err;
2768}
2769
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002770static int load_long_term_keys(struct sock *sk, u16 index,
2771 void *cp_data, u16 len)
2772{
2773 struct hci_dev *hdev;
2774 struct mgmt_cp_load_long_term_keys *cp = cp_data;
2775 u16 key_count, expected_len;
2776 int i;
2777
2778 if (len < sizeof(*cp))
2779 return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS,
2780 EINVAL);
2781
2782 key_count = get_unaligned_le16(&cp->key_count);
2783
2784 expected_len = sizeof(*cp) + key_count *
2785 sizeof(struct mgmt_ltk_info);
2786 if (expected_len != len) {
2787 BT_ERR("load_keys: expected %u bytes, got %u bytes",
2788 len, expected_len);
2789 return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS,
2790 EINVAL);
2791 }
2792
2793 hdev = hci_dev_get(index);
2794 if (!hdev)
2795 return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS,
2796 ENODEV);
2797
2798 BT_DBG("hci%u key_count %u", index, key_count);
2799
2800 hci_dev_lock(hdev);
2801
2802 hci_smp_ltks_clear(hdev);
2803
2804 for (i = 0; i < key_count; i++) {
2805 struct mgmt_ltk_info *key = &cp->keys[i];
2806 u8 type;
2807
2808 if (key->master)
2809 type = HCI_SMP_LTK;
2810 else
2811 type = HCI_SMP_LTK_SLAVE;
2812
2813 hci_add_ltk(hdev, &key->addr.bdaddr, key->addr.type,
2814 type, 0, key->authenticated, key->val,
2815 key->enc_size, key->ediv, key->rand);
2816 }
2817
2818 hci_dev_unlock(hdev);
2819 hci_dev_put(hdev);
2820
2821 return 0;
2822}
2823
Johan Hedberg03811012010-12-08 00:21:06 +02002824int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
2825{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002826 void *buf;
2827 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02002828 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002829 u16 opcode, index, len;
Johan Hedberg03811012010-12-08 00:21:06 +02002830 int err;
2831
2832 BT_DBG("got %zu bytes", msglen);
2833
2834 if (msglen < sizeof(*hdr))
2835 return -EINVAL;
2836
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03002837 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02002838 if (!buf)
2839 return -ENOMEM;
2840
2841 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
2842 err = -EFAULT;
2843 goto done;
2844 }
2845
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002846 hdr = buf;
Johan Hedberg03811012010-12-08 00:21:06 +02002847 opcode = get_unaligned_le16(&hdr->opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002848 index = get_unaligned_le16(&hdr->index);
Johan Hedberg03811012010-12-08 00:21:06 +02002849 len = get_unaligned_le16(&hdr->len);
2850
2851 if (len != msglen - sizeof(*hdr)) {
2852 err = -EINVAL;
2853 goto done;
2854 }
2855
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002856 cp = buf + sizeof(*hdr);
2857
Johan Hedberg03811012010-12-08 00:21:06 +02002858 switch (opcode) {
Johan Hedberg02d98122010-12-13 21:07:04 +02002859 case MGMT_OP_READ_VERSION:
2860 err = read_version(sk);
2861 break;
Johan Hedberge70bb2e2012-02-13 16:59:33 +02002862 case MGMT_OP_READ_COMMANDS:
2863 err = read_commands(sk);
2864 break;
Johan Hedbergfaba42e2010-12-13 21:07:05 +02002865 case MGMT_OP_READ_INDEX_LIST:
2866 err = read_index_list(sk);
2867 break;
Johan Hedbergf7b64e62010-12-13 21:07:06 +02002868 case MGMT_OP_READ_INFO:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002869 err = read_controller_info(sk, index);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02002870 break;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002871 case MGMT_OP_SET_POWERED:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002872 err = set_powered(sk, index, cp, len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002873 break;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002874 case MGMT_OP_SET_DISCOVERABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002875 err = set_discoverable(sk, index, cp, len);
Johan Hedberg73f22f62010-12-29 16:00:25 +02002876 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002877 case MGMT_OP_SET_CONNECTABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002878 err = set_connectable(sk, index, cp, len);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002879 break;
Johan Hedbergf7c68692011-12-15 00:47:36 +02002880 case MGMT_OP_SET_FAST_CONNECTABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002881 err = set_fast_connectable(sk, index, cp, len);
Johan Hedbergf7c68692011-12-15 00:47:36 +02002882 break;
Johan Hedbergc542a062011-01-26 13:11:03 +02002883 case MGMT_OP_SET_PAIRABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002884 err = set_pairable(sk, index, cp, len);
Johan Hedbergc542a062011-01-26 13:11:03 +02002885 break;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02002886 case MGMT_OP_SET_LINK_SECURITY:
2887 err = set_link_security(sk, index, cp, len);
2888 break;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02002889 case MGMT_OP_SET_SSP:
2890 err = set_ssp(sk, index, cp, len);
2891 break;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02002892 case MGMT_OP_SET_HS:
2893 err = set_hs(sk, index, cp, len);
2894 break;
Johan Hedberg06199cf2012-02-22 16:37:11 +02002895 case MGMT_OP_SET_LE:
2896 err = set_le(sk, index, cp, len);
2897 break;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002898 case MGMT_OP_ADD_UUID:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002899 err = add_uuid(sk, index, cp, len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002900 break;
2901 case MGMT_OP_REMOVE_UUID:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002902 err = remove_uuid(sk, index, cp, len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002903 break;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002904 case MGMT_OP_SET_DEV_CLASS:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002905 err = set_dev_class(sk, index, cp, len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002906 break;
Johan Hedberg86742e12011-11-07 23:13:38 +02002907 case MGMT_OP_LOAD_LINK_KEYS:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002908 err = load_link_keys(sk, index, cp, len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002909 break;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002910 case MGMT_OP_DISCONNECT:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002911 err = disconnect(sk, index, cp, len);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002912 break;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002913 case MGMT_OP_GET_CONNECTIONS:
Szymon Janc8ce62842011-03-01 16:55:32 +01002914 err = get_connections(sk, index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002915 break;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002916 case MGMT_OP_PIN_CODE_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002917 err = pin_code_reply(sk, index, cp, len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002918 break;
2919 case MGMT_OP_PIN_CODE_NEG_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002920 err = pin_code_neg_reply(sk, index, cp, len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002921 break;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002922 case MGMT_OP_SET_IO_CAPABILITY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002923 err = set_io_capability(sk, index, cp, len);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002924 break;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002925 case MGMT_OP_PAIR_DEVICE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002926 err = pair_device(sk, index, cp, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002927 break;
Johan Hedberg28424702012-02-02 04:02:29 +02002928 case MGMT_OP_CANCEL_PAIR_DEVICE:
2929 err = cancel_pair_device(sk, index, buf + sizeof(*hdr), len);
2930 break;
Johan Hedberg124f6e32012-02-09 13:50:12 +02002931 case MGMT_OP_UNPAIR_DEVICE:
2932 err = unpair_device(sk, index, cp, len);
2933 break;
Johan Hedberga5c29682011-02-19 12:05:57 -03002934 case MGMT_OP_USER_CONFIRM_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002935 err = user_confirm_reply(sk, index, cp, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03002936 break;
2937 case MGMT_OP_USER_CONFIRM_NEG_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002938 err = user_confirm_neg_reply(sk, index, cp, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03002939 break;
Brian Gix604086b2011-11-23 08:28:33 -08002940 case MGMT_OP_USER_PASSKEY_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002941 err = user_passkey_reply(sk, index, cp, len);
Brian Gix604086b2011-11-23 08:28:33 -08002942 break;
2943 case MGMT_OP_USER_PASSKEY_NEG_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002944 err = user_passkey_neg_reply(sk, index, cp, len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002945 break;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002946 case MGMT_OP_SET_LOCAL_NAME:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002947 err = set_local_name(sk, index, cp, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002948 break;
Szymon Jancc35938b2011-03-22 13:12:21 +01002949 case MGMT_OP_READ_LOCAL_OOB_DATA:
2950 err = read_local_oob_data(sk, index);
2951 break;
Szymon Janc2763eda2011-03-22 13:12:22 +01002952 case MGMT_OP_ADD_REMOTE_OOB_DATA:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002953 err = add_remote_oob_data(sk, index, cp, len);
Szymon Janc2763eda2011-03-22 13:12:22 +01002954 break;
2955 case MGMT_OP_REMOVE_REMOTE_OOB_DATA:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002956 err = remove_remote_oob_data(sk, index, cp, len);
Szymon Janc2763eda2011-03-22 13:12:22 +01002957 break;
Johan Hedberg14a53662011-04-27 10:29:56 -04002958 case MGMT_OP_START_DISCOVERY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002959 err = start_discovery(sk, index, cp, len);
Johan Hedberg14a53662011-04-27 10:29:56 -04002960 break;
2961 case MGMT_OP_STOP_DISCOVERY:
Johan Hedbergd9306502012-02-20 23:25:18 +02002962 err = stop_discovery(sk, index, cp, len);
Johan Hedberg14a53662011-04-27 10:29:56 -04002963 break;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002964 case MGMT_OP_CONFIRM_NAME:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002965 err = confirm_name(sk, index, cp, len);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002966 break;
Antti Julku7fbec222011-06-15 12:01:15 +03002967 case MGMT_OP_BLOCK_DEVICE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002968 err = block_device(sk, index, cp, len);
Antti Julku7fbec222011-06-15 12:01:15 +03002969 break;
2970 case MGMT_OP_UNBLOCK_DEVICE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002971 err = unblock_device(sk, index, cp, len);
Antti Julku7fbec222011-06-15 12:01:15 +03002972 break;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002973 case MGMT_OP_LOAD_LONG_TERM_KEYS:
2974 err = load_long_term_keys(sk, index, cp, len);
2975 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002976 default:
Johan Hedberg72a734e2010-12-30 00:38:22 +02002977 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02002978 err = cmd_status(sk, index, opcode,
2979 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002980 break;
2981 }
Johan Hedberg72a734e2010-12-30 00:38:22 +02002982
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002983 if (err < 0)
Johan Hedberg72a734e2010-12-30 00:38:22 +02002984 goto done;
2985
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002986 err = msglen;
2987
2988done:
2989 kfree(buf);
2990 return err;
2991}
2992
Johan Hedbergb24752f2011-11-03 14:40:33 +02002993static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
2994{
2995 u8 *status = data;
2996
2997 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
2998 mgmt_pending_remove(cmd);
2999}
3000
Johan Hedberg744cf192011-11-08 20:40:14 +02003001int mgmt_index_added(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +02003002{
Johan Hedberg744cf192011-11-08 20:40:14 +02003003 return mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02003004}
3005
Johan Hedberg744cf192011-11-08 20:40:14 +02003006int mgmt_index_removed(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +02003007{
Johan Hedbergb24752f2011-11-03 14:40:33 +02003008 u8 status = ENODEV;
3009
Johan Hedberg744cf192011-11-08 20:40:14 +02003010 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02003011
Johan Hedberg744cf192011-11-08 20:40:14 +02003012 return mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02003013}
3014
3015struct cmd_lookup {
Johan Hedberg03811012010-12-08 00:21:06 +02003016 struct sock *sk;
Johan Hedberg69ab39e2011-12-15 00:47:35 +02003017 struct hci_dev *hdev;
Johan Hedberg03811012010-12-08 00:21:06 +02003018};
3019
Johan Hedberg69ab39e2011-12-15 00:47:35 +02003020static void settings_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberg03811012010-12-08 00:21:06 +02003021{
Johan Hedberg03811012010-12-08 00:21:06 +02003022 struct cmd_lookup *match = data;
3023
Johan Hedberg69ab39e2011-12-15 00:47:35 +02003024 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02003025
3026 list_del(&cmd->list);
3027
3028 if (match->sk == NULL) {
3029 match->sk = cmd->sk;
3030 sock_hold(match->sk);
3031 }
3032
3033 mgmt_pending_free(cmd);
3034}
3035
Johan Hedberg744cf192011-11-08 20:40:14 +02003036int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg03811012010-12-08 00:21:06 +02003037{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02003038 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003039 int err;
Johan Hedberg03811012010-12-08 00:21:06 +02003040
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003041 if (!test_bit(HCI_MGMT, &hdev->dev_flags))
3042 return 0;
3043
Johan Hedberg69ab39e2011-12-15 00:47:35 +02003044 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
Johan Hedberg03811012010-12-08 00:21:06 +02003045
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003046 if (powered) {
3047 u8 scan = 0;
3048
3049 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3050 scan |= SCAN_PAGE;
3051 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3052 scan |= SCAN_INQUIRY;
3053
3054 if (scan)
3055 hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
3056 } else {
Johan Hedbergb24752f2011-11-03 14:40:33 +02003057 u8 status = ENETDOWN;
Johan Hedberg744cf192011-11-08 20:40:14 +02003058 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02003059 }
3060
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003061 err = new_settings(hdev, match.sk);
Johan Hedberg03811012010-12-08 00:21:06 +02003062
3063 if (match.sk)
3064 sock_put(match.sk);
3065
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003066 return err;
Johan Hedberg03811012010-12-08 00:21:06 +02003067}
3068
Johan Hedberg744cf192011-11-08 20:40:14 +02003069int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg03811012010-12-08 00:21:06 +02003070{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02003071 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003072 bool changed = false;
3073 int err = 0;
Johan Hedberg03811012010-12-08 00:21:06 +02003074
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003075 if (discoverable) {
3076 if (!test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3077 changed = true;
3078 } else {
3079 if (test_and_clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3080 changed = true;
3081 }
Johan Hedberg03811012010-12-08 00:21:06 +02003082
Johan Hedberged9b5f22012-02-21 20:47:06 +02003083 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp,
3084 &match);
3085
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003086 if (changed)
3087 err = new_settings(hdev, match.sk);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003088
Johan Hedberg03811012010-12-08 00:21:06 +02003089 if (match.sk)
3090 sock_put(match.sk);
3091
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003092 return err;
Johan Hedberg03811012010-12-08 00:21:06 +02003093}
3094
Johan Hedberg744cf192011-11-08 20:40:14 +02003095int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg03811012010-12-08 00:21:06 +02003096{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02003097 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003098 bool changed = false;
3099 int err = 0;
Johan Hedberg03811012010-12-08 00:21:06 +02003100
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003101 if (connectable) {
3102 if (!test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3103 changed = true;
3104 } else {
3105 if (test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3106 changed = true;
3107 }
Johan Hedberg03811012010-12-08 00:21:06 +02003108
Johan Hedberged9b5f22012-02-21 20:47:06 +02003109 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev, settings_rsp,
3110 &match);
3111
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003112 if (changed)
3113 err = new_settings(hdev, match.sk);
Johan Hedberg03811012010-12-08 00:21:06 +02003114
3115 if (match.sk)
3116 sock_put(match.sk);
3117
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003118 return err;
Johan Hedberg03811012010-12-08 00:21:06 +02003119}
3120
Johan Hedberg744cf192011-11-08 20:40:14 +02003121int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003122{
Johan Hedbergca69b792011-11-11 18:10:00 +02003123 u8 mgmt_err = mgmt_status(status);
3124
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003125 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02003126 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Johan Hedbergca69b792011-11-11 18:10:00 +02003127 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003128
3129 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02003130 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Johan Hedbergca69b792011-11-11 18:10:00 +02003131 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003132
3133 return 0;
3134}
3135
Johan Hedberg744cf192011-11-08 20:40:14 +02003136int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
3137 u8 persistent)
Johan Hedberg03811012010-12-08 00:21:06 +02003138{
Johan Hedberg86742e12011-11-07 23:13:38 +02003139 struct mgmt_ev_new_link_key ev;
Johan Hedberg03811012010-12-08 00:21:06 +02003140
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003141 memset(&ev, 0, sizeof(ev));
Johan Hedberg03811012010-12-08 00:21:06 +02003142
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003143 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02003144 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
3145 ev.key.addr.type = MGMT_ADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003146 ev.key.type = key->type;
3147 memcpy(ev.key.val, key->val, 16);
3148 ev.key.pin_len = key->pin_len;
Johan Hedberg03811012010-12-08 00:21:06 +02003149
Johan Hedberg744cf192011-11-08 20:40:14 +02003150 return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02003151}
Johan Hedbergf7520542011-01-20 12:34:39 +02003152
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003153int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
3154{
3155 struct mgmt_ev_new_long_term_key ev;
3156
3157 memset(&ev, 0, sizeof(ev));
3158
3159 ev.store_hint = persistent;
3160 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
3161 ev.key.addr.type = key->bdaddr_type;
3162 ev.key.authenticated = key->authenticated;
3163 ev.key.enc_size = key->enc_size;
3164 ev.key.ediv = key->ediv;
3165
3166 if (key->type == HCI_SMP_LTK)
3167 ev.key.master = 1;
3168
3169 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
3170 memcpy(ev.key.val, key->val, sizeof(key->val));
3171
3172 return mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev,
3173 &ev, sizeof(ev), NULL);
3174}
3175
Johan Hedbergafc747a2012-01-15 18:11:07 +02003176int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Johan Hedbergb644ba32012-01-17 21:48:47 +02003177 u8 addr_type, u8 *name, u8 name_len,
3178 u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02003179{
Johan Hedbergb644ba32012-01-17 21:48:47 +02003180 char buf[512];
3181 struct mgmt_ev_device_connected *ev = (void *) buf;
3182 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02003183
Johan Hedbergb644ba32012-01-17 21:48:47 +02003184 bacpy(&ev->addr.bdaddr, bdaddr);
3185 ev->addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02003186
Johan Hedbergb644ba32012-01-17 21:48:47 +02003187 if (name_len > 0)
3188 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
3189 name, name_len);
3190
3191 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
3192 eir_len = eir_append_data(&ev->eir[eir_len], eir_len,
3193 EIR_CLASS_OF_DEV, dev_class, 3);
3194
3195 put_unaligned_le16(eir_len, &ev->eir_len);
3196
3197 return mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
3198 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02003199}
3200
Johan Hedberg8962ee72011-01-20 12:40:27 +02003201static void disconnect_rsp(struct pending_cmd *cmd, void *data)
3202{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01003203 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003204 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02003205 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003206
Johan Hedberg88c3df12012-02-09 14:27:38 +02003207 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3208 rp.addr.type = cp->addr.type;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003209
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003210 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, 0, &rp,
3211 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003212
3213 *sk = cmd->sk;
3214 sock_hold(*sk);
3215
Johan Hedberga664b5b2011-02-19 12:06:02 -03003216 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003217}
3218
Johan Hedberg124f6e32012-02-09 13:50:12 +02003219static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02003220{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003221 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02003222 struct mgmt_cp_unpair_device *cp = cmd->param;
3223 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02003224
3225 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02003226 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3227 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02003228
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003229 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
3230
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003231 cmd_complete(cmd->sk, cmd->index, cmd->opcode, 0, &rp, sizeof(rp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02003232
3233 mgmt_pending_remove(cmd);
3234}
3235
Johan Hedbergafc747a2012-01-15 18:11:07 +02003236int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
3237 u8 link_type, u8 addr_type)
Johan Hedbergf7520542011-01-20 12:34:39 +02003238{
Johan Hedberg4c659c32011-11-07 23:13:39 +02003239 struct mgmt_addr_info ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003240 struct sock *sk = NULL;
3241 int err;
3242
Johan Hedberg744cf192011-11-08 20:40:14 +02003243 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02003244
Johan Hedbergf7520542011-01-20 12:34:39 +02003245 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02003246 ev.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02003247
Johan Hedbergafc747a2012-01-15 18:11:07 +02003248 err = mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev),
3249 sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003250
3251 if (sk)
3252 sock_put(sk);
3253
Johan Hedberg124f6e32012-02-09 13:50:12 +02003254 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003255 hdev);
Johan Hedberga8a1d192011-11-10 15:54:38 +02003256
Johan Hedberg8962ee72011-01-20 12:40:27 +02003257 return err;
3258}
3259
Johan Hedberg88c3df12012-02-09 14:27:38 +02003260int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
3261 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02003262{
Johan Hedberg88c3df12012-02-09 14:27:38 +02003263 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003264 struct pending_cmd *cmd;
3265 int err;
3266
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003267 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003268 if (!cmd)
3269 return -ENOENT;
3270
Johan Hedberg88c3df12012-02-09 14:27:38 +02003271 bacpy(&rp.addr.bdaddr, bdaddr);
3272 rp.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02003273
Johan Hedberg88c3df12012-02-09 14:27:38 +02003274 err = cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003275 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003276
Johan Hedberga664b5b2011-02-19 12:06:02 -03003277 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003278
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003279 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
3280 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003281 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02003282}
Johan Hedberg17d5c042011-01-22 06:09:08 +02003283
Johan Hedberg48264f02011-11-09 13:58:58 +02003284int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
3285 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02003286{
3287 struct mgmt_ev_connect_failed ev;
3288
Johan Hedberg4c659c32011-11-07 23:13:39 +02003289 bacpy(&ev.addr.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02003290 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003291 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003292
Johan Hedberg744cf192011-11-08 20:40:14 +02003293 return mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003294}
Johan Hedberg980e1a52011-01-22 06:10:07 +02003295
Johan Hedberg744cf192011-11-08 20:40:14 +02003296int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003297{
3298 struct mgmt_ev_pin_code_request ev;
3299
Johan Hedbergd8457692012-02-17 14:24:57 +02003300 bacpy(&ev.addr.bdaddr, bdaddr);
3301 ev.addr.type = MGMT_ADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02003302 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003303
Johan Hedberg744cf192011-11-08 20:40:14 +02003304 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01003305 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003306}
3307
Johan Hedberg744cf192011-11-08 20:40:14 +02003308int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3309 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003310{
3311 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003312 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003313 int err;
3314
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003315 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003316 if (!cmd)
3317 return -ENOENT;
3318
Johan Hedbergd8457692012-02-17 14:24:57 +02003319 bacpy(&rp.addr.bdaddr, bdaddr);
3320 rp.addr.type = MGMT_ADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003321
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003322 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
3323 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003324
Johan Hedberga664b5b2011-02-19 12:06:02 -03003325 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003326
3327 return err;
3328}
3329
Johan Hedberg744cf192011-11-08 20:40:14 +02003330int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3331 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003332{
3333 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003334 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003335 int err;
3336
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003337 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003338 if (!cmd)
3339 return -ENOENT;
3340
Johan Hedbergd8457692012-02-17 14:24:57 +02003341 bacpy(&rp.addr.bdaddr, bdaddr);
3342 rp.addr.type = MGMT_ADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003343
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003344 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
3345 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003346
Johan Hedberga664b5b2011-02-19 12:06:02 -03003347 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003348
3349 return err;
3350}
Johan Hedberga5c29682011-02-19 12:05:57 -03003351
Johan Hedberg744cf192011-11-08 20:40:14 +02003352int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003353 u8 link_type, u8 addr_type, __le32 value,
3354 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03003355{
3356 struct mgmt_ev_user_confirm_request ev;
3357
Johan Hedberg744cf192011-11-08 20:40:14 +02003358 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03003359
Johan Hedberg272d90d2012-02-09 15:26:12 +02003360 bacpy(&ev.addr.bdaddr, bdaddr);
3361 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07003362 ev.confirm_hint = confirm_hint;
Johan Hedberga5c29682011-02-19 12:05:57 -03003363 put_unaligned_le32(value, &ev.value);
3364
Johan Hedberg744cf192011-11-08 20:40:14 +02003365 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01003366 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03003367}
3368
Johan Hedberg272d90d2012-02-09 15:26:12 +02003369int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
3370 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08003371{
3372 struct mgmt_ev_user_passkey_request ev;
3373
3374 BT_DBG("%s", hdev->name);
3375
Johan Hedberg272d90d2012-02-09 15:26:12 +02003376 bacpy(&ev.addr.bdaddr, bdaddr);
3377 ev.addr.type = link_to_mgmt(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08003378
3379 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
3380 NULL);
3381}
3382
Brian Gix0df4c182011-11-16 13:53:13 -08003383static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003384 u8 link_type, u8 addr_type, u8 status,
3385 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03003386{
3387 struct pending_cmd *cmd;
3388 struct mgmt_rp_user_confirm_reply rp;
3389 int err;
3390
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003391 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03003392 if (!cmd)
3393 return -ENOENT;
3394
Johan Hedberg272d90d2012-02-09 15:26:12 +02003395 bacpy(&rp.addr.bdaddr, bdaddr);
3396 rp.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003397 err = cmd_complete(cmd->sk, hdev->id, opcode, mgmt_status(status),
3398 &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03003399
Johan Hedberga664b5b2011-02-19 12:06:02 -03003400 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03003401
3402 return err;
3403}
3404
Johan Hedberg744cf192011-11-08 20:40:14 +02003405int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003406 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003407{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003408 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3409 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003410}
3411
Johan Hedberg272d90d2012-02-09 15:26:12 +02003412int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3413 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003414{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003415 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3416 status, MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003417}
Johan Hedberg2a611692011-02-19 12:06:00 -03003418
Brian Gix604086b2011-11-23 08:28:33 -08003419int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003420 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003421{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003422 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3423 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003424}
3425
Johan Hedberg272d90d2012-02-09 15:26:12 +02003426int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3427 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003428{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003429 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3430 status, MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003431}
3432
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003433int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
3434 u8 addr_type, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03003435{
3436 struct mgmt_ev_auth_failed ev;
3437
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003438 bacpy(&ev.addr.bdaddr, bdaddr);
3439 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003440 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03003441
Johan Hedberg744cf192011-11-08 20:40:14 +02003442 return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03003443}
Johan Hedbergb312b1612011-03-16 14:29:37 +02003444
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003445int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
3446{
3447 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg47990ea2012-02-22 11:58:37 +02003448 bool changed = false;
3449 int err = 0;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003450
3451 if (status) {
3452 u8 mgmt_err = mgmt_status(status);
3453 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
3454 cmd_status_rsp, &mgmt_err);
3455 return 0;
3456 }
3457
Johan Hedberg47990ea2012-02-22 11:58:37 +02003458 if (test_bit(HCI_AUTH, &hdev->flags)) {
3459 if (!test_and_set_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
3460 changed = true;
3461 } else {
3462 if (test_and_clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
3463 changed = true;
3464 }
3465
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003466 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
3467 &match);
3468
Johan Hedberg47990ea2012-02-22 11:58:37 +02003469 if (changed)
3470 err = new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003471
3472 if (match.sk)
3473 sock_put(match.sk);
3474
3475 return err;
3476}
3477
Johan Hedbergcacaf522012-02-21 00:52:42 +02003478static int clear_eir(struct hci_dev *hdev)
3479{
3480 struct hci_cp_write_eir cp;
3481
3482 if (!(hdev->features[6] & LMP_EXT_INQ))
3483 return 0;
3484
Johan Hedbergc80da272012-02-22 15:38:48 +02003485 memset(hdev->eir, 0, sizeof(hdev->eir));
3486
Johan Hedbergcacaf522012-02-21 00:52:42 +02003487 memset(&cp, 0, sizeof(cp));
3488
3489 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
3490}
3491
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003492int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003493{
3494 struct cmd_lookup match = { NULL, hdev };
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003495 bool changed = false;
3496 int err = 0;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003497
3498 if (status) {
3499 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003500
3501 if (enable && test_and_clear_bit(HCI_SSP_ENABLED,
3502 &hdev->dev_flags))
3503 err = new_settings(hdev, NULL);
3504
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003505 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev,
3506 cmd_status_rsp, &mgmt_err);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003507
3508 return err;
3509 }
3510
3511 if (enable) {
3512 if (!test_and_set_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3513 changed = true;
3514 } else {
3515 if (test_and_clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3516 changed = true;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003517 }
3518
3519 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
3520
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003521 if (changed)
3522 err = new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003523
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02003524 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003525 sock_put(match.sk);
3526
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02003527 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3528 update_eir(hdev);
3529 else
3530 clear_eir(hdev);
Johan Hedbergcacaf522012-02-21 00:52:42 +02003531
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003532 return err;
3533}
3534
Johan Hedberg744cf192011-11-08 20:40:14 +02003535int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02003536{
3537 struct pending_cmd *cmd;
3538 struct mgmt_cp_set_local_name ev;
3539 int err;
3540
3541 memset(&ev, 0, sizeof(ev));
3542 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
3543
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003544 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003545 if (!cmd)
3546 goto send_event;
3547
3548 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02003549 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
Johan Hedbergca69b792011-11-11 18:10:00 +02003550 mgmt_status(status));
Johan Hedbergb312b1612011-03-16 14:29:37 +02003551 goto failed;
3552 }
3553
Johan Hedberg744cf192011-11-08 20:40:14 +02003554 update_eir(hdev);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03003555
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003556 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0, &ev,
Johan Hedbergb312b1612011-03-16 14:29:37 +02003557 sizeof(ev));
3558 if (err < 0)
3559 goto failed;
3560
3561send_event:
Johan Hedberg744cf192011-11-08 20:40:14 +02003562 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
Johan Hedbergb312b1612011-03-16 14:29:37 +02003563 cmd ? cmd->sk : NULL);
3564
3565failed:
3566 if (cmd)
3567 mgmt_pending_remove(cmd);
3568 return err;
3569}
Szymon Jancc35938b2011-03-22 13:12:21 +01003570
Johan Hedberg744cf192011-11-08 20:40:14 +02003571int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
3572 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01003573{
3574 struct pending_cmd *cmd;
3575 int err;
3576
Johan Hedberg744cf192011-11-08 20:40:14 +02003577 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01003578
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003579 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003580 if (!cmd)
3581 return -ENOENT;
3582
3583 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02003584 err = cmd_status(cmd->sk, hdev->id,
Johan Hedbergca69b792011-11-11 18:10:00 +02003585 MGMT_OP_READ_LOCAL_OOB_DATA,
3586 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01003587 } else {
3588 struct mgmt_rp_read_local_oob_data rp;
3589
3590 memcpy(rp.hash, hash, sizeof(rp.hash));
3591 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
3592
Johan Hedberg744cf192011-11-08 20:40:14 +02003593 err = cmd_complete(cmd->sk, hdev->id,
3594 MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003595 0, &rp, sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01003596 }
3597
3598 mgmt_pending_remove(cmd);
3599
3600 return err;
3601}
Johan Hedberge17acd42011-03-30 23:57:16 +03003602
Johan Hedberg06199cf2012-02-22 16:37:11 +02003603int mgmt_le_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
3604{
3605 struct cmd_lookup match = { NULL, hdev };
3606 bool changed = false;
3607 int err = 0;
3608
3609 if (status) {
3610 u8 mgmt_err = mgmt_status(status);
3611
3612 if (enable && test_and_clear_bit(HCI_LE_ENABLED,
3613 &hdev->dev_flags))
3614 err = new_settings(hdev, NULL);
3615
3616 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev,
3617 cmd_status_rsp, &mgmt_err);
3618
3619 return err;
3620 }
3621
3622 if (enable) {
3623 if (!test_and_set_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3624 changed = true;
3625 } else {
3626 if (test_and_clear_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3627 changed = true;
3628 }
3629
3630 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
3631
3632 if (changed)
3633 err = new_settings(hdev, match.sk);
3634
3635 if (match.sk)
3636 sock_put(match.sk);
3637
3638 return err;
3639}
3640
Johan Hedberg48264f02011-11-09 13:58:58 +02003641int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Johan Hedberg561aafb2012-01-04 13:31:59 +02003642 u8 addr_type, u8 *dev_class, s8 rssi,
Johan Hedberge319d2e2012-01-15 19:51:59 +02003643 u8 cfm_name, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03003644{
Johan Hedberge319d2e2012-01-15 19:51:59 +02003645 char buf[512];
3646 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02003647 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03003648
Johan Hedberg1dc06092012-01-15 21:01:23 +02003649 /* Leave 5 bytes for a potential CoD field */
3650 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Andre Guedes7d262f82012-01-10 18:20:49 -03003651 return -EINVAL;
3652
Johan Hedberg1dc06092012-01-15 21:01:23 +02003653 memset(buf, 0, sizeof(buf));
3654
Johan Hedberge319d2e2012-01-15 19:51:59 +02003655 bacpy(&ev->addr.bdaddr, bdaddr);
3656 ev->addr.type = link_to_mgmt(link_type, addr_type);
3657 ev->rssi = rssi;
3658 ev->confirm_name = cfm_name;
Johan Hedberge17acd42011-03-30 23:57:16 +03003659
Johan Hedberg1dc06092012-01-15 21:01:23 +02003660 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02003661 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03003662
Johan Hedberg1dc06092012-01-15 21:01:23 +02003663 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
3664 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
3665 dev_class, 3);
3666
3667 put_unaligned_le16(eir_len, &ev->eir_len);
3668
3669 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03003670
Johan Hedberge319d2e2012-01-15 19:51:59 +02003671 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03003672}
Johan Hedberga88a9652011-03-30 13:18:12 +03003673
Johan Hedbergb644ba32012-01-17 21:48:47 +02003674int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
3675 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03003676{
Johan Hedbergb644ba32012-01-17 21:48:47 +02003677 struct mgmt_ev_device_found *ev;
3678 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
3679 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03003680
Johan Hedbergb644ba32012-01-17 21:48:47 +02003681 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03003682
Johan Hedbergb644ba32012-01-17 21:48:47 +02003683 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03003684
Johan Hedbergb644ba32012-01-17 21:48:47 +02003685 bacpy(&ev->addr.bdaddr, bdaddr);
3686 ev->addr.type = link_to_mgmt(link_type, addr_type);
3687 ev->rssi = rssi;
3688
3689 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
3690 name_len);
3691
3692 put_unaligned_le16(eir_len, &ev->eir_len);
3693
Johan Hedberg053c7e02012-02-04 00:06:00 +02003694 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev,
3695 sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03003696}
Johan Hedberg314b2382011-04-27 10:29:57 -04003697
Andre Guedes7a135102011-11-09 17:14:25 -03003698int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
Johan Hedberg164a6e72011-11-01 17:06:44 +02003699{
3700 struct pending_cmd *cmd;
Johan Hedbergf808e162012-02-19 12:52:07 +02003701 u8 type;
Johan Hedberg164a6e72011-11-01 17:06:44 +02003702 int err;
3703
Andre Guedes203159d2012-02-13 15:41:01 -03003704 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3705
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003706 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003707 if (!cmd)
3708 return -ENOENT;
3709
Johan Hedbergf808e162012-02-19 12:52:07 +02003710 type = hdev->discovery.type;
3711
3712 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
3713 &type, sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02003714 mgmt_pending_remove(cmd);
3715
3716 return err;
3717}
3718
Andre Guedese6d465c2011-11-09 17:14:26 -03003719int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
3720{
3721 struct pending_cmd *cmd;
3722 int err;
3723
3724 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
3725 if (!cmd)
3726 return -ENOENT;
3727
Johan Hedbergd9306502012-02-20 23:25:18 +02003728 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
3729 &hdev->discovery.type,
3730 sizeof(hdev->discovery.type));
Johan Hedberg03811012010-12-08 00:21:06 +02003731 mgmt_pending_remove(cmd);
3732
3733 return err;
3734}
Johan Hedberg314b2382011-04-27 10:29:57 -04003735
Johan Hedberg744cf192011-11-08 20:40:14 +02003736int mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04003737{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02003738 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02003739 struct pending_cmd *cmd;
3740
Andre Guedes343fb142011-11-22 17:14:19 -03003741 BT_DBG("%s discovering %u", hdev->name, discovering);
3742
Johan Hedberg164a6e72011-11-01 17:06:44 +02003743 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003744 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003745 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003746 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003747
3748 if (cmd != NULL) {
Johan Hedbergf808e162012-02-19 12:52:07 +02003749 u8 type = hdev->discovery.type;
3750
Johan Hedbergd9306502012-02-20 23:25:18 +02003751 cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0,
Johan Hedbergf808e162012-02-19 12:52:07 +02003752 &type, sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02003753 mgmt_pending_remove(cmd);
3754 }
3755
Johan Hedbergf963e8e2012-02-20 23:30:44 +02003756 memset(&ev, 0, sizeof(ev));
3757 ev.type = hdev->discovery.type;
3758 ev.discovering = discovering;
3759
3760 return mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04003761}
Antti Julku5e762442011-08-25 16:48:02 +03003762
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003763int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003764{
3765 struct pending_cmd *cmd;
3766 struct mgmt_ev_device_blocked ev;
3767
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003768 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003769
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003770 bacpy(&ev.addr.bdaddr, bdaddr);
3771 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003772
Johan Hedberg744cf192011-11-08 20:40:14 +02003773 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
3774 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003775}
3776
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003777int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003778{
3779 struct pending_cmd *cmd;
3780 struct mgmt_ev_device_unblocked ev;
3781
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003782 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003783
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003784 bacpy(&ev.addr.bdaddr, bdaddr);
3785 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003786
Johan Hedberg744cf192011-11-08 20:40:14 +02003787 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
3788 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003789}
Marcel Holtmannd7b7e792012-02-20 21:47:49 +01003790
3791module_param(enable_hs, bool, 0644);
3792MODULE_PARM_DESC(enable_hs, "Enable High Speed support");
3793
3794module_param(enable_le, bool, 0644);
3795MODULE_PARM_DESC(enable_le, "Enable Low Energy support");