blob: c27481c3c95dae72d96fdd45210edbf5551aef91 [file] [log] [blame]
Johan Hedberg03811012010-12-08 00:21:06 +02001/*
2 BlueZ - Bluetooth protocol stack for Linux
Johan Hedbergea585ab2012-02-17 14:50:39 +02003
Johan Hedberg03811012010-12-08 00:21:06 +02004 Copyright (C) 2010 Nokia Corporation
Johan Hedbergea585ab2012-02-17 14:50:39 +02005 Copyright (C) 2011-2012 Intel Corporation
Johan Hedberg03811012010-12-08 00:21:06 +02006
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License version 2 as
9 published by the Free Software Foundation;
10
11 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
12 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
13 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
14 IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
15 CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
16 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19
20 ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
21 COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
22 SOFTWARE IS DISCLAIMED.
23*/
24
25/* Bluetooth HCI Management interface */
26
Johan Hedbergca69b792011-11-11 18:10:00 +020027#include <linux/kernel.h>
Szymon Janc72359752011-02-17 14:16:32 +010028#include <linux/uaccess.h>
Paul Gortmaker3a9a2312011-05-27 09:12:25 -040029#include <linux/module.h>
Johan Hedberg03811012010-12-08 00:21:06 +020030#include <asm/unaligned.h>
31
32#include <net/bluetooth/bluetooth.h>
33#include <net/bluetooth/hci_core.h>
34#include <net/bluetooth/mgmt.h>
Brian Gix5fe57d92011-12-21 16:12:13 -080035#include <net/bluetooth/smp.h>
Johan Hedberg03811012010-12-08 00:21:06 +020036
Marcel Holtmannd7b7e792012-02-20 21:47:49 +010037bool enable_hs;
38bool enable_le;
39
Johan Hedberg2da9c552012-02-17 14:39:28 +020040#define MGMT_VERSION 1
41#define MGMT_REVISION 0
Johan Hedberg02d98122010-12-13 21:07:04 +020042
Johan Hedberge70bb2e2012-02-13 16:59:33 +020043static const u16 mgmt_commands[] = {
44 MGMT_OP_READ_INDEX_LIST,
45 MGMT_OP_READ_INFO,
46 MGMT_OP_SET_POWERED,
47 MGMT_OP_SET_DISCOVERABLE,
48 MGMT_OP_SET_CONNECTABLE,
49 MGMT_OP_SET_FAST_CONNECTABLE,
50 MGMT_OP_SET_PAIRABLE,
51 MGMT_OP_SET_LINK_SECURITY,
52 MGMT_OP_SET_SSP,
53 MGMT_OP_SET_HS,
54 MGMT_OP_SET_LE,
55 MGMT_OP_SET_DEV_CLASS,
56 MGMT_OP_SET_LOCAL_NAME,
57 MGMT_OP_ADD_UUID,
58 MGMT_OP_REMOVE_UUID,
59 MGMT_OP_LOAD_LINK_KEYS,
60 MGMT_OP_LOAD_LONG_TERM_KEYS,
61 MGMT_OP_DISCONNECT,
62 MGMT_OP_GET_CONNECTIONS,
63 MGMT_OP_PIN_CODE_REPLY,
64 MGMT_OP_PIN_CODE_NEG_REPLY,
65 MGMT_OP_SET_IO_CAPABILITY,
66 MGMT_OP_PAIR_DEVICE,
67 MGMT_OP_CANCEL_PAIR_DEVICE,
68 MGMT_OP_UNPAIR_DEVICE,
69 MGMT_OP_USER_CONFIRM_REPLY,
70 MGMT_OP_USER_CONFIRM_NEG_REPLY,
71 MGMT_OP_USER_PASSKEY_REPLY,
72 MGMT_OP_USER_PASSKEY_NEG_REPLY,
73 MGMT_OP_READ_LOCAL_OOB_DATA,
74 MGMT_OP_ADD_REMOTE_OOB_DATA,
75 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
76 MGMT_OP_START_DISCOVERY,
77 MGMT_OP_STOP_DISCOVERY,
78 MGMT_OP_CONFIRM_NAME,
79 MGMT_OP_BLOCK_DEVICE,
80 MGMT_OP_UNBLOCK_DEVICE,
81};
82
83static const u16 mgmt_events[] = {
84 MGMT_EV_CONTROLLER_ERROR,
85 MGMT_EV_INDEX_ADDED,
86 MGMT_EV_INDEX_REMOVED,
87 MGMT_EV_NEW_SETTINGS,
88 MGMT_EV_CLASS_OF_DEV_CHANGED,
89 MGMT_EV_LOCAL_NAME_CHANGED,
90 MGMT_EV_NEW_LINK_KEY,
91 MGMT_EV_NEW_LONG_TERM_KEY,
92 MGMT_EV_DEVICE_CONNECTED,
93 MGMT_EV_DEVICE_DISCONNECTED,
94 MGMT_EV_CONNECT_FAILED,
95 MGMT_EV_PIN_CODE_REQUEST,
96 MGMT_EV_USER_CONFIRM_REQUEST,
97 MGMT_EV_USER_PASSKEY_REQUEST,
98 MGMT_EV_AUTH_FAILED,
99 MGMT_EV_DEVICE_FOUND,
100 MGMT_EV_DISCOVERING,
101 MGMT_EV_DEVICE_BLOCKED,
102 MGMT_EV_DEVICE_UNBLOCKED,
103 MGMT_EV_DEVICE_UNPAIRED,
104};
105
Andre Guedes3fd24152012-02-03 17:48:01 -0300106/*
107 * These LE scan and inquiry parameters were chosen according to LE General
108 * Discovery Procedure specification.
109 */
110#define LE_SCAN_TYPE 0x01
111#define LE_SCAN_WIN 0x12
112#define LE_SCAN_INT 0x12
113#define LE_SCAN_TIMEOUT_LE_ONLY 10240 /* TGAP(gen_disc_scan_min) */
Andre Guedes5e0452c2012-02-17 20:39:38 -0300114#define LE_SCAN_TIMEOUT_BREDR_LE 5120 /* TGAP(100)/2 */
Andre Guedes3fd24152012-02-03 17:48:01 -0300115
Andre Guedese8777522012-02-03 17:48:02 -0300116#define INQUIRY_LEN_BREDR 0x08 /* TGAP(100) */
Andre Guedes5e0452c2012-02-17 20:39:38 -0300117#define INQUIRY_LEN_BREDR_LE 0x04 /* TGAP(100)/2 */
Andre Guedes2519a1f2011-11-07 11:45:24 -0300118
Johan Hedberg7d785252011-12-15 00:47:39 +0200119#define SERVICE_CACHE_TIMEOUT (5 * 1000)
120
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200121#define hdev_is_powered(hdev) (test_bit(HCI_UP, &hdev->flags) && \
122 !test_bit(HCI_AUTO_OFF, &hdev->dev_flags))
123
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200124struct pending_cmd {
125 struct list_head list;
Johan Hedbergfc2f4b12011-11-09 13:58:56 +0200126 u16 opcode;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200127 int index;
Szymon Jancc68fb7f2011-03-22 13:12:19 +0100128 void *param;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200129 struct sock *sk;
Johan Hedberge9a416b2011-02-19 12:05:56 -0300130 void *user_data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200131};
132
Johan Hedbergca69b792011-11-11 18:10:00 +0200133/* HCI to MGMT error code conversion table */
134static u8 mgmt_status_table[] = {
135 MGMT_STATUS_SUCCESS,
136 MGMT_STATUS_UNKNOWN_COMMAND, /* Unknown Command */
137 MGMT_STATUS_NOT_CONNECTED, /* No Connection */
138 MGMT_STATUS_FAILED, /* Hardware Failure */
139 MGMT_STATUS_CONNECT_FAILED, /* Page Timeout */
140 MGMT_STATUS_AUTH_FAILED, /* Authentication Failed */
141 MGMT_STATUS_NOT_PAIRED, /* PIN or Key Missing */
142 MGMT_STATUS_NO_RESOURCES, /* Memory Full */
143 MGMT_STATUS_TIMEOUT, /* Connection Timeout */
144 MGMT_STATUS_NO_RESOURCES, /* Max Number of Connections */
145 MGMT_STATUS_NO_RESOURCES, /* Max Number of SCO Connections */
146 MGMT_STATUS_ALREADY_CONNECTED, /* ACL Connection Exists */
147 MGMT_STATUS_BUSY, /* Command Disallowed */
148 MGMT_STATUS_NO_RESOURCES, /* Rejected Limited Resources */
149 MGMT_STATUS_REJECTED, /* Rejected Security */
150 MGMT_STATUS_REJECTED, /* Rejected Personal */
151 MGMT_STATUS_TIMEOUT, /* Host Timeout */
152 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Feature */
153 MGMT_STATUS_INVALID_PARAMS, /* Invalid Parameters */
154 MGMT_STATUS_DISCONNECTED, /* OE User Ended Connection */
155 MGMT_STATUS_NO_RESOURCES, /* OE Low Resources */
156 MGMT_STATUS_DISCONNECTED, /* OE Power Off */
157 MGMT_STATUS_DISCONNECTED, /* Connection Terminated */
158 MGMT_STATUS_BUSY, /* Repeated Attempts */
159 MGMT_STATUS_REJECTED, /* Pairing Not Allowed */
160 MGMT_STATUS_FAILED, /* Unknown LMP PDU */
161 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Remote Feature */
162 MGMT_STATUS_REJECTED, /* SCO Offset Rejected */
163 MGMT_STATUS_REJECTED, /* SCO Interval Rejected */
164 MGMT_STATUS_REJECTED, /* Air Mode Rejected */
165 MGMT_STATUS_INVALID_PARAMS, /* Invalid LMP Parameters */
166 MGMT_STATUS_FAILED, /* Unspecified Error */
167 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported LMP Parameter Value */
168 MGMT_STATUS_FAILED, /* Role Change Not Allowed */
169 MGMT_STATUS_TIMEOUT, /* LMP Response Timeout */
170 MGMT_STATUS_FAILED, /* LMP Error Transaction Collision */
171 MGMT_STATUS_FAILED, /* LMP PDU Not Allowed */
172 MGMT_STATUS_REJECTED, /* Encryption Mode Not Accepted */
173 MGMT_STATUS_FAILED, /* Unit Link Key Used */
174 MGMT_STATUS_NOT_SUPPORTED, /* QoS Not Supported */
175 MGMT_STATUS_TIMEOUT, /* Instant Passed */
176 MGMT_STATUS_NOT_SUPPORTED, /* Pairing Not Supported */
177 MGMT_STATUS_FAILED, /* Transaction Collision */
178 MGMT_STATUS_INVALID_PARAMS, /* Unacceptable Parameter */
179 MGMT_STATUS_REJECTED, /* QoS Rejected */
180 MGMT_STATUS_NOT_SUPPORTED, /* Classification Not Supported */
181 MGMT_STATUS_REJECTED, /* Insufficient Security */
182 MGMT_STATUS_INVALID_PARAMS, /* Parameter Out Of Range */
183 MGMT_STATUS_BUSY, /* Role Switch Pending */
184 MGMT_STATUS_FAILED, /* Slot Violation */
185 MGMT_STATUS_FAILED, /* Role Switch Failed */
186 MGMT_STATUS_INVALID_PARAMS, /* EIR Too Large */
187 MGMT_STATUS_NOT_SUPPORTED, /* Simple Pairing Not Supported */
188 MGMT_STATUS_BUSY, /* Host Busy Pairing */
189 MGMT_STATUS_REJECTED, /* Rejected, No Suitable Channel */
190 MGMT_STATUS_BUSY, /* Controller Busy */
191 MGMT_STATUS_INVALID_PARAMS, /* Unsuitable Connection Interval */
192 MGMT_STATUS_TIMEOUT, /* Directed Advertising Timeout */
193 MGMT_STATUS_AUTH_FAILED, /* Terminated Due to MIC Failure */
194 MGMT_STATUS_CONNECT_FAILED, /* Connection Establishment Failed */
195 MGMT_STATUS_CONNECT_FAILED, /* MAC Connection Failed */
196};
197
198static u8 mgmt_status(u8 hci_status)
199{
200 if (hci_status < ARRAY_SIZE(mgmt_status_table))
201 return mgmt_status_table[hci_status];
202
203 return MGMT_STATUS_FAILED;
204}
205
Szymon Janc4e51eae2011-02-25 19:05:48 +0100206static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200207{
208 struct sk_buff *skb;
209 struct mgmt_hdr *hdr;
210 struct mgmt_ev_cmd_status *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300211 int err;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200212
Szymon Janc34eb5252011-02-28 14:10:08 +0100213 BT_DBG("sock %p, index %u, cmd %u, status %u", sk, index, cmd, status);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200214
215 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_ATOMIC);
216 if (!skb)
217 return -ENOMEM;
218
219 hdr = (void *) skb_put(skb, sizeof(*hdr));
220
221 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_STATUS);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100222 hdr->index = cpu_to_le16(index);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200223 hdr->len = cpu_to_le16(sizeof(*ev));
224
225 ev = (void *) skb_put(skb, sizeof(*ev));
226 ev->status = status;
227 put_unaligned_le16(cmd, &ev->opcode);
228
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300229 err = sock_queue_rcv_skb(sk, skb);
230 if (err < 0)
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200231 kfree_skb(skb);
232
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300233 return err;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200234}
235
Johan Hedbergaee9b212012-02-18 15:07:59 +0200236static int cmd_complete(struct sock *sk, u16 index, u16 cmd, u8 status,
237 void *rp, size_t rp_len)
Johan Hedberg02d98122010-12-13 21:07:04 +0200238{
239 struct sk_buff *skb;
240 struct mgmt_hdr *hdr;
241 struct mgmt_ev_cmd_complete *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300242 int err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200243
244 BT_DBG("sock %p", sk);
245
Johan Hedberga38528f2011-01-22 06:46:43 +0200246 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + rp_len, GFP_ATOMIC);
Johan Hedberg02d98122010-12-13 21:07:04 +0200247 if (!skb)
248 return -ENOMEM;
249
250 hdr = (void *) skb_put(skb, sizeof(*hdr));
Johan Hedberga38528f2011-01-22 06:46:43 +0200251
Johan Hedberg02d98122010-12-13 21:07:04 +0200252 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100253 hdr->index = cpu_to_le16(index);
Johan Hedberga38528f2011-01-22 06:46:43 +0200254 hdr->len = cpu_to_le16(sizeof(*ev) + rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200255
Johan Hedberga38528f2011-01-22 06:46:43 +0200256 ev = (void *) skb_put(skb, sizeof(*ev) + rp_len);
257 put_unaligned_le16(cmd, &ev->opcode);
Johan Hedbergaee9b212012-02-18 15:07:59 +0200258 ev->status = status;
Szymon Janc8020c162011-02-28 14:09:50 +0100259
260 if (rp)
261 memcpy(ev->data, rp, rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200262
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300263 err = sock_queue_rcv_skb(sk, skb);
264 if (err < 0)
Johan Hedberg02d98122010-12-13 21:07:04 +0200265 kfree_skb(skb);
266
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300267 return err;;
Johan Hedberg02d98122010-12-13 21:07:04 +0200268}
269
Johan Hedberga38528f2011-01-22 06:46:43 +0200270static int read_version(struct sock *sk)
271{
272 struct mgmt_rp_read_version rp;
273
274 BT_DBG("sock %p", sk);
275
276 rp.version = MGMT_VERSION;
277 put_unaligned_le16(MGMT_REVISION, &rp.revision);
278
Johan Hedbergaee9b212012-02-18 15:07:59 +0200279 return cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, 0, &rp,
Szymon Janc4e51eae2011-02-25 19:05:48 +0100280 sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200281}
282
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200283static int read_commands(struct sock *sk)
284{
285 struct mgmt_rp_read_commands *rp;
286 u16 num_commands = ARRAY_SIZE(mgmt_commands);
287 u16 num_events = ARRAY_SIZE(mgmt_events);
288 u16 *opcode;
289 size_t rp_size;
290 int i, err;
291
292 BT_DBG("sock %p", sk);
293
294 rp_size = sizeof(*rp) + ((num_commands + num_events) * sizeof(u16));
295
296 rp = kmalloc(rp_size, GFP_KERNEL);
297 if (!rp)
298 return -ENOMEM;
299
300 put_unaligned_le16(num_commands, &rp->num_commands);
301 put_unaligned_le16(num_events, &rp->num_events);
302
303 for (i = 0, opcode = rp->opcodes; i < num_commands; i++, opcode++)
304 put_unaligned_le16(mgmt_commands[i], opcode);
305
306 for (i = 0; i < num_events; i++, opcode++)
307 put_unaligned_le16(mgmt_events[i], opcode);
308
Johan Hedbergaee9b212012-02-18 15:07:59 +0200309 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_COMMANDS, 0, rp,
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200310 rp_size);
311 kfree(rp);
312
313 return err;
314}
315
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200316static int read_index_list(struct sock *sk)
317{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200318 struct mgmt_rp_read_index_list *rp;
319 struct list_head *p;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200320 struct hci_dev *d;
Johan Hedberga38528f2011-01-22 06:46:43 +0200321 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200322 u16 count;
Johan Hedberga38528f2011-01-22 06:46:43 +0200323 int i, err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200324
325 BT_DBG("sock %p", sk);
326
327 read_lock(&hci_dev_list_lock);
328
329 count = 0;
330 list_for_each(p, &hci_dev_list) {
331 count++;
332 }
333
Johan Hedberga38528f2011-01-22 06:46:43 +0200334 rp_len = sizeof(*rp) + (2 * count);
335 rp = kmalloc(rp_len, GFP_ATOMIC);
336 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100337 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200338 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100339 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200340
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200341 put_unaligned_le16(count, &rp->num_controllers);
342
343 i = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200344 list_for_each_entry(d, &hci_dev_list, list) {
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200345 if (test_bit(HCI_SETUP, &d->dev_flags))
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200346 continue;
347
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200348 put_unaligned_le16(d->id, &rp->index[i++]);
349 BT_DBG("Added hci%u", d->id);
350 }
351
352 read_unlock(&hci_dev_list_lock);
353
Johan Hedbergaee9b212012-02-18 15:07:59 +0200354 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST, 0, rp,
Szymon Janc4e51eae2011-02-25 19:05:48 +0100355 rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200356
Johan Hedberga38528f2011-01-22 06:46:43 +0200357 kfree(rp);
358
359 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200360}
361
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200362static u32 get_supported_settings(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +0200363{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200364 u32 settings = 0;
Johan Hedberg03811012010-12-08 00:21:06 +0200365
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200366 settings |= MGMT_SETTING_POWERED;
367 settings |= MGMT_SETTING_CONNECTABLE;
368 settings |= MGMT_SETTING_FAST_CONNECTABLE;
369 settings |= MGMT_SETTING_DISCOVERABLE;
370 settings |= MGMT_SETTING_PAIRABLE;
Johan Hedberg03811012010-12-08 00:21:06 +0200371
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200372 if (hdev->features[6] & LMP_SIMPLE_PAIR)
373 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200374
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200375 if (!(hdev->features[4] & LMP_NO_BREDR)) {
376 settings |= MGMT_SETTING_BREDR;
377 settings |= MGMT_SETTING_LINK_SECURITY;
378 }
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200379
Marcel Holtmannd7b7e792012-02-20 21:47:49 +0100380 if (enable_hs)
381 settings |= MGMT_SETTING_HS;
382
383 if (enable_le) {
384 if (hdev->features[4] & LMP_LE)
385 settings |= MGMT_SETTING_LE;
386 }
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200387
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200388 return settings;
389}
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200390
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200391static u32 get_current_settings(struct hci_dev *hdev)
392{
393 u32 settings = 0;
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200394
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100395 if (!test_bit(HCI_UP, &hdev->flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200396 return settings;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200397
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100398 if (!test_bit(HCI_AUTO_OFF, &hdev->dev_flags))
399 settings |= MGMT_SETTING_POWERED;
400
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200401 if (test_bit(HCI_PSCAN, &hdev->flags))
402 settings |= MGMT_SETTING_CONNECTABLE;
403
404 if (test_bit(HCI_ISCAN, &hdev->flags))
405 settings |= MGMT_SETTING_DISCOVERABLE;
406
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200407 if (test_bit(HCI_PAIRABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200408 settings |= MGMT_SETTING_PAIRABLE;
409
410 if (!(hdev->features[4] & LMP_NO_BREDR))
411 settings |= MGMT_SETTING_BREDR;
412
Andre Guedes59e29402011-12-30 10:34:03 -0300413 if (hdev->host_features[0] & LMP_HOST_LE)
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200414 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200415
416 if (test_bit(HCI_AUTH, &hdev->flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200417 settings |= MGMT_SETTING_LINK_SECURITY;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200418
Johan Hedberg84bde9d2012-01-25 14:21:06 +0200419 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200420 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200421
Johan Hedberg6d80dfd2012-02-20 23:50:38 +0200422 if (test_bit(HCI_HS_ENABLED, &hdev->dev_flags))
423 settings |= MGMT_SETTING_HS;
424
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200425 return settings;
Johan Hedbergc542a062011-01-26 13:11:03 +0200426}
427
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300428#define PNP_INFO_SVCLASS_ID 0x1200
429
430static u8 bluetooth_base_uuid[] = {
431 0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80,
432 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
433};
434
435static u16 get_uuid16(u8 *uuid128)
436{
437 u32 val;
438 int i;
439
440 for (i = 0; i < 12; i++) {
441 if (bluetooth_base_uuid[i] != uuid128[i])
442 return 0;
443 }
444
445 memcpy(&val, &uuid128[12], 4);
446
447 val = le32_to_cpu(val);
448 if (val > 0xffff)
449 return 0;
450
451 return (u16) val;
452}
453
454static void create_eir(struct hci_dev *hdev, u8 *data)
455{
456 u8 *ptr = data;
457 u16 eir_len = 0;
458 u16 uuid16_list[HCI_MAX_EIR_LENGTH / sizeof(u16)];
459 int i, truncated = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200460 struct bt_uuid *uuid;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300461 size_t name_len;
462
463 name_len = strlen(hdev->dev_name);
464
465 if (name_len > 0) {
466 /* EIR Data type */
467 if (name_len > 48) {
468 name_len = 48;
469 ptr[1] = EIR_NAME_SHORT;
470 } else
471 ptr[1] = EIR_NAME_COMPLETE;
472
473 /* EIR Data length */
474 ptr[0] = name_len + 1;
475
476 memcpy(ptr + 2, hdev->dev_name, name_len);
477
478 eir_len += (name_len + 2);
479 ptr += (name_len + 2);
480 }
481
482 memset(uuid16_list, 0, sizeof(uuid16_list));
483
484 /* Group all UUID16 types */
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200485 list_for_each_entry(uuid, &hdev->uuids, list) {
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300486 u16 uuid16;
487
488 uuid16 = get_uuid16(uuid->uuid);
489 if (uuid16 == 0)
490 return;
491
492 if (uuid16 < 0x1100)
493 continue;
494
495 if (uuid16 == PNP_INFO_SVCLASS_ID)
496 continue;
497
498 /* Stop if not enough space to put next UUID */
499 if (eir_len + 2 + sizeof(u16) > HCI_MAX_EIR_LENGTH) {
500 truncated = 1;
501 break;
502 }
503
504 /* Check for duplicates */
505 for (i = 0; uuid16_list[i] != 0; i++)
506 if (uuid16_list[i] == uuid16)
507 break;
508
509 if (uuid16_list[i] == 0) {
510 uuid16_list[i] = uuid16;
511 eir_len += sizeof(u16);
512 }
513 }
514
515 if (uuid16_list[0] != 0) {
516 u8 *length = ptr;
517
518 /* EIR Data type */
519 ptr[1] = truncated ? EIR_UUID16_SOME : EIR_UUID16_ALL;
520
521 ptr += 2;
522 eir_len += 2;
523
524 for (i = 0; uuid16_list[i] != 0; i++) {
525 *ptr++ = (uuid16_list[i] & 0x00ff);
526 *ptr++ = (uuid16_list[i] & 0xff00) >> 8;
527 }
528
529 /* EIR Data length */
530 *length = (i * sizeof(u16)) + 1;
531 }
532}
533
534static int update_eir(struct hci_dev *hdev)
535{
536 struct hci_cp_write_eir cp;
537
538 if (!(hdev->features[6] & LMP_EXT_INQ))
539 return 0;
540
Johan Hedberg84bde9d2012-01-25 14:21:06 +0200541 if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300542 return 0;
543
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200544 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300545 return 0;
546
547 memset(&cp, 0, sizeof(cp));
548
549 create_eir(hdev, cp.data);
550
551 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
552 return 0;
553
554 memcpy(hdev->eir, cp.data, sizeof(cp.data));
555
556 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
557}
558
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200559static u8 get_service_classes(struct hci_dev *hdev)
560{
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300561 struct bt_uuid *uuid;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200562 u8 val = 0;
563
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300564 list_for_each_entry(uuid, &hdev->uuids, list)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200565 val |= uuid->svc_hint;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200566
567 return val;
568}
569
570static int update_class(struct hci_dev *hdev)
571{
572 u8 cod[3];
573
574 BT_DBG("%s", hdev->name);
575
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200576 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200577 return 0;
578
579 cod[0] = hdev->minor_class;
580 cod[1] = hdev->major_class;
581 cod[2] = get_service_classes(hdev);
582
583 if (memcmp(cod, hdev->dev_class, 3) == 0)
584 return 0;
585
586 return hci_send_cmd(hdev, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
587}
588
Johan Hedberg7d785252011-12-15 00:47:39 +0200589static void service_cache_off(struct work_struct *work)
590{
591 struct hci_dev *hdev = container_of(work, struct hci_dev,
592 service_cache.work);
593
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200594 if (!test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200595 return;
596
597 hci_dev_lock(hdev);
598
599 update_eir(hdev);
600 update_class(hdev);
601
602 hci_dev_unlock(hdev);
603}
604
605static void mgmt_init_hdev(struct hci_dev *hdev)
606{
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200607 if (!test_and_set_bit(HCI_MGMT, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200608 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
609
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200610 if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200611 schedule_delayed_work(&hdev->service_cache,
612 msecs_to_jiffies(SERVICE_CACHE_TIMEOUT));
613}
614
Johan Hedberg03811012010-12-08 00:21:06 +0200615static int read_controller_info(struct sock *sk, u16 index)
616{
617 struct mgmt_rp_read_info rp;
618 struct hci_dev *hdev;
619
620 BT_DBG("sock %p hci%u", sk, index);
621
622 hdev = hci_dev_get(index);
623 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200624 return cmd_status(sk, index, MGMT_OP_READ_INFO,
625 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200626
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300627 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200628
Johan Hedberg7d785252011-12-15 00:47:39 +0200629 if (test_and_clear_bit(HCI_PI_MGMT_INIT, &hci_pi(sk)->flags))
630 mgmt_init_hdev(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200631
632 memset(&rp, 0, sizeof(rp));
633
Johan Hedberg03811012010-12-08 00:21:06 +0200634 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200635
636 rp.version = hdev->hci_ver;
637
Johan Hedberg03811012010-12-08 00:21:06 +0200638 put_unaligned_le16(hdev->manufacturer, &rp.manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200639
640 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
641 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
642
643 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedberg03811012010-12-08 00:21:06 +0200644
645 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
646
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300647 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200648 hci_dev_put(hdev);
649
Johan Hedbergaee9b212012-02-18 15:07:59 +0200650 return cmd_complete(sk, index, MGMT_OP_READ_INFO, 0, &rp, sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +0200651}
652
653static void mgmt_pending_free(struct pending_cmd *cmd)
654{
655 sock_put(cmd->sk);
656 kfree(cmd->param);
657 kfree(cmd);
658}
659
660static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
661 struct hci_dev *hdev,
662 void *data, u16 len)
663{
664 struct pending_cmd *cmd;
665
666 cmd = kmalloc(sizeof(*cmd), GFP_ATOMIC);
667 if (!cmd)
668 return NULL;
669
670 cmd->opcode = opcode;
671 cmd->index = hdev->id;
672
673 cmd->param = kmalloc(len, GFP_ATOMIC);
674 if (!cmd->param) {
675 kfree(cmd);
676 return NULL;
677 }
678
679 if (data)
680 memcpy(cmd->param, data, len);
681
682 cmd->sk = sk;
683 sock_hold(sk);
684
685 list_add(&cmd->list, &hdev->mgmt_pending);
686
687 return cmd;
688}
689
690static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
691 void (*cb)(struct pending_cmd *cmd, void *data),
692 void *data)
693{
694 struct list_head *p, *n;
695
696 list_for_each_safe(p, n, &hdev->mgmt_pending) {
697 struct pending_cmd *cmd;
698
699 cmd = list_entry(p, struct pending_cmd, list);
700
701 if (opcode > 0 && cmd->opcode != opcode)
702 continue;
703
704 cb(cmd, data);
705 }
706}
707
708static struct pending_cmd *mgmt_pending_find(u16 opcode, struct hci_dev *hdev)
709{
710 struct pending_cmd *cmd;
711
712 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
713 if (cmd->opcode == opcode)
714 return cmd;
715 }
716
717 return NULL;
718}
719
720static void mgmt_pending_remove(struct pending_cmd *cmd)
721{
722 list_del(&cmd->list);
723 mgmt_pending_free(cmd);
724}
725
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200726static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +0200727{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200728 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +0200729
Johan Hedbergaee9b212012-02-18 15:07:59 +0200730 return cmd_complete(sk, hdev->id, opcode, 0, &settings,
731 sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +0200732}
733
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300734static int set_powered(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200735{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300736 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200737 struct hci_dev *hdev;
738 struct pending_cmd *cmd;
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200739 int err;
Johan Hedberg03811012010-12-08 00:21:06 +0200740
Johan Hedberg03811012010-12-08 00:21:06 +0200741 BT_DBG("request for hci%u", index);
742
743 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200744 return cmd_status(sk, index, MGMT_OP_SET_POWERED,
745 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200746
747 hdev = hci_dev_get(index);
748 if (!hdev)
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
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300752 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200753
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100754 if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) {
755 cancel_delayed_work(&hdev->power_off);
756
757 if (cp->val) {
758 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
759 mgmt_powered(hdev, 1);
760 goto failed;
761 }
762 }
763
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200764 if (!!cp->val == hdev_is_powered(hdev)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200765 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200766 goto failed;
767 }
768
769 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200770 err = cmd_status(sk, index, MGMT_OP_SET_POWERED,
771 MGMT_STATUS_BUSY);
Johan Hedberg03811012010-12-08 00:21:06 +0200772 goto failed;
773 }
774
775 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
776 if (!cmd) {
777 err = -ENOMEM;
778 goto failed;
779 }
780
781 if (cp->val)
Gustavo F. Padovan7f971042011-12-18 12:40:32 -0200782 schedule_work(&hdev->power_on);
Johan Hedberg03811012010-12-08 00:21:06 +0200783 else
Gustavo F. Padovan80b7ab32011-12-17 14:52:27 -0200784 schedule_work(&hdev->power_off.work);
Johan Hedberg03811012010-12-08 00:21:06 +0200785
786 err = 0;
787
788failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300789 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200790 hci_dev_put(hdev);
791 return err;
792}
793
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300794static int set_discoverable(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200795{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300796 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberge41d8b42010-12-13 21:07:03 +0200797 struct hci_dev *hdev;
Johan Hedberg03811012010-12-08 00:21:06 +0200798 struct pending_cmd *cmd;
799 u8 scan;
800 int err;
801
Johan Hedberg03811012010-12-08 00:21:06 +0200802 BT_DBG("request for hci%u", index);
803
804 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200805 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
806 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200807
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200808 hdev = hci_dev_get(index);
809 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200810 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
811 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200812
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300813 hci_dev_lock(hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200814
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200815 if (!hdev_is_powered(hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200816 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
817 MGMT_STATUS_NOT_POWERED);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200818 goto failed;
819 }
820
821 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
822 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200823 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
824 MGMT_STATUS_BUSY);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200825 goto failed;
826 }
827
828 if (cp->val == test_bit(HCI_ISCAN, &hdev->flags) &&
829 test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200830 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200831 goto failed;
832 }
833
834 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
835 if (!cmd) {
836 err = -ENOMEM;
837 goto failed;
838 }
839
840 scan = SCAN_PAGE;
841
842 if (cp->val)
843 scan |= SCAN_INQUIRY;
844 else
845 cancel_delayed_work(&hdev->discov_off);
846
847 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
848 if (err < 0)
849 mgmt_pending_remove(cmd);
850
Johan Hedberg03811012010-12-08 00:21:06 +0200851 if (cp->val)
852 hdev->discov_timeout = get_unaligned_le16(&cp->timeout);
853
Johan Hedberge41d8b42010-12-13 21:07:03 +0200854failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300855 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200856 hci_dev_put(hdev);
857
858 return err;
859}
860
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300861static int set_connectable(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200862{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300863 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200864 struct hci_dev *hdev;
865 struct pending_cmd *cmd;
866 u8 scan;
867 int err;
868
Johan Hedberge41d8b42010-12-13 21:07:03 +0200869 BT_DBG("request for hci%u", index);
870
Johan Hedberg03811012010-12-08 00:21:06 +0200871 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200872 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
873 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200874
875 hdev = hci_dev_get(index);
876 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200877 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
878 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200879
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300880 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200881
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200882 if (!hdev_is_powered(hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200883 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
884 MGMT_STATUS_NOT_POWERED);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200885 goto failed;
886 }
887
888 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
889 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200890 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
891 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200892 goto failed;
893 }
894
895 if (cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200896 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200897 goto failed;
898 }
899
900 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
901 if (!cmd) {
902 err = -ENOMEM;
903 goto failed;
904 }
905
906 if (cp->val)
907 scan = SCAN_PAGE;
908 else
909 scan = 0;
910
911 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
912 if (err < 0)
913 mgmt_pending_remove(cmd);
914
915failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300916 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200917 hci_dev_put(hdev);
918
919 return err;
920}
921
922static int mgmt_event(u16 event, struct hci_dev *hdev, void *data,
923 u16 data_len, struct sock *skip_sk)
924{
925 struct sk_buff *skb;
926 struct mgmt_hdr *hdr;
927
928 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_ATOMIC);
929 if (!skb)
930 return -ENOMEM;
931
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200932 hdr = (void *) skb_put(skb, sizeof(*hdr));
933 hdr->opcode = cpu_to_le16(event);
934 if (hdev)
935 hdr->index = cpu_to_le16(hdev->id);
936 else
937 hdr->index = cpu_to_le16(MGMT_INDEX_NONE);
938 hdr->len = cpu_to_le16(data_len);
939
940 if (data)
941 memcpy(skb_put(skb, data_len), data, data_len);
942
Marcel Holtmann470fe1b2012-02-20 14:50:30 +0100943 hci_send_to_control(skb, skip_sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200944 kfree_skb(skb);
945
946 return 0;
947}
948
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300949static int set_pairable(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +0200950{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300951 struct mgmt_mode *cp = data;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200952 struct hci_dev *hdev;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200953 __le32 ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200954 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200955
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200956 BT_DBG("request for hci%u", index);
957
958 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200959 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE,
960 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200961
962 hdev = hci_dev_get(index);
963 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200964 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE,
965 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200966
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300967 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200968
969 if (cp->val)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200970 set_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200971 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200972 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200973
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200974 err = send_settings_rsp(sk, MGMT_OP_SET_PAIRABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200975 if (err < 0)
976 goto failed;
977
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200978 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200979
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200980 err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200981
982failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300983 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200984 hci_dev_put(hdev);
985
986 return err;
987}
Johan Hedberg72a734e2010-12-30 00:38:22 +0200988
Johan Hedberg33ef95e2012-02-16 23:56:27 +0200989static int set_link_security(struct sock *sk, u16 index, void *data, u16 len)
990{
991 struct mgmt_mode *cp = data;
992 struct pending_cmd *cmd;
993 struct hci_dev *hdev;
994 uint8_t val;
995 int err;
996
997 BT_DBG("request for hci%u", index);
998
999 if (len != sizeof(*cp))
1000 return cmd_status(sk, index, MGMT_OP_SET_LINK_SECURITY,
1001 MGMT_STATUS_INVALID_PARAMS);
1002
1003 hdev = hci_dev_get(index);
1004 if (!hdev)
1005 return cmd_status(sk, index, MGMT_OP_SET_LINK_SECURITY,
1006 MGMT_STATUS_INVALID_PARAMS);
1007
1008 hci_dev_lock(hdev);
1009
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001010 if (!hdev_is_powered(hdev)) {
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001011 err = cmd_status(sk, index, MGMT_OP_SET_LINK_SECURITY,
1012 MGMT_STATUS_NOT_POWERED);
1013 goto failed;
1014 }
1015
1016 if (mgmt_pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
1017 err = cmd_status(sk, index, MGMT_OP_SET_LINK_SECURITY,
1018 MGMT_STATUS_BUSY);
1019 goto failed;
1020 }
1021
1022 val = !!cp->val;
1023
1024 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1025 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1026 goto failed;
1027 }
1028
1029 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1030 if (!cmd) {
1031 err = -ENOMEM;
1032 goto failed;
1033 }
1034
1035 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1036 if (err < 0) {
1037 mgmt_pending_remove(cmd);
1038 goto failed;
1039 }
1040
1041failed:
1042 hci_dev_unlock(hdev);
1043 hci_dev_put(hdev);
1044
1045 return err;
1046}
1047
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001048static int set_ssp(struct sock *sk, u16 index, void *data, u16 len)
1049{
1050 struct mgmt_mode *cp = data;
1051 struct pending_cmd *cmd;
1052 struct hci_dev *hdev;
1053 uint8_t val;
1054 int err;
1055
1056 BT_DBG("request for hci%u", index);
1057
1058 if (len != sizeof(*cp))
1059 return cmd_status(sk, index, MGMT_OP_SET_SSP,
1060 MGMT_STATUS_INVALID_PARAMS);
1061
1062 hdev = hci_dev_get(index);
1063 if (!hdev)
1064 return cmd_status(sk, index, MGMT_OP_SET_SSP,
1065 MGMT_STATUS_INVALID_PARAMS);
1066
1067 hci_dev_lock(hdev);
1068
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001069 if (!hdev_is_powered(hdev)) {
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001070 err = cmd_status(sk, index, MGMT_OP_SET_SSP,
1071 MGMT_STATUS_NOT_POWERED);
1072 goto failed;
1073 }
1074
Johan Hedberg1e163572012-02-20 23:53:46 +02001075 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
1076 err = cmd_status(sk, index, MGMT_OP_SET_SSP,
1077 MGMT_STATUS_NOT_SUPPORTED);
1078 goto failed;
1079 }
1080
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001081 if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev)) {
1082 err = cmd_status(sk, index, MGMT_OP_SET_SSP, MGMT_STATUS_BUSY);
1083 goto failed;
1084 }
1085
1086 val = !!cp->val;
1087
1088 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) == val) {
1089 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1090 goto failed;
1091 }
1092
1093 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1094 if (!cmd) {
1095 err = -ENOMEM;
1096 goto failed;
1097 }
1098
1099 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, sizeof(val), &val);
1100 if (err < 0) {
1101 mgmt_pending_remove(cmd);
1102 goto failed;
1103 }
1104
1105failed:
1106 hci_dev_unlock(hdev);
1107 hci_dev_put(hdev);
1108
1109 return err;
1110}
1111
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001112static int set_hs(struct sock *sk, u16 index, void *data, u16 len)
1113{
1114 struct mgmt_mode *cp = data;
1115 struct hci_dev *hdev;
1116 int err;
1117
1118 BT_DBG("request for hci%u", index);
1119
1120 if (len != sizeof(*cp))
1121 return cmd_status(sk, index, MGMT_OP_SET_HS,
1122 MGMT_STATUS_INVALID_PARAMS);
1123
1124 hdev = hci_dev_get(index);
1125 if (!hdev)
1126 return cmd_status(sk, index, MGMT_OP_SET_HS,
1127 MGMT_STATUS_INVALID_PARAMS);
1128
1129 if (!enable_hs) {
1130 err = cmd_status(sk, index, MGMT_OP_SET_HS,
1131 MGMT_STATUS_NOT_SUPPORTED);
1132 goto failed;
1133 }
1134
1135 if (cp->val)
1136 set_bit(HCI_HS_ENABLED, &hdev->dev_flags);
1137 else
1138 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
1139
1140 err = send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
1141
1142failed:
1143 hci_dev_put(hdev);
1144 return err;
1145}
1146
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001147static int add_uuid(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001148{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001149 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001150 struct hci_dev *hdev;
1151 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001152 int err;
1153
Szymon Janc4e51eae2011-02-25 19:05:48 +01001154 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001155
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001156 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001157 return cmd_status(sk, index, MGMT_OP_ADD_UUID,
1158 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001159
Szymon Janc4e51eae2011-02-25 19:05:48 +01001160 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001161 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001162 return cmd_status(sk, index, MGMT_OP_ADD_UUID,
1163 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001164
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001165 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001166
1167 uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC);
1168 if (!uuid) {
1169 err = -ENOMEM;
1170 goto failed;
1171 }
1172
1173 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001174 uuid->svc_hint = cp->svc_hint;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001175
1176 list_add(&uuid->list, &hdev->uuids);
1177
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001178 err = update_class(hdev);
1179 if (err < 0)
1180 goto failed;
1181
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001182 err = update_eir(hdev);
1183 if (err < 0)
1184 goto failed;
1185
Johan Hedbergaee9b212012-02-18 15:07:59 +02001186 err = cmd_complete(sk, index, MGMT_OP_ADD_UUID, 0, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001187
1188failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001189 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001190 hci_dev_put(hdev);
1191
1192 return err;
1193}
1194
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001195static int remove_uuid(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001196{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001197 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001198 struct list_head *p, *n;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001199 struct hci_dev *hdev;
1200 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 +02001201 int err, found;
1202
Szymon Janc4e51eae2011-02-25 19:05:48 +01001203 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001204
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001205 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001206 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
1207 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001208
Szymon Janc4e51eae2011-02-25 19:05:48 +01001209 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001210 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001211 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
1212 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001213
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001214 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001215
1216 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
1217 err = hci_uuids_clear(hdev);
1218 goto unlock;
1219 }
1220
1221 found = 0;
1222
1223 list_for_each_safe(p, n, &hdev->uuids) {
1224 struct bt_uuid *match = list_entry(p, struct bt_uuid, list);
1225
1226 if (memcmp(match->uuid, cp->uuid, 16) != 0)
1227 continue;
1228
1229 list_del(&match->list);
1230 found++;
1231 }
1232
1233 if (found == 0) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001234 err = cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
1235 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001236 goto unlock;
1237 }
1238
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001239 err = update_class(hdev);
1240 if (err < 0)
1241 goto unlock;
1242
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001243 err = update_eir(hdev);
1244 if (err < 0)
1245 goto unlock;
1246
Johan Hedbergaee9b212012-02-18 15:07:59 +02001247 err = cmd_complete(sk, index, MGMT_OP_REMOVE_UUID, 0, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001248
1249unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001250 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001251 hci_dev_put(hdev);
1252
1253 return err;
1254}
1255
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001256static int set_dev_class(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001257{
1258 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001259 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001260 int err;
1261
Szymon Janc4e51eae2011-02-25 19:05:48 +01001262 BT_DBG("request for hci%u", index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001263
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001264 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001265 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS,
1266 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001267
Szymon Janc4e51eae2011-02-25 19:05:48 +01001268 hdev = hci_dev_get(index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001269 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001270 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS,
1271 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001272
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001273 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001274
1275 hdev->major_class = cp->major;
1276 hdev->minor_class = cp->minor;
1277
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001278 if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02001279 hci_dev_unlock(hdev);
1280 cancel_delayed_work_sync(&hdev->service_cache);
1281 hci_dev_lock(hdev);
Johan Hedberg14c0b602011-12-15 00:47:37 +02001282 update_eir(hdev);
Johan Hedberg7d785252011-12-15 00:47:39 +02001283 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02001284
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001285 err = update_class(hdev);
1286
1287 if (err == 0)
Johan Hedbergaee9b212012-02-18 15:07:59 +02001288 err = cmd_complete(sk, index, MGMT_OP_SET_DEV_CLASS, 0,
1289 NULL, 0);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001290
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001291 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001292 hci_dev_put(hdev);
1293
1294 return err;
1295}
1296
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001297static int load_link_keys(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001298{
1299 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001300 struct mgmt_cp_load_link_keys *cp = data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001301 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001302 int i;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001303
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001304 if (len < sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001305 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1306 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001307
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001308 key_count = get_unaligned_le16(&cp->key_count);
1309
Johan Hedberg86742e12011-11-07 23:13:38 +02001310 expected_len = sizeof(*cp) + key_count *
1311 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001312 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001313 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001314 len, expected_len);
Johan Hedbergca69b792011-11-11 18:10:00 +02001315 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1316 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001317 }
1318
Szymon Janc4e51eae2011-02-25 19:05:48 +01001319 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001320 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001321 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1322 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001323
Szymon Janc4e51eae2011-02-25 19:05:48 +01001324 BT_DBG("hci%u debug_keys %u key_count %u", index, cp->debug_keys,
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001325 key_count);
1326
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001327 hci_dev_lock(hdev);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001328
1329 hci_link_keys_clear(hdev);
1330
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001331 set_bit(HCI_LINK_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001332
1333 if (cp->debug_keys)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001334 set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001335 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001336 clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001337
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001338 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001339 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001340
Johan Hedbergd753fdc2012-02-17 14:06:34 +02001341 hci_add_link_key(hdev, NULL, 0, &key->addr.bdaddr, key->val,
1342 key->type, key->pin_len);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001343 }
1344
Johan Hedbergaee9b212012-02-18 15:07:59 +02001345 cmd_complete(sk, index, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02001346
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001347 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001348 hci_dev_put(hdev);
1349
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001350 return 0;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001351}
1352
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001353static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
1354 u8 addr_type, struct sock *skip_sk)
1355{
1356 struct mgmt_ev_device_unpaired ev;
1357
1358 bacpy(&ev.addr.bdaddr, bdaddr);
1359 ev.addr.type = addr_type;
1360
1361 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
1362 skip_sk);
1363}
1364
Johan Hedberg124f6e32012-02-09 13:50:12 +02001365static int unpair_device(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001366{
1367 struct hci_dev *hdev;
Johan Hedberg124f6e32012-02-09 13:50:12 +02001368 struct mgmt_cp_unpair_device *cp = data;
1369 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001370 struct hci_cp_disconnect dc;
1371 struct pending_cmd *cmd;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001372 struct hci_conn *conn;
Johan Hedbergaee9b212012-02-18 15:07:59 +02001373 u8 status = 0;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001374 int err;
1375
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001376 if (len != sizeof(*cp))
Johan Hedberg124f6e32012-02-09 13:50:12 +02001377 return cmd_status(sk, index, MGMT_OP_UNPAIR_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02001378 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001379
Szymon Janc4e51eae2011-02-25 19:05:48 +01001380 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001381 if (!hdev)
Johan Hedberg124f6e32012-02-09 13:50:12 +02001382 return cmd_status(sk, index, MGMT_OP_UNPAIR_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02001383 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001384
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001385 hci_dev_lock(hdev);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001386
Johan Hedberga8a1d192011-11-10 15:54:38 +02001387 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02001388 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1389 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001390
Johan Hedberg124f6e32012-02-09 13:50:12 +02001391 if (cp->addr.type == MGMT_ADDR_BREDR)
1392 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
1393 else
1394 err = hci_remove_ltk(hdev, &cp->addr.bdaddr);
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03001395
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001396 if (err < 0) {
Johan Hedbergaee9b212012-02-18 15:07:59 +02001397 status = MGMT_STATUS_NOT_PAIRED;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001398 goto unlock;
1399 }
1400
Johan Hedberga8a1d192011-11-10 15:54:38 +02001401 if (!test_bit(HCI_UP, &hdev->flags) || !cp->disconnect) {
Johan Hedbergaee9b212012-02-18 15:07:59 +02001402 err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE, status,
1403 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001404 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001405 goto unlock;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001406 }
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001407
Johan Hedberg124f6e32012-02-09 13:50:12 +02001408 if (cp->addr.type == MGMT_ADDR_BREDR)
1409 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
1410 &cp->addr.bdaddr);
1411 else
1412 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
1413 &cp->addr.bdaddr);
1414
Johan Hedberga8a1d192011-11-10 15:54:38 +02001415 if (!conn) {
Johan Hedbergaee9b212012-02-18 15:07:59 +02001416 err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE, status,
1417 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001418 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001419 goto unlock;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001420 }
1421
Johan Hedberg124f6e32012-02-09 13:50:12 +02001422 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
1423 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02001424 if (!cmd) {
1425 err = -ENOMEM;
1426 goto unlock;
1427 }
1428
1429 put_unaligned_le16(conn->handle, &dc.handle);
1430 dc.reason = 0x13; /* Remote User Terminated Connection */
1431 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1432 if (err < 0)
1433 mgmt_pending_remove(cmd);
1434
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001435unlock:
Johan Hedbergca69b792011-11-11 18:10:00 +02001436 if (err < 0)
Johan Hedbergaee9b212012-02-18 15:07:59 +02001437 err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE, status,
1438 &rp, sizeof(rp));
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001439 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001440 hci_dev_put(hdev);
1441
1442 return err;
1443}
1444
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001445static int disconnect(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02001446{
1447 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001448 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001449 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03001450 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001451 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001452 int err;
1453
1454 BT_DBG("");
1455
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001456 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001457 return cmd_status(sk, index, MGMT_OP_DISCONNECT,
1458 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001459
Szymon Janc4e51eae2011-02-25 19:05:48 +01001460 hdev = hci_dev_get(index);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001461 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001462 return cmd_status(sk, index, MGMT_OP_DISCONNECT,
1463 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001464
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001465 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001466
1467 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001468 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1469 MGMT_STATUS_NOT_POWERED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001470 goto failed;
1471 }
1472
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001473 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001474 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1475 MGMT_STATUS_BUSY);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001476 goto failed;
1477 }
1478
Johan Hedberg88c3df12012-02-09 14:27:38 +02001479 if (cp->addr.type == MGMT_ADDR_BREDR)
1480 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
1481 else
1482 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03001483
Johan Hedberg8962ee72011-01-20 12:40:27 +02001484 if (!conn) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001485 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1486 MGMT_STATUS_NOT_CONNECTED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001487 goto failed;
1488 }
1489
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001490 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001491 if (!cmd) {
1492 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001493 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001494 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001495
1496 put_unaligned_le16(conn->handle, &dc.handle);
1497 dc.reason = 0x13; /* Remote User Terminated Connection */
1498
1499 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1500 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001501 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001502
1503failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001504 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001505 hci_dev_put(hdev);
1506
1507 return err;
1508}
1509
Johan Hedberg48264f02011-11-09 13:58:58 +02001510static u8 link_to_mgmt(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02001511{
1512 switch (link_type) {
1513 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02001514 switch (addr_type) {
1515 case ADDR_LE_DEV_PUBLIC:
1516 return MGMT_ADDR_LE_PUBLIC;
1517 case ADDR_LE_DEV_RANDOM:
1518 return MGMT_ADDR_LE_RANDOM;
1519 default:
1520 return MGMT_ADDR_INVALID;
1521 }
Johan Hedberg4c659c32011-11-07 23:13:39 +02001522 case ACL_LINK:
1523 return MGMT_ADDR_BREDR;
1524 default:
1525 return MGMT_ADDR_INVALID;
1526 }
1527}
1528
Szymon Janc8ce62842011-03-01 16:55:32 +01001529static int get_connections(struct sock *sk, u16 index)
Johan Hedberg2784eb42011-01-21 13:56:35 +02001530{
Johan Hedberg2784eb42011-01-21 13:56:35 +02001531 struct mgmt_rp_get_connections *rp;
1532 struct hci_dev *hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001533 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02001534 size_t rp_len;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001535 u16 count;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001536 int i, err;
1537
1538 BT_DBG("");
1539
Szymon Janc4e51eae2011-02-25 19:05:48 +01001540 hdev = hci_dev_get(index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001541 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001542 return cmd_status(sk, index, MGMT_OP_GET_CONNECTIONS,
1543 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001544
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001545 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001546
1547 count = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02001548 list_for_each_entry(c, &hdev->conn_hash.list, list) {
1549 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
1550 count++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001551 }
1552
Johan Hedberg4c659c32011-11-07 23:13:39 +02001553 rp_len = sizeof(*rp) + (count * sizeof(struct mgmt_addr_info));
Johan Hedberga38528f2011-01-22 06:46:43 +02001554 rp = kmalloc(rp_len, GFP_ATOMIC);
1555 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02001556 err = -ENOMEM;
1557 goto unlock;
1558 }
1559
Johan Hedberg2784eb42011-01-21 13:56:35 +02001560 put_unaligned_le16(count, &rp->conn_count);
1561
Johan Hedberg2784eb42011-01-21 13:56:35 +02001562 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001563 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02001564 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
1565 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001566 bacpy(&rp->addr[i].bdaddr, &c->dst);
Johan Hedberg48264f02011-11-09 13:58:58 +02001567 rp->addr[i].type = link_to_mgmt(c->type, c->dst_type);
Johan Hedberg4c659c32011-11-07 23:13:39 +02001568 if (rp->addr[i].type == MGMT_ADDR_INVALID)
1569 continue;
1570 i++;
1571 }
1572
1573 /* Recalculate length in case of filtered SCO connections, etc */
1574 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02001575
Johan Hedbergaee9b212012-02-18 15:07:59 +02001576 err = cmd_complete(sk, index, MGMT_OP_GET_CONNECTIONS, 0, rp, rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001577
1578unlock:
Johan Hedberga38528f2011-01-22 06:46:43 +02001579 kfree(rp);
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001580 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001581 hci_dev_put(hdev);
1582 return err;
1583}
1584
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001585static int send_pin_code_neg_reply(struct sock *sk, u16 index,
1586 struct hci_dev *hdev, struct mgmt_cp_pin_code_neg_reply *cp)
1587{
1588 struct pending_cmd *cmd;
1589 int err;
1590
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001591 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001592 sizeof(*cp));
1593 if (!cmd)
1594 return -ENOMEM;
1595
Johan Hedbergd8457692012-02-17 14:24:57 +02001596 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
1597 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001598 if (err < 0)
1599 mgmt_pending_remove(cmd);
1600
1601 return err;
1602}
1603
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001604static int pin_code_reply(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001605{
1606 struct hci_dev *hdev;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001607 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001608 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001609 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03001610 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001611 int err;
1612
1613 BT_DBG("");
1614
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001615 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001616 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1617 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001618
Szymon Janc4e51eae2011-02-25 19:05:48 +01001619 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001620 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001621 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1622 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001623
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001624 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001625
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001626 if (!hdev_is_powered(hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001627 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1628 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001629 goto failed;
1630 }
1631
Johan Hedbergd8457692012-02-17 14:24:57 +02001632 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001633 if (!conn) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001634 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1635 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001636 goto failed;
1637 }
1638
1639 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02001640 struct mgmt_cp_pin_code_neg_reply ncp;
1641
1642 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001643
1644 BT_ERR("PIN code is not 16 bytes long");
1645
1646 err = send_pin_code_neg_reply(sk, index, hdev, &ncp);
1647 if (err >= 0)
1648 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001649 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001650
1651 goto failed;
1652 }
1653
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001654 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data,
1655 len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001656 if (!cmd) {
1657 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001658 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001659 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02001660
Johan Hedbergd8457692012-02-17 14:24:57 +02001661 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001662 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02001663 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02001664
1665 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
1666 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001667 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001668
1669failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001670 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001671 hci_dev_put(hdev);
1672
1673 return err;
1674}
1675
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001676static int pin_code_neg_reply(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001677{
1678 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001679 struct mgmt_cp_pin_code_neg_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001680 int err;
1681
1682 BT_DBG("");
1683
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001684 if (len != sizeof(*cp))
1685 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001686 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001687
Szymon Janc4e51eae2011-02-25 19:05:48 +01001688 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001689 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001690 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001691 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001692
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001693 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001694
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001695 if (!hdev_is_powered(hdev)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001696 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001697 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001698 goto failed;
1699 }
1700
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001701 err = send_pin_code_neg_reply(sk, index, hdev, cp);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001702
1703failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001704 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001705 hci_dev_put(hdev);
1706
1707 return err;
1708}
1709
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001710static int set_io_capability(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001711{
1712 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001713 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001714
1715 BT_DBG("");
1716
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001717 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001718 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY,
1719 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001720
Szymon Janc4e51eae2011-02-25 19:05:48 +01001721 hdev = hci_dev_get(index);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001722 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001723 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY,
1724 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001725
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001726 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001727
1728 hdev->io_capability = cp->io_capability;
1729
1730 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Szymon Jancb8534e02011-03-01 16:55:34 +01001731 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001732
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001733 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001734 hci_dev_put(hdev);
1735
Johan Hedbergaee9b212012-02-18 15:07:59 +02001736 return cmd_complete(sk, index, MGMT_OP_SET_IO_CAPABILITY, 0, NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001737}
1738
Johan Hedberge9a416b2011-02-19 12:05:56 -03001739static inline struct pending_cmd *find_pairing(struct hci_conn *conn)
1740{
1741 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001742 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001743
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001744 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03001745 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
1746 continue;
1747
Johan Hedberge9a416b2011-02-19 12:05:56 -03001748 if (cmd->user_data != conn)
1749 continue;
1750
1751 return cmd;
1752 }
1753
1754 return NULL;
1755}
1756
1757static void pairing_complete(struct pending_cmd *cmd, u8 status)
1758{
1759 struct mgmt_rp_pair_device rp;
1760 struct hci_conn *conn = cmd->user_data;
1761
Johan Hedbergba4e5642011-11-11 00:07:34 +02001762 bacpy(&rp.addr.bdaddr, &conn->dst);
1763 rp.addr.type = link_to_mgmt(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001764
Johan Hedbergaee9b212012-02-18 15:07:59 +02001765 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, status,
1766 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001767
1768 /* So we don't get further callbacks for this connection */
1769 conn->connect_cfm_cb = NULL;
1770 conn->security_cfm_cb = NULL;
1771 conn->disconn_cfm_cb = NULL;
1772
1773 hci_conn_put(conn);
1774
Johan Hedberga664b5b2011-02-19 12:06:02 -03001775 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001776}
1777
1778static void pairing_complete_cb(struct hci_conn *conn, u8 status)
1779{
1780 struct pending_cmd *cmd;
1781
1782 BT_DBG("status %u", status);
1783
Johan Hedberg56e5cb82011-11-08 20:40:16 +02001784 cmd = find_pairing(conn);
1785 if (!cmd)
1786 BT_DBG("Unable to find a pending command");
1787 else
Johan Hedberge2113262012-02-18 15:20:03 +02001788 pairing_complete(cmd, mgmt_status(status));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001789}
1790
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001791static int pair_device(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001792{
1793 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001794 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02001795 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001796 struct pending_cmd *cmd;
1797 u8 sec_level, auth_type;
1798 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001799 int err;
1800
1801 BT_DBG("");
1802
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001803 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001804 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE,
1805 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001806
Szymon Janc4e51eae2011-02-25 19:05:48 +01001807 hdev = hci_dev_get(index);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001808 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001809 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE,
1810 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001811
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001812 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001813
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001814 sec_level = BT_SECURITY_MEDIUM;
1815 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001816 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001817 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03001818 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001819
Johan Hedbergba4e5642011-11-11 00:07:34 +02001820 if (cp->addr.type == MGMT_ADDR_BREDR)
1821 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr, sec_level,
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001822 auth_type);
1823 else
Johan Hedbergba4e5642011-11-11 00:07:34 +02001824 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr, sec_level,
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001825 auth_type);
1826
Johan Hedberg1425acb2011-11-11 00:07:35 +02001827 memset(&rp, 0, sizeof(rp));
1828 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1829 rp.addr.type = cp->addr.type;
1830
Ville Tervo30e76272011-02-22 16:10:53 -03001831 if (IS_ERR(conn)) {
Johan Hedberge2113262012-02-18 15:20:03 +02001832 err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE,
1833 MGMT_STATUS_CONNECT_FAILED,
1834 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001835 goto unlock;
1836 }
1837
1838 if (conn->connect_cfm_cb) {
1839 hci_conn_put(conn);
Johan Hedberge2113262012-02-18 15:20:03 +02001840 err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE,
1841 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001842 goto unlock;
1843 }
1844
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001845 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001846 if (!cmd) {
1847 err = -ENOMEM;
1848 hci_conn_put(conn);
1849 goto unlock;
1850 }
1851
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001852 /* For LE, just connecting isn't a proof that the pairing finished */
Johan Hedbergba4e5642011-11-11 00:07:34 +02001853 if (cp->addr.type == MGMT_ADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001854 conn->connect_cfm_cb = pairing_complete_cb;
1855
Johan Hedberge9a416b2011-02-19 12:05:56 -03001856 conn->security_cfm_cb = pairing_complete_cb;
1857 conn->disconn_cfm_cb = pairing_complete_cb;
1858 conn->io_capability = cp->io_cap;
1859 cmd->user_data = conn;
1860
1861 if (conn->state == BT_CONNECTED &&
1862 hci_conn_security(conn, sec_level, auth_type))
1863 pairing_complete(cmd, 0);
1864
1865 err = 0;
1866
1867unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001868 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001869 hci_dev_put(hdev);
1870
1871 return err;
1872}
1873
Johan Hedberg28424702012-02-02 04:02:29 +02001874static int cancel_pair_device(struct sock *sk, u16 index,
1875 unsigned char *data, u16 len)
1876{
1877 struct mgmt_addr_info *addr = (void *) data;
1878 struct hci_dev *hdev;
1879 struct pending_cmd *cmd;
1880 struct hci_conn *conn;
1881 int err;
1882
1883 BT_DBG("");
1884
1885 if (len != sizeof(*addr))
1886 return cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
1887 MGMT_STATUS_INVALID_PARAMS);
1888
1889 hdev = hci_dev_get(index);
1890 if (!hdev)
1891 return cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
1892 MGMT_STATUS_INVALID_PARAMS);
1893
1894 hci_dev_lock(hdev);
1895
1896 cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
1897 if (!cmd) {
1898 err = cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
1899 MGMT_STATUS_INVALID_PARAMS);
1900 goto unlock;
1901 }
1902
1903 conn = cmd->user_data;
1904
1905 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
1906 err = cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
1907 MGMT_STATUS_INVALID_PARAMS);
1908 goto unlock;
1909 }
1910
1911 pairing_complete(cmd, MGMT_STATUS_CANCELLED);
1912
Johan Hedbergaee9b212012-02-18 15:07:59 +02001913 err = cmd_complete(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE, 0, addr,
Johan Hedberg28424702012-02-02 04:02:29 +02001914 sizeof(*addr));
1915unlock:
1916 hci_dev_unlock(hdev);
1917 hci_dev_put(hdev);
1918
1919 return err;
1920}
1921
Brian Gix0df4c182011-11-16 13:53:13 -08001922static int user_pairing_resp(struct sock *sk, u16 index, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02001923 u8 type, u16 mgmt_op, u16 hci_op,
1924 __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03001925{
Johan Hedberga5c29682011-02-19 12:05:57 -03001926 struct pending_cmd *cmd;
1927 struct hci_dev *hdev;
Brian Gix0df4c182011-11-16 13:53:13 -08001928 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03001929 int err;
1930
Szymon Janc4e51eae2011-02-25 19:05:48 +01001931 hdev = hci_dev_get(index);
Johan Hedberga5c29682011-02-19 12:05:57 -03001932 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001933 return cmd_status(sk, index, mgmt_op,
1934 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga5c29682011-02-19 12:05:57 -03001935
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001936 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02001937
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001938 if (!hdev_is_powered(hdev)) {
Brian Gix0df4c182011-11-16 13:53:13 -08001939 err = cmd_status(sk, index, mgmt_op, MGMT_STATUS_NOT_POWERED);
1940 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03001941 }
1942
Johan Hedberg272d90d2012-02-09 15:26:12 +02001943 if (type == MGMT_ADDR_BREDR)
1944 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, bdaddr);
1945 else
Brian Gix47c15e22011-11-16 13:53:14 -08001946 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, bdaddr);
Brian Gix47c15e22011-11-16 13:53:14 -08001947
Johan Hedberg272d90d2012-02-09 15:26:12 +02001948 if (!conn) {
1949 err = cmd_status(sk, index, mgmt_op,
1950 MGMT_STATUS_NOT_CONNECTED);
1951 goto done;
1952 }
1953
1954 if (type == MGMT_ADDR_LE_PUBLIC || type == MGMT_ADDR_LE_RANDOM) {
Brian Gix47c15e22011-11-16 13:53:14 -08001955 /* Continue with pairing via SMP */
Brian Gix5fe57d92011-12-21 16:12:13 -08001956 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix47c15e22011-11-16 13:53:14 -08001957
Brian Gix5fe57d92011-12-21 16:12:13 -08001958 if (!err)
1959 err = cmd_status(sk, index, mgmt_op,
1960 MGMT_STATUS_SUCCESS);
1961 else
1962 err = cmd_status(sk, index, mgmt_op,
1963 MGMT_STATUS_FAILED);
1964
Brian Gix47c15e22011-11-16 13:53:14 -08001965 goto done;
1966 }
1967
Brian Gix0df4c182011-11-16 13:53:13 -08001968 cmd = mgmt_pending_add(sk, mgmt_op, hdev, bdaddr, sizeof(*bdaddr));
Johan Hedberga5c29682011-02-19 12:05:57 -03001969 if (!cmd) {
1970 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08001971 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03001972 }
1973
Brian Gix0df4c182011-11-16 13:53:13 -08001974 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08001975 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
1976 struct hci_cp_user_passkey_reply cp;
1977
1978 bacpy(&cp.bdaddr, bdaddr);
1979 cp.passkey = passkey;
1980 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
1981 } else
1982 err = hci_send_cmd(hdev, hci_op, sizeof(*bdaddr), bdaddr);
1983
Johan Hedberga664b5b2011-02-19 12:06:02 -03001984 if (err < 0)
1985 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03001986
Brian Gix0df4c182011-11-16 13:53:13 -08001987done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001988 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03001989 hci_dev_put(hdev);
1990
1991 return err;
1992}
1993
Brian Gix0df4c182011-11-16 13:53:13 -08001994static int user_confirm_reply(struct sock *sk, u16 index, void *data, u16 len)
1995{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001996 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08001997
1998 BT_DBG("");
1999
2000 if (len != sizeof(*cp))
2001 return cmd_status(sk, index, MGMT_OP_USER_CONFIRM_REPLY,
2002 MGMT_STATUS_INVALID_PARAMS);
2003
Johan Hedberg272d90d2012-02-09 15:26:12 +02002004 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
2005 MGMT_OP_USER_CONFIRM_REPLY,
2006 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002007}
2008
2009static int user_confirm_neg_reply(struct sock *sk, u16 index, void *data,
2010 u16 len)
2011{
Johan Hedbergc9c26592011-12-15 00:47:41 +02002012 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002013
2014 BT_DBG("");
2015
2016 if (len != sizeof(*cp))
2017 return cmd_status(sk, index, MGMT_OP_USER_CONFIRM_NEG_REPLY,
2018 MGMT_STATUS_INVALID_PARAMS);
2019
Johan Hedberg272d90d2012-02-09 15:26:12 +02002020 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
2021 MGMT_OP_USER_CONFIRM_NEG_REPLY,
2022 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002023}
2024
Brian Gix604086b2011-11-23 08:28:33 -08002025static int user_passkey_reply(struct sock *sk, u16 index, void *data, u16 len)
2026{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002027 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002028
2029 BT_DBG("");
2030
2031 if (len != sizeof(*cp))
2032 return cmd_status(sk, index, MGMT_OP_USER_PASSKEY_REPLY,
2033 EINVAL);
2034
Johan Hedberg272d90d2012-02-09 15:26:12 +02002035 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
2036 MGMT_OP_USER_PASSKEY_REPLY,
2037 HCI_OP_USER_PASSKEY_REPLY,
2038 cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08002039}
2040
2041static int user_passkey_neg_reply(struct sock *sk, u16 index, void *data,
2042 u16 len)
2043{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002044 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002045
2046 BT_DBG("");
2047
2048 if (len != sizeof(*cp))
2049 return cmd_status(sk, index, MGMT_OP_USER_PASSKEY_NEG_REPLY,
2050 EINVAL);
2051
Johan Hedberg272d90d2012-02-09 15:26:12 +02002052 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
2053 MGMT_OP_USER_PASSKEY_NEG_REPLY,
2054 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08002055}
2056
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002057static int set_local_name(struct sock *sk, u16 index, void *data,
Johan Hedbergb312b1612011-03-16 14:29:37 +02002058 u16 len)
2059{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002060 struct mgmt_cp_set_local_name *mgmt_cp = data;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002061 struct hci_cp_write_local_name hci_cp;
2062 struct hci_dev *hdev;
2063 struct pending_cmd *cmd;
2064 int err;
2065
2066 BT_DBG("");
2067
2068 if (len != sizeof(*mgmt_cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02002069 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME,
2070 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002071
2072 hdev = hci_dev_get(index);
2073 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002074 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME,
2075 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002076
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002077 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002078
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002079 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data,
2080 len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002081 if (!cmd) {
2082 err = -ENOMEM;
2083 goto failed;
2084 }
2085
2086 memcpy(hci_cp.name, mgmt_cp->name, sizeof(hci_cp.name));
2087 err = hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(hci_cp),
2088 &hci_cp);
2089 if (err < 0)
2090 mgmt_pending_remove(cmd);
2091
2092failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002093 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002094 hci_dev_put(hdev);
2095
2096 return err;
2097}
2098
Szymon Jancc35938b2011-03-22 13:12:21 +01002099static int read_local_oob_data(struct sock *sk, u16 index)
2100{
2101 struct hci_dev *hdev;
2102 struct pending_cmd *cmd;
2103 int err;
2104
2105 BT_DBG("hci%u", index);
2106
2107 hdev = hci_dev_get(index);
2108 if (!hdev)
2109 return cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002110 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancc35938b2011-03-22 13:12:21 +01002111
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002112 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002113
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002114 if (!hdev_is_powered(hdev)) {
Szymon Jancc35938b2011-03-22 13:12:21 +01002115 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002116 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002117 goto unlock;
2118 }
2119
2120 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
2121 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002122 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002123 goto unlock;
2124 }
2125
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002126 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02002127 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2128 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01002129 goto unlock;
2130 }
2131
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002132 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01002133 if (!cmd) {
2134 err = -ENOMEM;
2135 goto unlock;
2136 }
2137
2138 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
2139 if (err < 0)
2140 mgmt_pending_remove(cmd);
2141
2142unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002143 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002144 hci_dev_put(hdev);
2145
2146 return err;
2147}
2148
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002149static int add_remote_oob_data(struct sock *sk, u16 index, void *data,
2150 u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002151{
2152 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002153 struct mgmt_cp_add_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002154 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002155 int err;
2156
2157 BT_DBG("hci%u ", index);
2158
2159 if (len != sizeof(*cp))
2160 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002161 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01002162
2163 hdev = hci_dev_get(index);
2164 if (!hdev)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002165 return cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
2166 MGMT_STATUS_INVALID_PARAMS,
2167 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002168
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002169 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002170
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002171 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, cp->hash,
Szymon Janc2763eda2011-03-22 13:12:22 +01002172 cp->randomizer);
2173 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002174 status = MGMT_STATUS_FAILED;
Szymon Janc2763eda2011-03-22 13:12:22 +01002175 else
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002176 status = 0;
2177
2178 err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, status,
2179 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002180
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002181 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002182 hci_dev_put(hdev);
2183
2184 return err;
2185}
2186
2187static int remove_remote_oob_data(struct sock *sk, u16 index,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002188 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002189{
2190 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002191 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002192 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002193 int err;
2194
2195 BT_DBG("hci%u ", index);
2196
2197 if (len != sizeof(*cp))
2198 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002199 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01002200
2201 hdev = hci_dev_get(index);
2202 if (!hdev)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002203 return cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2204 MGMT_STATUS_INVALID_PARAMS,
2205 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002206
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002207 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002208
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002209 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr);
Szymon Janc2763eda2011-03-22 13:12:22 +01002210 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002211 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01002212 else
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002213 status = 0;
2214
2215 err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA, status,
2216 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002217
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002218 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002219 hci_dev_put(hdev);
2220
2221 return err;
2222}
2223
Andre Guedes5e0452c2012-02-17 20:39:38 -03002224static int discovery(struct hci_dev *hdev)
2225{
2226 int err;
2227
2228 if (lmp_host_le_capable(hdev)) {
2229 if (lmp_bredr_capable(hdev)) {
2230 err = hci_le_scan(hdev, LE_SCAN_TYPE,
2231 LE_SCAN_INT, LE_SCAN_WIN,
2232 LE_SCAN_TIMEOUT_BREDR_LE);
2233 } else {
2234 hdev->discovery.type = DISCOV_TYPE_LE;
2235 err = hci_le_scan(hdev, LE_SCAN_TYPE,
2236 LE_SCAN_INT, LE_SCAN_WIN,
2237 LE_SCAN_TIMEOUT_LE_ONLY);
2238 }
2239 } else {
2240 hdev->discovery.type = DISCOV_TYPE_BREDR;
2241 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
2242 }
2243
2244 return err;
2245}
2246
2247int mgmt_interleaved_discovery(struct hci_dev *hdev)
2248{
2249 int err;
2250
2251 BT_DBG("%s", hdev->name);
2252
2253 hci_dev_lock(hdev);
2254
2255 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR_LE);
2256 if (err < 0)
2257 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2258
2259 hci_dev_unlock(hdev);
2260
2261 return err;
2262}
2263
Johan Hedberg450dfda2011-11-12 11:58:22 +02002264static int start_discovery(struct sock *sk, u16 index,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002265 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002266{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002267 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002268 struct pending_cmd *cmd;
2269 struct hci_dev *hdev;
2270 int err;
2271
2272 BT_DBG("hci%u", index);
2273
Johan Hedberg450dfda2011-11-12 11:58:22 +02002274 if (len != sizeof(*cp))
2275 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2276 MGMT_STATUS_INVALID_PARAMS);
2277
Johan Hedberg14a53662011-04-27 10:29:56 -04002278 hdev = hci_dev_get(index);
2279 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002280 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2281 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg14a53662011-04-27 10:29:56 -04002282
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002283 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002284
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002285 if (!hdev_is_powered(hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02002286 err = cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2287 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02002288 goto failed;
2289 }
2290
Johan Hedbergff9ef572012-01-04 14:23:45 +02002291 if (hdev->discovery.state != DISCOVERY_STOPPED) {
2292 err = cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2293 MGMT_STATUS_BUSY);
2294 goto failed;
2295 }
2296
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002297 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002298 if (!cmd) {
2299 err = -ENOMEM;
2300 goto failed;
2301 }
2302
Andre Guedes4aab14e2012-02-17 20:39:36 -03002303 hdev->discovery.type = cp->type;
2304
2305 switch (hdev->discovery.type) {
Andre Guedesf39799f2012-02-17 20:39:35 -03002306 case DISCOV_TYPE_BREDR:
Andre Guedes3fd24152012-02-03 17:48:01 -03002307 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
Andre Guedesf39799f2012-02-17 20:39:35 -03002308 break;
2309
2310 case DISCOV_TYPE_LE:
Andre Guedes3fd24152012-02-03 17:48:01 -03002311 err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT,
2312 LE_SCAN_WIN, LE_SCAN_TIMEOUT_LE_ONLY);
Andre Guedesf39799f2012-02-17 20:39:35 -03002313 break;
2314
Andre Guedes5e0452c2012-02-17 20:39:38 -03002315 case DISCOV_TYPE_INTERLEAVED:
2316 err = discovery(hdev);
2317 break;
2318
Andre Guedesf39799f2012-02-17 20:39:35 -03002319 default:
Andre Guedes3fd24152012-02-03 17:48:01 -03002320 err = -EINVAL;
Andre Guedesf39799f2012-02-17 20:39:35 -03002321 }
Andre Guedes3fd24152012-02-03 17:48:01 -03002322
Johan Hedberg14a53662011-04-27 10:29:56 -04002323 if (err < 0)
2324 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002325 else
2326 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002327
2328failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002329 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002330 hci_dev_put(hdev);
2331
2332 return err;
2333}
2334
Johan Hedbergd9306502012-02-20 23:25:18 +02002335static int stop_discovery(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002336{
Johan Hedbergd9306502012-02-20 23:25:18 +02002337 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002338 struct hci_dev *hdev;
2339 struct pending_cmd *cmd;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002340 struct hci_cp_remote_name_req_cancel cp;
2341 struct inquiry_entry *e;
Johan Hedberg14a53662011-04-27 10:29:56 -04002342 int err;
2343
2344 BT_DBG("hci%u", index);
2345
Johan Hedbergd9306502012-02-20 23:25:18 +02002346 if (len != sizeof(*mgmt_cp))
2347 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY,
2348 MGMT_STATUS_INVALID_PARAMS);
2349
Johan Hedberg14a53662011-04-27 10:29:56 -04002350 hdev = hci_dev_get(index);
2351 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002352 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY,
2353 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg14a53662011-04-27 10:29:56 -04002354
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002355 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002356
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002357 if (!hci_discovery_active(hdev)) {
Johan Hedbergd9306502012-02-20 23:25:18 +02002358 err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY,
2359 MGMT_STATUS_REJECTED,
2360 &mgmt_cp->type, sizeof(mgmt_cp->type));
2361 goto unlock;
2362 }
2363
2364 if (hdev->discovery.type != mgmt_cp->type) {
2365 err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY,
2366 MGMT_STATUS_INVALID_PARAMS,
2367 &mgmt_cp->type, sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002368 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02002369 }
2370
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002371 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002372 if (!cmd) {
2373 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002374 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04002375 }
2376
Andre Guedes343f9352012-02-17 20:39:37 -03002377 if (hdev->discovery.state == DISCOVERY_FINDING) {
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002378 err = hci_cancel_inquiry(hdev);
2379 if (err < 0)
2380 mgmt_pending_remove(cmd);
2381 else
2382 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
2383 goto unlock;
2384 }
2385
2386 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY, NAME_PENDING);
2387 if (!e) {
2388 mgmt_pending_remove(cmd);
Johan Hedbergaee9b212012-02-18 15:07:59 +02002389 err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY, 0,
Johan Hedbergd9306502012-02-20 23:25:18 +02002390 &mgmt_cp->type, sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002391 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2392 goto unlock;
2393 }
2394
2395 bacpy(&cp.bdaddr, &e->data.bdaddr);
2396 err = hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ_CANCEL,
2397 sizeof(cp), &cp);
Johan Hedberg14a53662011-04-27 10:29:56 -04002398 if (err < 0)
2399 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002400 else
2401 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002402
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002403unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002404 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002405 hci_dev_put(hdev);
2406
2407 return err;
2408}
2409
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002410static int confirm_name(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02002411{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002412 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002413 struct inquiry_entry *e;
2414 struct hci_dev *hdev;
2415 int err;
2416
2417 BT_DBG("hci%u", index);
2418
2419 if (len != sizeof(*cp))
2420 return cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2421 MGMT_STATUS_INVALID_PARAMS);
2422
2423 hdev = hci_dev_get(index);
2424 if (!hdev)
2425 return cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2426 MGMT_STATUS_INVALID_PARAMS);
2427
2428 hci_dev_lock(hdev);
2429
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002430 if (!hci_discovery_active(hdev)) {
2431 err = cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2432 MGMT_STATUS_FAILED);
2433 goto failed;
2434 }
2435
Johan Hedberga198e7b2012-02-17 14:27:06 +02002436 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002437 if (!e) {
2438 err = cmd_status (sk, index, MGMT_OP_CONFIRM_NAME,
2439 MGMT_STATUS_INVALID_PARAMS);
2440 goto failed;
2441 }
2442
2443 if (cp->name_known) {
2444 e->name_state = NAME_KNOWN;
2445 list_del(&e->list);
2446 } else {
2447 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e202012-01-09 00:53:02 +02002448 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002449 }
2450
2451 err = 0;
2452
2453failed:
2454 hci_dev_unlock(hdev);
2455
2456 return err;
2457}
2458
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002459static int block_device(struct sock *sk, u16 index, void *data, u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002460{
2461 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002462 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002463 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03002464 int err;
2465
2466 BT_DBG("hci%u", index);
2467
Antti Julku7fbec222011-06-15 12:01:15 +03002468 if (len != sizeof(*cp))
2469 return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002470 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002471
2472 hdev = hci_dev_get(index);
2473 if (!hdev)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002474 return cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE,
2475 MGMT_STATUS_INVALID_PARAMS,
2476 &cp->addr, sizeof(cp->addr));
Antti Julku7fbec222011-06-15 12:01:15 +03002477
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002478 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002479
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002480 err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002481 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002482 status = MGMT_STATUS_FAILED;
Antti Julku7fbec222011-06-15 12:01:15 +03002483 else
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002484 status = 0;
2485
2486 err = cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE, status,
2487 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03002488
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002489 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002490 hci_dev_put(hdev);
2491
2492 return err;
2493}
2494
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002495static int unblock_device(struct sock *sk, u16 index, void *data, u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002496{
2497 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002498 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002499 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03002500 int err;
2501
2502 BT_DBG("hci%u", index);
2503
Antti Julku7fbec222011-06-15 12:01:15 +03002504 if (len != sizeof(*cp))
2505 return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002506 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002507
2508 hdev = hci_dev_get(index);
2509 if (!hdev)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002510 return cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE,
2511 MGMT_STATUS_INVALID_PARAMS,
2512 &cp->addr, sizeof(cp->addr));
Antti Julku7fbec222011-06-15 12:01:15 +03002513
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002514 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002515
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002516 err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002517 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002518 status = MGMT_STATUS_INVALID_PARAMS;
Antti Julku7fbec222011-06-15 12:01:15 +03002519 else
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002520 status = 0;
2521
2522 err = cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE, status,
2523 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03002524
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002525 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002526 hci_dev_put(hdev);
2527
2528 return err;
2529}
2530
Antti Julkuf6422ec2011-06-22 13:11:56 +03002531static int set_fast_connectable(struct sock *sk, u16 index,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002532 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03002533{
2534 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002535 struct mgmt_mode *cp = data;
Antti Julkuf6422ec2011-06-22 13:11:56 +03002536 struct hci_cp_write_page_scan_activity acp;
2537 u8 type;
2538 int err;
2539
2540 BT_DBG("hci%u", index);
2541
2542 if (len != sizeof(*cp))
2543 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002544 MGMT_STATUS_INVALID_PARAMS);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002545
2546 hdev = hci_dev_get(index);
2547 if (!hdev)
2548 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002549 MGMT_STATUS_INVALID_PARAMS);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002550
2551 hci_dev_lock(hdev);
2552
Johan Hedbergf7c68692011-12-15 00:47:36 +02002553 if (cp->val) {
Antti Julkuf6422ec2011-06-22 13:11:56 +03002554 type = PAGE_SCAN_TYPE_INTERLACED;
2555 acp.interval = 0x0024; /* 22.5 msec page scan interval */
2556 } else {
2557 type = PAGE_SCAN_TYPE_STANDARD; /* default */
2558 acp.interval = 0x0800; /* default 1.28 sec page scan */
2559 }
2560
2561 acp.window = 0x0012; /* default 11.25 msec page scan window */
2562
2563 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
2564 sizeof(acp), &acp);
2565 if (err < 0) {
2566 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002567 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002568 goto done;
2569 }
2570
2571 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
2572 if (err < 0) {
2573 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002574 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002575 goto done;
2576 }
2577
Johan Hedbergaee9b212012-02-18 15:07:59 +02002578 err = cmd_complete(sk, index, MGMT_OP_SET_FAST_CONNECTABLE, 0,
2579 NULL, 0);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002580done:
2581 hci_dev_unlock(hdev);
2582 hci_dev_put(hdev);
2583
2584 return err;
2585}
2586
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002587static int load_long_term_keys(struct sock *sk, u16 index,
2588 void *cp_data, u16 len)
2589{
2590 struct hci_dev *hdev;
2591 struct mgmt_cp_load_long_term_keys *cp = cp_data;
2592 u16 key_count, expected_len;
2593 int i;
2594
2595 if (len < sizeof(*cp))
2596 return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS,
2597 EINVAL);
2598
2599 key_count = get_unaligned_le16(&cp->key_count);
2600
2601 expected_len = sizeof(*cp) + key_count *
2602 sizeof(struct mgmt_ltk_info);
2603 if (expected_len != len) {
2604 BT_ERR("load_keys: expected %u bytes, got %u bytes",
2605 len, expected_len);
2606 return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS,
2607 EINVAL);
2608 }
2609
2610 hdev = hci_dev_get(index);
2611 if (!hdev)
2612 return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS,
2613 ENODEV);
2614
2615 BT_DBG("hci%u key_count %u", index, key_count);
2616
2617 hci_dev_lock(hdev);
2618
2619 hci_smp_ltks_clear(hdev);
2620
2621 for (i = 0; i < key_count; i++) {
2622 struct mgmt_ltk_info *key = &cp->keys[i];
2623 u8 type;
2624
2625 if (key->master)
2626 type = HCI_SMP_LTK;
2627 else
2628 type = HCI_SMP_LTK_SLAVE;
2629
2630 hci_add_ltk(hdev, &key->addr.bdaddr, key->addr.type,
2631 type, 0, key->authenticated, key->val,
2632 key->enc_size, key->ediv, key->rand);
2633 }
2634
2635 hci_dev_unlock(hdev);
2636 hci_dev_put(hdev);
2637
2638 return 0;
2639}
2640
Johan Hedberg03811012010-12-08 00:21:06 +02002641int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
2642{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002643 void *buf;
2644 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02002645 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002646 u16 opcode, index, len;
Johan Hedberg03811012010-12-08 00:21:06 +02002647 int err;
2648
2649 BT_DBG("got %zu bytes", msglen);
2650
2651 if (msglen < sizeof(*hdr))
2652 return -EINVAL;
2653
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03002654 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02002655 if (!buf)
2656 return -ENOMEM;
2657
2658 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
2659 err = -EFAULT;
2660 goto done;
2661 }
2662
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002663 hdr = buf;
Johan Hedberg03811012010-12-08 00:21:06 +02002664 opcode = get_unaligned_le16(&hdr->opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002665 index = get_unaligned_le16(&hdr->index);
Johan Hedberg03811012010-12-08 00:21:06 +02002666 len = get_unaligned_le16(&hdr->len);
2667
2668 if (len != msglen - sizeof(*hdr)) {
2669 err = -EINVAL;
2670 goto done;
2671 }
2672
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002673 cp = buf + sizeof(*hdr);
2674
Johan Hedberg03811012010-12-08 00:21:06 +02002675 switch (opcode) {
Johan Hedberg02d98122010-12-13 21:07:04 +02002676 case MGMT_OP_READ_VERSION:
2677 err = read_version(sk);
2678 break;
Johan Hedberge70bb2e2012-02-13 16:59:33 +02002679 case MGMT_OP_READ_COMMANDS:
2680 err = read_commands(sk);
2681 break;
Johan Hedbergfaba42e2010-12-13 21:07:05 +02002682 case MGMT_OP_READ_INDEX_LIST:
2683 err = read_index_list(sk);
2684 break;
Johan Hedbergf7b64e62010-12-13 21:07:06 +02002685 case MGMT_OP_READ_INFO:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002686 err = read_controller_info(sk, index);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02002687 break;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002688 case MGMT_OP_SET_POWERED:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002689 err = set_powered(sk, index, cp, len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002690 break;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002691 case MGMT_OP_SET_DISCOVERABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002692 err = set_discoverable(sk, index, cp, len);
Johan Hedberg73f22f62010-12-29 16:00:25 +02002693 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002694 case MGMT_OP_SET_CONNECTABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002695 err = set_connectable(sk, index, cp, len);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002696 break;
Johan Hedbergf7c68692011-12-15 00:47:36 +02002697 case MGMT_OP_SET_FAST_CONNECTABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002698 err = set_fast_connectable(sk, index, cp, len);
Johan Hedbergf7c68692011-12-15 00:47:36 +02002699 break;
Johan Hedbergc542a062011-01-26 13:11:03 +02002700 case MGMT_OP_SET_PAIRABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002701 err = set_pairable(sk, index, cp, len);
Johan Hedbergc542a062011-01-26 13:11:03 +02002702 break;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02002703 case MGMT_OP_SET_LINK_SECURITY:
2704 err = set_link_security(sk, index, cp, len);
2705 break;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02002706 case MGMT_OP_SET_SSP:
2707 err = set_ssp(sk, index, cp, len);
2708 break;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02002709 case MGMT_OP_SET_HS:
2710 err = set_hs(sk, index, cp, len);
2711 break;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002712 case MGMT_OP_ADD_UUID:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002713 err = add_uuid(sk, index, cp, len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002714 break;
2715 case MGMT_OP_REMOVE_UUID:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002716 err = remove_uuid(sk, index, cp, len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002717 break;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002718 case MGMT_OP_SET_DEV_CLASS:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002719 err = set_dev_class(sk, index, cp, len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002720 break;
Johan Hedberg86742e12011-11-07 23:13:38 +02002721 case MGMT_OP_LOAD_LINK_KEYS:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002722 err = load_link_keys(sk, index, cp, len);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002723 break;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002724 case MGMT_OP_DISCONNECT:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002725 err = disconnect(sk, index, cp, len);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002726 break;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002727 case MGMT_OP_GET_CONNECTIONS:
Szymon Janc8ce62842011-03-01 16:55:32 +01002728 err = get_connections(sk, index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002729 break;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002730 case MGMT_OP_PIN_CODE_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002731 err = pin_code_reply(sk, index, cp, len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002732 break;
2733 case MGMT_OP_PIN_CODE_NEG_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002734 err = pin_code_neg_reply(sk, index, cp, len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002735 break;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002736 case MGMT_OP_SET_IO_CAPABILITY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002737 err = set_io_capability(sk, index, cp, len);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002738 break;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002739 case MGMT_OP_PAIR_DEVICE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002740 err = pair_device(sk, index, cp, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002741 break;
Johan Hedberg28424702012-02-02 04:02:29 +02002742 case MGMT_OP_CANCEL_PAIR_DEVICE:
2743 err = cancel_pair_device(sk, index, buf + sizeof(*hdr), len);
2744 break;
Johan Hedberg124f6e32012-02-09 13:50:12 +02002745 case MGMT_OP_UNPAIR_DEVICE:
2746 err = unpair_device(sk, index, cp, len);
2747 break;
Johan Hedberga5c29682011-02-19 12:05:57 -03002748 case MGMT_OP_USER_CONFIRM_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002749 err = user_confirm_reply(sk, index, cp, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03002750 break;
2751 case MGMT_OP_USER_CONFIRM_NEG_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002752 err = user_confirm_neg_reply(sk, index, cp, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03002753 break;
Brian Gix604086b2011-11-23 08:28:33 -08002754 case MGMT_OP_USER_PASSKEY_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002755 err = user_passkey_reply(sk, index, cp, len);
Brian Gix604086b2011-11-23 08:28:33 -08002756 break;
2757 case MGMT_OP_USER_PASSKEY_NEG_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002758 err = user_passkey_neg_reply(sk, index, cp, len);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002759 break;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002760 case MGMT_OP_SET_LOCAL_NAME:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002761 err = set_local_name(sk, index, cp, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002762 break;
Szymon Jancc35938b2011-03-22 13:12:21 +01002763 case MGMT_OP_READ_LOCAL_OOB_DATA:
2764 err = read_local_oob_data(sk, index);
2765 break;
Szymon Janc2763eda2011-03-22 13:12:22 +01002766 case MGMT_OP_ADD_REMOTE_OOB_DATA:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002767 err = add_remote_oob_data(sk, index, cp, len);
Szymon Janc2763eda2011-03-22 13:12:22 +01002768 break;
2769 case MGMT_OP_REMOVE_REMOTE_OOB_DATA:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002770 err = remove_remote_oob_data(sk, index, cp, len);
Szymon Janc2763eda2011-03-22 13:12:22 +01002771 break;
Johan Hedberg14a53662011-04-27 10:29:56 -04002772 case MGMT_OP_START_DISCOVERY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002773 err = start_discovery(sk, index, cp, len);
Johan Hedberg14a53662011-04-27 10:29:56 -04002774 break;
2775 case MGMT_OP_STOP_DISCOVERY:
Johan Hedbergd9306502012-02-20 23:25:18 +02002776 err = stop_discovery(sk, index, cp, len);
Johan Hedberg14a53662011-04-27 10:29:56 -04002777 break;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002778 case MGMT_OP_CONFIRM_NAME:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002779 err = confirm_name(sk, index, cp, len);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002780 break;
Antti Julku7fbec222011-06-15 12:01:15 +03002781 case MGMT_OP_BLOCK_DEVICE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002782 err = block_device(sk, index, cp, len);
Antti Julku7fbec222011-06-15 12:01:15 +03002783 break;
2784 case MGMT_OP_UNBLOCK_DEVICE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002785 err = unblock_device(sk, index, cp, len);
Antti Julku7fbec222011-06-15 12:01:15 +03002786 break;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002787 case MGMT_OP_LOAD_LONG_TERM_KEYS:
2788 err = load_long_term_keys(sk, index, cp, len);
2789 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002790 default:
Johan Hedberg72a734e2010-12-30 00:38:22 +02002791 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02002792 err = cmd_status(sk, index, opcode,
2793 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002794 break;
2795 }
Johan Hedberg72a734e2010-12-30 00:38:22 +02002796
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002797 if (err < 0)
Johan Hedberg72a734e2010-12-30 00:38:22 +02002798 goto done;
2799
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002800 err = msglen;
2801
2802done:
2803 kfree(buf);
2804 return err;
2805}
2806
Johan Hedbergb24752f2011-11-03 14:40:33 +02002807static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
2808{
2809 u8 *status = data;
2810
2811 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
2812 mgmt_pending_remove(cmd);
2813}
2814
Johan Hedberg744cf192011-11-08 20:40:14 +02002815int mgmt_index_added(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +02002816{
Johan Hedberg744cf192011-11-08 20:40:14 +02002817 return mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02002818}
2819
Johan Hedberg744cf192011-11-08 20:40:14 +02002820int mgmt_index_removed(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +02002821{
Johan Hedbergb24752f2011-11-03 14:40:33 +02002822 u8 status = ENODEV;
2823
Johan Hedberg744cf192011-11-08 20:40:14 +02002824 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002825
Johan Hedberg744cf192011-11-08 20:40:14 +02002826 return mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02002827}
2828
2829struct cmd_lookup {
Johan Hedberg03811012010-12-08 00:21:06 +02002830 struct sock *sk;
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002831 struct hci_dev *hdev;
Johan Hedberg03811012010-12-08 00:21:06 +02002832};
2833
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002834static void settings_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberg03811012010-12-08 00:21:06 +02002835{
Johan Hedberg03811012010-12-08 00:21:06 +02002836 struct cmd_lookup *match = data;
2837
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002838 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02002839
2840 list_del(&cmd->list);
2841
2842 if (match->sk == NULL) {
2843 match->sk = cmd->sk;
2844 sock_hold(match->sk);
2845 }
2846
2847 mgmt_pending_free(cmd);
2848}
2849
Johan Hedberg744cf192011-11-08 20:40:14 +02002850int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg03811012010-12-08 00:21:06 +02002851{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002852 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002853 __le32 ev;
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002854 int err;
Johan Hedberg03811012010-12-08 00:21:06 +02002855
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002856 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
Johan Hedberg03811012010-12-08 00:21:06 +02002857
Johan Hedbergb24752f2011-11-03 14:40:33 +02002858 if (!powered) {
2859 u8 status = ENETDOWN;
Johan Hedberg744cf192011-11-08 20:40:14 +02002860 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002861 }
2862
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002863 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg03811012010-12-08 00:21:06 +02002864
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002865 err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev),
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002866 match.sk);
Johan Hedberg03811012010-12-08 00:21:06 +02002867
2868 if (match.sk)
2869 sock_put(match.sk);
2870
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002871 return err;
Johan Hedberg03811012010-12-08 00:21:06 +02002872}
2873
Johan Hedberg744cf192011-11-08 20:40:14 +02002874int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg03811012010-12-08 00:21:06 +02002875{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002876 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002877 __le32 ev;
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002878 int err;
Johan Hedberg03811012010-12-08 00:21:06 +02002879
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002880 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp, &match);
Johan Hedberg03811012010-12-08 00:21:06 +02002881
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002882 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg03811012010-12-08 00:21:06 +02002883
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002884 err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01002885 match.sk);
Johan Hedberg03811012010-12-08 00:21:06 +02002886 if (match.sk)
2887 sock_put(match.sk);
2888
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002889 return err;
Johan Hedberg03811012010-12-08 00:21:06 +02002890}
2891
Johan Hedberg744cf192011-11-08 20:40:14 +02002892int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg03811012010-12-08 00:21:06 +02002893{
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002894 __le32 ev;
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002895 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002896 int err;
Johan Hedberg03811012010-12-08 00:21:06 +02002897
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002898 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev, settings_rsp,
2899 &match);
Johan Hedberg03811012010-12-08 00:21:06 +02002900
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002901 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg03811012010-12-08 00:21:06 +02002902
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002903 err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), match.sk);
Johan Hedberg03811012010-12-08 00:21:06 +02002904
2905 if (match.sk)
2906 sock_put(match.sk);
2907
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002908 return err;
Johan Hedberg03811012010-12-08 00:21:06 +02002909}
2910
Johan Hedberg744cf192011-11-08 20:40:14 +02002911int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002912{
Johan Hedbergca69b792011-11-11 18:10:00 +02002913 u8 mgmt_err = mgmt_status(status);
2914
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002915 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02002916 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Johan Hedbergca69b792011-11-11 18:10:00 +02002917 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002918
2919 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02002920 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Johan Hedbergca69b792011-11-11 18:10:00 +02002921 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002922
2923 return 0;
2924}
2925
Johan Hedberg744cf192011-11-08 20:40:14 +02002926int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
2927 u8 persistent)
Johan Hedberg03811012010-12-08 00:21:06 +02002928{
Johan Hedberg86742e12011-11-07 23:13:38 +02002929 struct mgmt_ev_new_link_key ev;
Johan Hedberg03811012010-12-08 00:21:06 +02002930
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002931 memset(&ev, 0, sizeof(ev));
Johan Hedberg03811012010-12-08 00:21:06 +02002932
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002933 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02002934 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
2935 ev.key.addr.type = MGMT_ADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002936 ev.key.type = key->type;
2937 memcpy(ev.key.val, key->val, 16);
2938 ev.key.pin_len = key->pin_len;
Johan Hedberg03811012010-12-08 00:21:06 +02002939
Johan Hedberg744cf192011-11-08 20:40:14 +02002940 return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02002941}
Johan Hedbergf7520542011-01-20 12:34:39 +02002942
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002943int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
2944{
2945 struct mgmt_ev_new_long_term_key ev;
2946
2947 memset(&ev, 0, sizeof(ev));
2948
2949 ev.store_hint = persistent;
2950 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
2951 ev.key.addr.type = key->bdaddr_type;
2952 ev.key.authenticated = key->authenticated;
2953 ev.key.enc_size = key->enc_size;
2954 ev.key.ediv = key->ediv;
2955
2956 if (key->type == HCI_SMP_LTK)
2957 ev.key.master = 1;
2958
2959 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
2960 memcpy(ev.key.val, key->val, sizeof(key->val));
2961
2962 return mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev,
2963 &ev, sizeof(ev), NULL);
2964}
2965
Johan Hedbergafc747a2012-01-15 18:11:07 +02002966int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Johan Hedbergb644ba32012-01-17 21:48:47 +02002967 u8 addr_type, u8 *name, u8 name_len,
2968 u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02002969{
Johan Hedbergb644ba32012-01-17 21:48:47 +02002970 char buf[512];
2971 struct mgmt_ev_device_connected *ev = (void *) buf;
2972 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02002973
Johan Hedbergb644ba32012-01-17 21:48:47 +02002974 bacpy(&ev->addr.bdaddr, bdaddr);
2975 ev->addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02002976
Johan Hedbergb644ba32012-01-17 21:48:47 +02002977 if (name_len > 0)
2978 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
2979 name, name_len);
2980
2981 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
2982 eir_len = eir_append_data(&ev->eir[eir_len], eir_len,
2983 EIR_CLASS_OF_DEV, dev_class, 3);
2984
2985 put_unaligned_le16(eir_len, &ev->eir_len);
2986
2987 return mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
2988 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02002989}
2990
Johan Hedberg8962ee72011-01-20 12:40:27 +02002991static void disconnect_rsp(struct pending_cmd *cmd, void *data)
2992{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01002993 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002994 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02002995 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002996
Johan Hedberg88c3df12012-02-09 14:27:38 +02002997 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2998 rp.addr.type = cp->addr.type;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002999
Johan Hedbergaee9b212012-02-18 15:07:59 +02003000 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, 0, &rp,
3001 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003002
3003 *sk = cmd->sk;
3004 sock_hold(*sk);
3005
Johan Hedberga664b5b2011-02-19 12:06:02 -03003006 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003007}
3008
Johan Hedberg124f6e32012-02-09 13:50:12 +02003009static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02003010{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003011 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02003012 struct mgmt_cp_unpair_device *cp = cmd->param;
3013 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02003014
3015 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02003016 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3017 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02003018
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003019 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
3020
Johan Hedbergaee9b212012-02-18 15:07:59 +02003021 cmd_complete(cmd->sk, cmd->index, cmd->opcode, 0, &rp, sizeof(rp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02003022
3023 mgmt_pending_remove(cmd);
3024}
3025
Johan Hedbergafc747a2012-01-15 18:11:07 +02003026int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
3027 u8 link_type, u8 addr_type)
Johan Hedbergf7520542011-01-20 12:34:39 +02003028{
Johan Hedberg4c659c32011-11-07 23:13:39 +02003029 struct mgmt_addr_info ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003030 struct sock *sk = NULL;
3031 int err;
3032
Johan Hedberg744cf192011-11-08 20:40:14 +02003033 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02003034
Johan Hedbergf7520542011-01-20 12:34:39 +02003035 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02003036 ev.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02003037
Johan Hedbergafc747a2012-01-15 18:11:07 +02003038 err = mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev),
3039 sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003040
3041 if (sk)
3042 sock_put(sk);
3043
Johan Hedberg124f6e32012-02-09 13:50:12 +02003044 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003045 hdev);
Johan Hedberga8a1d192011-11-10 15:54:38 +02003046
Johan Hedberg8962ee72011-01-20 12:40:27 +02003047 return err;
3048}
3049
Johan Hedberg88c3df12012-02-09 14:27:38 +02003050int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
3051 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02003052{
Johan Hedberg88c3df12012-02-09 14:27:38 +02003053 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003054 struct pending_cmd *cmd;
3055 int err;
3056
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003057 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003058 if (!cmd)
3059 return -ENOENT;
3060
Johan Hedberg88c3df12012-02-09 14:27:38 +02003061 bacpy(&rp.addr.bdaddr, bdaddr);
3062 rp.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02003063
Johan Hedberg88c3df12012-02-09 14:27:38 +02003064 err = cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
Johan Hedbergaee9b212012-02-18 15:07:59 +02003065 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003066
Johan Hedberga664b5b2011-02-19 12:06:02 -03003067 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003068
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003069 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
3070 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003071 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02003072}
Johan Hedberg17d5c042011-01-22 06:09:08 +02003073
Johan Hedberg48264f02011-11-09 13:58:58 +02003074int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
3075 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02003076{
3077 struct mgmt_ev_connect_failed ev;
3078
Johan Hedberg4c659c32011-11-07 23:13:39 +02003079 bacpy(&ev.addr.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02003080 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003081 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003082
Johan Hedberg744cf192011-11-08 20:40:14 +02003083 return mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003084}
Johan Hedberg980e1a52011-01-22 06:10:07 +02003085
Johan Hedberg744cf192011-11-08 20:40:14 +02003086int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003087{
3088 struct mgmt_ev_pin_code_request ev;
3089
Johan Hedbergd8457692012-02-17 14:24:57 +02003090 bacpy(&ev.addr.bdaddr, bdaddr);
3091 ev.addr.type = MGMT_ADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02003092 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003093
Johan Hedberg744cf192011-11-08 20:40:14 +02003094 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01003095 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003096}
3097
Johan Hedberg744cf192011-11-08 20:40:14 +02003098int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3099 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003100{
3101 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003102 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003103 int err;
3104
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003105 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003106 if (!cmd)
3107 return -ENOENT;
3108
Johan Hedbergd8457692012-02-17 14:24:57 +02003109 bacpy(&rp.addr.bdaddr, bdaddr);
3110 rp.addr.type = MGMT_ADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003111
Johan Hedbergaee9b212012-02-18 15:07:59 +02003112 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
3113 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003114
Johan Hedberga664b5b2011-02-19 12:06:02 -03003115 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003116
3117 return err;
3118}
3119
Johan Hedberg744cf192011-11-08 20:40:14 +02003120int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3121 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003122{
3123 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003124 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003125 int err;
3126
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003127 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003128 if (!cmd)
3129 return -ENOENT;
3130
Johan Hedbergd8457692012-02-17 14:24:57 +02003131 bacpy(&rp.addr.bdaddr, bdaddr);
3132 rp.addr.type = MGMT_ADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003133
Johan Hedbergaee9b212012-02-18 15:07:59 +02003134 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
3135 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003136
Johan Hedberga664b5b2011-02-19 12:06:02 -03003137 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003138
3139 return err;
3140}
Johan Hedberga5c29682011-02-19 12:05:57 -03003141
Johan Hedberg744cf192011-11-08 20:40:14 +02003142int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003143 u8 link_type, u8 addr_type, __le32 value,
3144 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03003145{
3146 struct mgmt_ev_user_confirm_request ev;
3147
Johan Hedberg744cf192011-11-08 20:40:14 +02003148 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03003149
Johan Hedberg272d90d2012-02-09 15:26:12 +02003150 bacpy(&ev.addr.bdaddr, bdaddr);
3151 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07003152 ev.confirm_hint = confirm_hint;
Johan Hedberga5c29682011-02-19 12:05:57 -03003153 put_unaligned_le32(value, &ev.value);
3154
Johan Hedberg744cf192011-11-08 20:40:14 +02003155 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01003156 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03003157}
3158
Johan Hedberg272d90d2012-02-09 15:26:12 +02003159int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
3160 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08003161{
3162 struct mgmt_ev_user_passkey_request ev;
3163
3164 BT_DBG("%s", hdev->name);
3165
Johan Hedberg272d90d2012-02-09 15:26:12 +02003166 bacpy(&ev.addr.bdaddr, bdaddr);
3167 ev.addr.type = link_to_mgmt(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08003168
3169 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
3170 NULL);
3171}
3172
Brian Gix0df4c182011-11-16 13:53:13 -08003173static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003174 u8 link_type, u8 addr_type, u8 status,
3175 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03003176{
3177 struct pending_cmd *cmd;
3178 struct mgmt_rp_user_confirm_reply rp;
3179 int err;
3180
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003181 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03003182 if (!cmd)
3183 return -ENOENT;
3184
Johan Hedberg272d90d2012-02-09 15:26:12 +02003185 bacpy(&rp.addr.bdaddr, bdaddr);
3186 rp.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergaee9b212012-02-18 15:07:59 +02003187 err = cmd_complete(cmd->sk, hdev->id, opcode, mgmt_status(status),
3188 &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03003189
Johan Hedberga664b5b2011-02-19 12:06:02 -03003190 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03003191
3192 return err;
3193}
3194
Johan Hedberg744cf192011-11-08 20:40:14 +02003195int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003196 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003197{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003198 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3199 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003200}
3201
Johan Hedberg272d90d2012-02-09 15:26:12 +02003202int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3203 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003204{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003205 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3206 status, MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003207}
Johan Hedberg2a611692011-02-19 12:06:00 -03003208
Brian Gix604086b2011-11-23 08:28:33 -08003209int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003210 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003211{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003212 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3213 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003214}
3215
Johan Hedberg272d90d2012-02-09 15:26:12 +02003216int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3217 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003218{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003219 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3220 status, MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003221}
3222
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003223int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
3224 u8 addr_type, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03003225{
3226 struct mgmt_ev_auth_failed ev;
3227
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003228 bacpy(&ev.addr.bdaddr, bdaddr);
3229 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003230 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03003231
Johan Hedberg744cf192011-11-08 20:40:14 +02003232 return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03003233}
Johan Hedbergb312b1612011-03-16 14:29:37 +02003234
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003235int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
3236{
3237 struct cmd_lookup match = { NULL, hdev };
3238 __le32 ev;
3239 int err;
3240
3241 if (status) {
3242 u8 mgmt_err = mgmt_status(status);
3243 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
3244 cmd_status_rsp, &mgmt_err);
3245 return 0;
3246 }
3247
3248 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
3249 &match);
3250
3251 ev = cpu_to_le32(get_current_settings(hdev));
3252 err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), match.sk);
3253
3254 if (match.sk)
3255 sock_put(match.sk);
3256
3257 return err;
3258}
3259
Johan Hedbergcacaf522012-02-21 00:52:42 +02003260static int clear_eir(struct hci_dev *hdev)
3261{
3262 struct hci_cp_write_eir cp;
3263
3264 if (!(hdev->features[6] & LMP_EXT_INQ))
3265 return 0;
3266
3267 memset(&cp, 0, sizeof(cp));
3268
3269 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
3270}
3271
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003272int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 status)
3273{
3274 struct cmd_lookup match = { NULL, hdev };
3275 __le32 ev;
3276 int err;
3277
3278 if (status) {
3279 u8 mgmt_err = mgmt_status(status);
3280 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev,
3281 cmd_status_rsp, &mgmt_err);
3282 return 0;
3283 }
3284
3285 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
3286
3287 ev = cpu_to_le32(get_current_settings(hdev));
3288 err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), match.sk);
3289
Johan Hedbergcacaf522012-02-21 00:52:42 +02003290 if (match.sk) {
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003291 sock_put(match.sk);
3292
Johan Hedbergcacaf522012-02-21 00:52:42 +02003293 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3294 update_eir(hdev);
3295 else
3296 clear_eir(hdev);
3297 }
3298
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003299 return err;
3300}
3301
Johan Hedberg744cf192011-11-08 20:40:14 +02003302int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02003303{
3304 struct pending_cmd *cmd;
3305 struct mgmt_cp_set_local_name ev;
3306 int err;
3307
3308 memset(&ev, 0, sizeof(ev));
3309 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
3310
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003311 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003312 if (!cmd)
3313 goto send_event;
3314
3315 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02003316 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
Johan Hedbergca69b792011-11-11 18:10:00 +02003317 mgmt_status(status));
Johan Hedbergb312b1612011-03-16 14:29:37 +02003318 goto failed;
3319 }
3320
Johan Hedberg744cf192011-11-08 20:40:14 +02003321 update_eir(hdev);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03003322
Johan Hedbergaee9b212012-02-18 15:07:59 +02003323 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0, &ev,
Johan Hedbergb312b1612011-03-16 14:29:37 +02003324 sizeof(ev));
3325 if (err < 0)
3326 goto failed;
3327
3328send_event:
Johan Hedberg744cf192011-11-08 20:40:14 +02003329 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
Johan Hedbergb312b1612011-03-16 14:29:37 +02003330 cmd ? cmd->sk : NULL);
3331
3332failed:
3333 if (cmd)
3334 mgmt_pending_remove(cmd);
3335 return err;
3336}
Szymon Jancc35938b2011-03-22 13:12:21 +01003337
Johan Hedberg744cf192011-11-08 20:40:14 +02003338int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
3339 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01003340{
3341 struct pending_cmd *cmd;
3342 int err;
3343
Johan Hedberg744cf192011-11-08 20:40:14 +02003344 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01003345
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003346 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003347 if (!cmd)
3348 return -ENOENT;
3349
3350 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02003351 err = cmd_status(cmd->sk, hdev->id,
Johan Hedbergca69b792011-11-11 18:10:00 +02003352 MGMT_OP_READ_LOCAL_OOB_DATA,
3353 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01003354 } else {
3355 struct mgmt_rp_read_local_oob_data rp;
3356
3357 memcpy(rp.hash, hash, sizeof(rp.hash));
3358 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
3359
Johan Hedberg744cf192011-11-08 20:40:14 +02003360 err = cmd_complete(cmd->sk, hdev->id,
3361 MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergaee9b212012-02-18 15:07:59 +02003362 0, &rp, sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01003363 }
3364
3365 mgmt_pending_remove(cmd);
3366
3367 return err;
3368}
Johan Hedberge17acd42011-03-30 23:57:16 +03003369
Johan Hedberg48264f02011-11-09 13:58:58 +02003370int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Johan Hedberg561aafb2012-01-04 13:31:59 +02003371 u8 addr_type, u8 *dev_class, s8 rssi,
Johan Hedberge319d2e2012-01-15 19:51:59 +02003372 u8 cfm_name, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03003373{
Johan Hedberge319d2e2012-01-15 19:51:59 +02003374 char buf[512];
3375 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02003376 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03003377
Johan Hedberg1dc06092012-01-15 21:01:23 +02003378 /* Leave 5 bytes for a potential CoD field */
3379 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Andre Guedes7d262f82012-01-10 18:20:49 -03003380 return -EINVAL;
3381
Johan Hedberg1dc06092012-01-15 21:01:23 +02003382 memset(buf, 0, sizeof(buf));
3383
Johan Hedberge319d2e2012-01-15 19:51:59 +02003384 bacpy(&ev->addr.bdaddr, bdaddr);
3385 ev->addr.type = link_to_mgmt(link_type, addr_type);
3386 ev->rssi = rssi;
3387 ev->confirm_name = cfm_name;
Johan Hedberge17acd42011-03-30 23:57:16 +03003388
Johan Hedberg1dc06092012-01-15 21:01:23 +02003389 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02003390 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03003391
Johan Hedberg1dc06092012-01-15 21:01:23 +02003392 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
3393 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
3394 dev_class, 3);
3395
3396 put_unaligned_le16(eir_len, &ev->eir_len);
3397
3398 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03003399
Johan Hedberge319d2e2012-01-15 19:51:59 +02003400 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03003401}
Johan Hedberga88a9652011-03-30 13:18:12 +03003402
Johan Hedbergb644ba32012-01-17 21:48:47 +02003403int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
3404 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03003405{
Johan Hedbergb644ba32012-01-17 21:48:47 +02003406 struct mgmt_ev_device_found *ev;
3407 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
3408 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03003409
Johan Hedbergb644ba32012-01-17 21:48:47 +02003410 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03003411
Johan Hedbergb644ba32012-01-17 21:48:47 +02003412 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03003413
Johan Hedbergb644ba32012-01-17 21:48:47 +02003414 bacpy(&ev->addr.bdaddr, bdaddr);
3415 ev->addr.type = link_to_mgmt(link_type, addr_type);
3416 ev->rssi = rssi;
3417
3418 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
3419 name_len);
3420
3421 put_unaligned_le16(eir_len, &ev->eir_len);
3422
Johan Hedberg053c7e02012-02-04 00:06:00 +02003423 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev,
3424 sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03003425}
Johan Hedberg314b2382011-04-27 10:29:57 -04003426
Andre Guedes7a135102011-11-09 17:14:25 -03003427int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
Johan Hedberg164a6e72011-11-01 17:06:44 +02003428{
3429 struct pending_cmd *cmd;
Johan Hedbergf808e162012-02-19 12:52:07 +02003430 u8 type;
Johan Hedberg164a6e72011-11-01 17:06:44 +02003431 int err;
3432
Andre Guedes203159d2012-02-13 15:41:01 -03003433 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3434
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003435 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003436 if (!cmd)
3437 return -ENOENT;
3438
Johan Hedbergf808e162012-02-19 12:52:07 +02003439 type = hdev->discovery.type;
3440
3441 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
3442 &type, sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02003443 mgmt_pending_remove(cmd);
3444
3445 return err;
3446}
3447
Andre Guedese6d465c2011-11-09 17:14:26 -03003448int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
3449{
3450 struct pending_cmd *cmd;
3451 int err;
3452
3453 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
3454 if (!cmd)
3455 return -ENOENT;
3456
Johan Hedbergd9306502012-02-20 23:25:18 +02003457 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
3458 &hdev->discovery.type,
3459 sizeof(hdev->discovery.type));
Johan Hedberg03811012010-12-08 00:21:06 +02003460 mgmt_pending_remove(cmd);
3461
3462 return err;
3463}
Johan Hedberg314b2382011-04-27 10:29:57 -04003464
Johan Hedberg744cf192011-11-08 20:40:14 +02003465int mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04003466{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02003467 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02003468 struct pending_cmd *cmd;
3469
Andre Guedes343fb142011-11-22 17:14:19 -03003470 BT_DBG("%s discovering %u", hdev->name, discovering);
3471
Johan Hedberg164a6e72011-11-01 17:06:44 +02003472 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003473 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003474 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003475 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003476
3477 if (cmd != NULL) {
Johan Hedbergf808e162012-02-19 12:52:07 +02003478 u8 type = hdev->discovery.type;
3479
Johan Hedbergd9306502012-02-20 23:25:18 +02003480 cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0,
Johan Hedbergf808e162012-02-19 12:52:07 +02003481 &type, sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02003482 mgmt_pending_remove(cmd);
3483 }
3484
Johan Hedbergf963e8e2012-02-20 23:30:44 +02003485 memset(&ev, 0, sizeof(ev));
3486 ev.type = hdev->discovery.type;
3487 ev.discovering = discovering;
3488
3489 return mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04003490}
Antti Julku5e762442011-08-25 16:48:02 +03003491
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003492int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003493{
3494 struct pending_cmd *cmd;
3495 struct mgmt_ev_device_blocked ev;
3496
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003497 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003498
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003499 bacpy(&ev.addr.bdaddr, bdaddr);
3500 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003501
Johan Hedberg744cf192011-11-08 20:40:14 +02003502 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
3503 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003504}
3505
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003506int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003507{
3508 struct pending_cmd *cmd;
3509 struct mgmt_ev_device_unblocked ev;
3510
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003511 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003512
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003513 bacpy(&ev.addr.bdaddr, bdaddr);
3514 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003515
Johan Hedberg744cf192011-11-08 20:40:14 +02003516 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
3517 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003518}
Marcel Holtmannd7b7e792012-02-20 21:47:49 +01003519
3520module_param(enable_hs, bool, 0644);
3521MODULE_PARM_DESC(enable_hs, "Enable High Speed support");
3522
3523module_param(enable_le, bool, 0644);
3524MODULE_PARM_DESC(enable_le, "Enable Low Energy support");