blob: 08b867a4d0e601be3b798ab902f72dcb36533da9 [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
Johan Hedbergf1f0eb02012-02-21 17:15:41 +0200395 if (hdev_is_powered(hdev))
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100396 settings |= MGMT_SETTING_POWERED;
397
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200398 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200399 settings |= MGMT_SETTING_CONNECTABLE;
400
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200401 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200402 settings |= MGMT_SETTING_DISCOVERABLE;
403
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200404 if (test_bit(HCI_PAIRABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200405 settings |= MGMT_SETTING_PAIRABLE;
406
407 if (!(hdev->features[4] & LMP_NO_BREDR))
408 settings |= MGMT_SETTING_BREDR;
409
Andre Guedes59e29402011-12-30 10:34:03 -0300410 if (hdev->host_features[0] & LMP_HOST_LE)
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200411 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200412
413 if (test_bit(HCI_AUTH, &hdev->flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200414 settings |= MGMT_SETTING_LINK_SECURITY;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200415
Johan Hedberg84bde9d2012-01-25 14:21:06 +0200416 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200417 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200418
Johan Hedberg6d80dfd2012-02-20 23:50:38 +0200419 if (test_bit(HCI_HS_ENABLED, &hdev->dev_flags))
420 settings |= MGMT_SETTING_HS;
421
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200422 return settings;
Johan Hedbergc542a062011-01-26 13:11:03 +0200423}
424
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300425#define PNP_INFO_SVCLASS_ID 0x1200
426
427static u8 bluetooth_base_uuid[] = {
428 0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80,
429 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
430};
431
432static u16 get_uuid16(u8 *uuid128)
433{
434 u32 val;
435 int i;
436
437 for (i = 0; i < 12; i++) {
438 if (bluetooth_base_uuid[i] != uuid128[i])
439 return 0;
440 }
441
442 memcpy(&val, &uuid128[12], 4);
443
444 val = le32_to_cpu(val);
445 if (val > 0xffff)
446 return 0;
447
448 return (u16) val;
449}
450
451static void create_eir(struct hci_dev *hdev, u8 *data)
452{
453 u8 *ptr = data;
454 u16 eir_len = 0;
455 u16 uuid16_list[HCI_MAX_EIR_LENGTH / sizeof(u16)];
456 int i, truncated = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200457 struct bt_uuid *uuid;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300458 size_t name_len;
459
460 name_len = strlen(hdev->dev_name);
461
462 if (name_len > 0) {
463 /* EIR Data type */
464 if (name_len > 48) {
465 name_len = 48;
466 ptr[1] = EIR_NAME_SHORT;
467 } else
468 ptr[1] = EIR_NAME_COMPLETE;
469
470 /* EIR Data length */
471 ptr[0] = name_len + 1;
472
473 memcpy(ptr + 2, hdev->dev_name, name_len);
474
475 eir_len += (name_len + 2);
476 ptr += (name_len + 2);
477 }
478
479 memset(uuid16_list, 0, sizeof(uuid16_list));
480
481 /* Group all UUID16 types */
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200482 list_for_each_entry(uuid, &hdev->uuids, list) {
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300483 u16 uuid16;
484
485 uuid16 = get_uuid16(uuid->uuid);
486 if (uuid16 == 0)
487 return;
488
489 if (uuid16 < 0x1100)
490 continue;
491
492 if (uuid16 == PNP_INFO_SVCLASS_ID)
493 continue;
494
495 /* Stop if not enough space to put next UUID */
496 if (eir_len + 2 + sizeof(u16) > HCI_MAX_EIR_LENGTH) {
497 truncated = 1;
498 break;
499 }
500
501 /* Check for duplicates */
502 for (i = 0; uuid16_list[i] != 0; i++)
503 if (uuid16_list[i] == uuid16)
504 break;
505
506 if (uuid16_list[i] == 0) {
507 uuid16_list[i] = uuid16;
508 eir_len += sizeof(u16);
509 }
510 }
511
512 if (uuid16_list[0] != 0) {
513 u8 *length = ptr;
514
515 /* EIR Data type */
516 ptr[1] = truncated ? EIR_UUID16_SOME : EIR_UUID16_ALL;
517
518 ptr += 2;
519 eir_len += 2;
520
521 for (i = 0; uuid16_list[i] != 0; i++) {
522 *ptr++ = (uuid16_list[i] & 0x00ff);
523 *ptr++ = (uuid16_list[i] & 0xff00) >> 8;
524 }
525
526 /* EIR Data length */
527 *length = (i * sizeof(u16)) + 1;
528 }
529}
530
531static int update_eir(struct hci_dev *hdev)
532{
533 struct hci_cp_write_eir cp;
534
535 if (!(hdev->features[6] & LMP_EXT_INQ))
536 return 0;
537
Johan Hedberg84bde9d2012-01-25 14:21:06 +0200538 if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300539 return 0;
540
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200541 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300542 return 0;
543
544 memset(&cp, 0, sizeof(cp));
545
546 create_eir(hdev, cp.data);
547
548 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
549 return 0;
550
551 memcpy(hdev->eir, cp.data, sizeof(cp.data));
552
553 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
554}
555
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200556static u8 get_service_classes(struct hci_dev *hdev)
557{
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300558 struct bt_uuid *uuid;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200559 u8 val = 0;
560
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300561 list_for_each_entry(uuid, &hdev->uuids, list)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200562 val |= uuid->svc_hint;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200563
564 return val;
565}
566
567static int update_class(struct hci_dev *hdev)
568{
569 u8 cod[3];
570
571 BT_DBG("%s", hdev->name);
572
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200573 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200574 return 0;
575
576 cod[0] = hdev->minor_class;
577 cod[1] = hdev->major_class;
578 cod[2] = get_service_classes(hdev);
579
580 if (memcmp(cod, hdev->dev_class, 3) == 0)
581 return 0;
582
583 return hci_send_cmd(hdev, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
584}
585
Johan Hedberg7d785252011-12-15 00:47:39 +0200586static void service_cache_off(struct work_struct *work)
587{
588 struct hci_dev *hdev = container_of(work, struct hci_dev,
589 service_cache.work);
590
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200591 if (!test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200592 return;
593
594 hci_dev_lock(hdev);
595
596 update_eir(hdev);
597 update_class(hdev);
598
599 hci_dev_unlock(hdev);
600}
601
602static void mgmt_init_hdev(struct hci_dev *hdev)
603{
Johan Hedberg0cbf4ed2012-02-21 17:25:22 +0200604 if (!test_and_set_bit(HCI_MGMT, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +0200605 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
606
Johan Hedberg0cbf4ed2012-02-21 17:25:22 +0200607 /* Non-mgmt controlled devices get this bit set
608 * implicitly so that pairing works for them, however
609 * for mgmt we require user-space to explicitly enable
610 * it
611 */
612 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
613 }
614
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200615 if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200616 schedule_delayed_work(&hdev->service_cache,
617 msecs_to_jiffies(SERVICE_CACHE_TIMEOUT));
618}
619
Johan Hedberg03811012010-12-08 00:21:06 +0200620static int read_controller_info(struct sock *sk, u16 index)
621{
622 struct mgmt_rp_read_info rp;
623 struct hci_dev *hdev;
624
625 BT_DBG("sock %p hci%u", sk, index);
626
627 hdev = hci_dev_get(index);
628 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200629 return cmd_status(sk, index, MGMT_OP_READ_INFO,
630 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200631
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300632 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200633
Johan Hedberg7d785252011-12-15 00:47:39 +0200634 if (test_and_clear_bit(HCI_PI_MGMT_INIT, &hci_pi(sk)->flags))
635 mgmt_init_hdev(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200636
637 memset(&rp, 0, sizeof(rp));
638
Johan Hedberg03811012010-12-08 00:21:06 +0200639 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200640
641 rp.version = hdev->hci_ver;
642
Johan Hedberg03811012010-12-08 00:21:06 +0200643 put_unaligned_le16(hdev->manufacturer, &rp.manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200644
645 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
646 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
647
648 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedberg03811012010-12-08 00:21:06 +0200649
650 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
651
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300652 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200653 hci_dev_put(hdev);
654
Johan Hedbergaee9b212012-02-18 15:07:59 +0200655 return cmd_complete(sk, index, MGMT_OP_READ_INFO, 0, &rp, sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +0200656}
657
658static void mgmt_pending_free(struct pending_cmd *cmd)
659{
660 sock_put(cmd->sk);
661 kfree(cmd->param);
662 kfree(cmd);
663}
664
665static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
666 struct hci_dev *hdev,
667 void *data, u16 len)
668{
669 struct pending_cmd *cmd;
670
671 cmd = kmalloc(sizeof(*cmd), GFP_ATOMIC);
672 if (!cmd)
673 return NULL;
674
675 cmd->opcode = opcode;
676 cmd->index = hdev->id;
677
678 cmd->param = kmalloc(len, GFP_ATOMIC);
679 if (!cmd->param) {
680 kfree(cmd);
681 return NULL;
682 }
683
684 if (data)
685 memcpy(cmd->param, data, len);
686
687 cmd->sk = sk;
688 sock_hold(sk);
689
690 list_add(&cmd->list, &hdev->mgmt_pending);
691
692 return cmd;
693}
694
695static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
696 void (*cb)(struct pending_cmd *cmd, void *data),
697 void *data)
698{
699 struct list_head *p, *n;
700
701 list_for_each_safe(p, n, &hdev->mgmt_pending) {
702 struct pending_cmd *cmd;
703
704 cmd = list_entry(p, struct pending_cmd, list);
705
706 if (opcode > 0 && cmd->opcode != opcode)
707 continue;
708
709 cb(cmd, data);
710 }
711}
712
713static struct pending_cmd *mgmt_pending_find(u16 opcode, struct hci_dev *hdev)
714{
715 struct pending_cmd *cmd;
716
717 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
718 if (cmd->opcode == opcode)
719 return cmd;
720 }
721
722 return NULL;
723}
724
725static void mgmt_pending_remove(struct pending_cmd *cmd)
726{
727 list_del(&cmd->list);
728 mgmt_pending_free(cmd);
729}
730
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200731static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +0200732{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200733 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +0200734
Johan Hedbergaee9b212012-02-18 15:07:59 +0200735 return cmd_complete(sk, hdev->id, opcode, 0, &settings,
736 sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +0200737}
738
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300739static int set_powered(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200740{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300741 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200742 struct hci_dev *hdev;
743 struct pending_cmd *cmd;
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200744 int err;
Johan Hedberg03811012010-12-08 00:21:06 +0200745
Johan Hedberg03811012010-12-08 00:21:06 +0200746 BT_DBG("request for hci%u", index);
747
748 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200749 return cmd_status(sk, index, MGMT_OP_SET_POWERED,
750 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200751
752 hdev = hci_dev_get(index);
753 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200754 return cmd_status(sk, index, MGMT_OP_SET_POWERED,
755 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200756
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300757 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200758
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100759 if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) {
760 cancel_delayed_work(&hdev->power_off);
761
762 if (cp->val) {
763 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
764 mgmt_powered(hdev, 1);
765 goto failed;
766 }
767 }
768
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200769 if (!!cp->val == hdev_is_powered(hdev)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200770 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200771 goto failed;
772 }
773
774 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200775 err = cmd_status(sk, index, MGMT_OP_SET_POWERED,
776 MGMT_STATUS_BUSY);
Johan Hedberg03811012010-12-08 00:21:06 +0200777 goto failed;
778 }
779
780 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
781 if (!cmd) {
782 err = -ENOMEM;
783 goto failed;
784 }
785
786 if (cp->val)
Gustavo F. Padovan7f971042011-12-18 12:40:32 -0200787 schedule_work(&hdev->power_on);
Johan Hedberg03811012010-12-08 00:21:06 +0200788 else
Gustavo F. Padovan80b7ab32011-12-17 14:52:27 -0200789 schedule_work(&hdev->power_off.work);
Johan Hedberg03811012010-12-08 00:21:06 +0200790
791 err = 0;
792
793failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300794 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200795 hci_dev_put(hdev);
796 return err;
797}
798
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200799static int mgmt_event(u16 event, struct hci_dev *hdev, void *data,
800 u16 data_len, struct sock *skip_sk)
801{
802 struct sk_buff *skb;
803 struct mgmt_hdr *hdr;
804
805 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_ATOMIC);
806 if (!skb)
807 return -ENOMEM;
808
809 hdr = (void *) skb_put(skb, sizeof(*hdr));
810 hdr->opcode = cpu_to_le16(event);
811 if (hdev)
812 hdr->index = cpu_to_le16(hdev->id);
813 else
814 hdr->index = cpu_to_le16(MGMT_INDEX_NONE);
815 hdr->len = cpu_to_le16(data_len);
816
817 if (data)
818 memcpy(skb_put(skb, data_len), data, data_len);
819
820 hci_send_to_control(skb, skip_sk);
821 kfree_skb(skb);
822
823 return 0;
824}
825
826static int new_settings(struct hci_dev *hdev, struct sock *skip)
827{
828 __le32 ev;
829
830 ev = cpu_to_le32(get_current_settings(hdev));
831
832 return mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), skip);
833}
834
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300835static int set_discoverable(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200836{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300837 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberge41d8b42010-12-13 21:07:03 +0200838 struct hci_dev *hdev;
Johan Hedberg03811012010-12-08 00:21:06 +0200839 struct pending_cmd *cmd;
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200840 u16 timeout;
Johan Hedberg03811012010-12-08 00:21:06 +0200841 u8 scan;
842 int err;
843
Johan Hedberg03811012010-12-08 00:21:06 +0200844 BT_DBG("request for hci%u", index);
845
846 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200847 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
848 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200849
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200850 hdev = hci_dev_get(index);
851 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200852 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
853 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200854
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200855 timeout = get_unaligned_le16(&cp->timeout);
856
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300857 hci_dev_lock(hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200858
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200859 if (!hdev_is_powered(hdev) && timeout > 0) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200860 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
861 MGMT_STATUS_NOT_POWERED);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200862 goto failed;
863 }
864
865 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
866 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200867 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
868 MGMT_STATUS_BUSY);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200869 goto failed;
870 }
871
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200872 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) {
873 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
874 MGMT_STATUS_REJECTED);
875 goto failed;
876 }
877
878 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200879 bool changed = false;
880
881 if (!!cp->val != test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
882 change_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
883 changed = true;
884 }
885
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200886 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200887 if (err < 0)
888 goto failed;
889
890 if (changed)
891 err = new_settings(hdev, sk);
892
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200893 goto failed;
894 }
895
896 if (!!cp->val == test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200897 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200898 goto failed;
899 }
900
901 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
902 if (!cmd) {
903 err = -ENOMEM;
904 goto failed;
905 }
906
907 scan = SCAN_PAGE;
908
909 if (cp->val)
910 scan |= SCAN_INQUIRY;
911 else
912 cancel_delayed_work(&hdev->discov_off);
913
914 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
915 if (err < 0)
916 mgmt_pending_remove(cmd);
917
Johan Hedberg03811012010-12-08 00:21:06 +0200918 if (cp->val)
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200919 hdev->discov_timeout = timeout;
Johan Hedberg03811012010-12-08 00:21:06 +0200920
921failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300922 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200923 hci_dev_put(hdev);
924
925 return err;
926}
927
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300928static int set_connectable(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200929{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300930 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200931 struct hci_dev *hdev;
932 struct pending_cmd *cmd;
933 u8 scan;
934 int err;
935
Johan Hedberge41d8b42010-12-13 21:07:03 +0200936 BT_DBG("request for hci%u", index);
937
Johan Hedberg03811012010-12-08 00:21:06 +0200938 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200939 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
940 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200941
942 hdev = hci_dev_get(index);
943 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200944 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
945 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200946
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300947 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200948
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200949 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200950 bool changed = false;
951
952 if (!!cp->val != test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
953 changed = true;
954
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200955 if (cp->val)
956 set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
957 else {
958 clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
959 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
960 }
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200961
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200962 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200963 if (err < 0)
964 goto failed;
965
966 if (changed)
967 err = new_settings(hdev, sk);
968
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200969 goto failed;
970 }
971
972 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
973 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200974 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
975 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200976 goto failed;
977 }
978
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200979 if (!!cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200980 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200981 goto failed;
982 }
983
984 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
985 if (!cmd) {
986 err = -ENOMEM;
987 goto failed;
988 }
989
990 if (cp->val)
991 scan = SCAN_PAGE;
Johan Hedbergdf2c6c52012-02-21 19:15:49 +0200992 else {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200993 scan = 0;
994
Johan Hedbergdf2c6c52012-02-21 19:15:49 +0200995 if (test_bit(HCI_ISCAN, &hdev->flags) &&
996 hdev->discov_timeout > 0)
997 cancel_delayed_work(&hdev->discov_off);
998 }
999
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001000 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1001 if (err < 0)
1002 mgmt_pending_remove(cmd);
1003
1004failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001005 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001006 hci_dev_put(hdev);
1007
1008 return err;
1009}
1010
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001011static int set_pairable(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001012{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001013 struct mgmt_mode *cp = data;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001014 struct hci_dev *hdev;
1015 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001016
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001017 BT_DBG("request for hci%u", index);
1018
1019 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001020 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE,
1021 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001022
1023 hdev = hci_dev_get(index);
1024 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001025 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE,
1026 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001027
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001028 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001029
1030 if (cp->val)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001031 set_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001032 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001033 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001034
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001035 err = send_settings_rsp(sk, MGMT_OP_SET_PAIRABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001036 if (err < 0)
1037 goto failed;
1038
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001039 err = new_settings(hdev, sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001040
1041failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001042 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001043 hci_dev_put(hdev);
1044
1045 return err;
1046}
Johan Hedberg72a734e2010-12-30 00:38:22 +02001047
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001048static int set_link_security(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_LINK_SECURITY,
1060 MGMT_STATUS_INVALID_PARAMS);
1061
1062 hdev = hci_dev_get(index);
1063 if (!hdev)
1064 return cmd_status(sk, index, MGMT_OP_SET_LINK_SECURITY,
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 Hedberg33ef95e2012-02-16 23:56:27 +02001070 err = cmd_status(sk, index, MGMT_OP_SET_LINK_SECURITY,
1071 MGMT_STATUS_NOT_POWERED);
1072 goto failed;
1073 }
1074
1075 if (mgmt_pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
1076 err = cmd_status(sk, index, MGMT_OP_SET_LINK_SECURITY,
1077 MGMT_STATUS_BUSY);
1078 goto failed;
1079 }
1080
1081 val = !!cp->val;
1082
1083 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1084 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1085 goto failed;
1086 }
1087
1088 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1089 if (!cmd) {
1090 err = -ENOMEM;
1091 goto failed;
1092 }
1093
1094 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1095 if (err < 0) {
1096 mgmt_pending_remove(cmd);
1097 goto failed;
1098 }
1099
1100failed:
1101 hci_dev_unlock(hdev);
1102 hci_dev_put(hdev);
1103
1104 return err;
1105}
1106
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001107static int set_ssp(struct sock *sk, u16 index, void *data, u16 len)
1108{
1109 struct mgmt_mode *cp = data;
1110 struct pending_cmd *cmd;
1111 struct hci_dev *hdev;
1112 uint8_t val;
1113 int err;
1114
1115 BT_DBG("request for hci%u", index);
1116
1117 if (len != sizeof(*cp))
1118 return cmd_status(sk, index, MGMT_OP_SET_SSP,
1119 MGMT_STATUS_INVALID_PARAMS);
1120
1121 hdev = hci_dev_get(index);
1122 if (!hdev)
1123 return cmd_status(sk, index, MGMT_OP_SET_SSP,
1124 MGMT_STATUS_INVALID_PARAMS);
1125
1126 hci_dev_lock(hdev);
1127
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001128 if (!hdev_is_powered(hdev)) {
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001129 err = cmd_status(sk, index, MGMT_OP_SET_SSP,
1130 MGMT_STATUS_NOT_POWERED);
1131 goto failed;
1132 }
1133
Johan Hedberg1e163572012-02-20 23:53:46 +02001134 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
1135 err = cmd_status(sk, index, MGMT_OP_SET_SSP,
1136 MGMT_STATUS_NOT_SUPPORTED);
1137 goto failed;
1138 }
1139
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001140 if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev)) {
1141 err = cmd_status(sk, index, MGMT_OP_SET_SSP, MGMT_STATUS_BUSY);
1142 goto failed;
1143 }
1144
1145 val = !!cp->val;
1146
1147 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) == val) {
1148 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1149 goto failed;
1150 }
1151
1152 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1153 if (!cmd) {
1154 err = -ENOMEM;
1155 goto failed;
1156 }
1157
1158 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, sizeof(val), &val);
1159 if (err < 0) {
1160 mgmt_pending_remove(cmd);
1161 goto failed;
1162 }
1163
1164failed:
1165 hci_dev_unlock(hdev);
1166 hci_dev_put(hdev);
1167
1168 return err;
1169}
1170
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001171static int set_hs(struct sock *sk, u16 index, void *data, u16 len)
1172{
1173 struct mgmt_mode *cp = data;
1174 struct hci_dev *hdev;
1175 int err;
1176
1177 BT_DBG("request for hci%u", index);
1178
1179 if (len != sizeof(*cp))
1180 return cmd_status(sk, index, MGMT_OP_SET_HS,
1181 MGMT_STATUS_INVALID_PARAMS);
1182
1183 hdev = hci_dev_get(index);
1184 if (!hdev)
1185 return cmd_status(sk, index, MGMT_OP_SET_HS,
1186 MGMT_STATUS_INVALID_PARAMS);
1187
1188 if (!enable_hs) {
1189 err = cmd_status(sk, index, MGMT_OP_SET_HS,
1190 MGMT_STATUS_NOT_SUPPORTED);
1191 goto failed;
1192 }
1193
1194 if (cp->val)
1195 set_bit(HCI_HS_ENABLED, &hdev->dev_flags);
1196 else
1197 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
1198
1199 err = send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
1200
1201failed:
1202 hci_dev_put(hdev);
1203 return err;
1204}
1205
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001206static int add_uuid(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001207{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001208 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001209 struct hci_dev *hdev;
1210 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001211 int err;
1212
Szymon Janc4e51eae2011-02-25 19:05:48 +01001213 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001214
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001215 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001216 return cmd_status(sk, index, MGMT_OP_ADD_UUID,
1217 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001218
Szymon Janc4e51eae2011-02-25 19:05:48 +01001219 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001220 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001221 return cmd_status(sk, index, MGMT_OP_ADD_UUID,
1222 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001223
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001224 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001225
1226 uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC);
1227 if (!uuid) {
1228 err = -ENOMEM;
1229 goto failed;
1230 }
1231
1232 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001233 uuid->svc_hint = cp->svc_hint;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001234
1235 list_add(&uuid->list, &hdev->uuids);
1236
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001237 err = update_class(hdev);
1238 if (err < 0)
1239 goto failed;
1240
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001241 err = update_eir(hdev);
1242 if (err < 0)
1243 goto failed;
1244
Johan Hedbergaee9b212012-02-18 15:07:59 +02001245 err = cmd_complete(sk, index, MGMT_OP_ADD_UUID, 0, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001246
1247failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001248 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001249 hci_dev_put(hdev);
1250
1251 return err;
1252}
1253
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001254static int remove_uuid(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001255{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001256 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001257 struct list_head *p, *n;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001258 struct hci_dev *hdev;
1259 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 +02001260 int err, found;
1261
Szymon Janc4e51eae2011-02-25 19:05:48 +01001262 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +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_REMOVE_UUID,
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 Hedberg2aeb9a12011-01-04 12:08:51 +02001269 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001270 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
1271 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001272
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001273 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001274
1275 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
1276 err = hci_uuids_clear(hdev);
1277 goto unlock;
1278 }
1279
1280 found = 0;
1281
1282 list_for_each_safe(p, n, &hdev->uuids) {
1283 struct bt_uuid *match = list_entry(p, struct bt_uuid, list);
1284
1285 if (memcmp(match->uuid, cp->uuid, 16) != 0)
1286 continue;
1287
1288 list_del(&match->list);
1289 found++;
1290 }
1291
1292 if (found == 0) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001293 err = cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
1294 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001295 goto unlock;
1296 }
1297
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001298 err = update_class(hdev);
1299 if (err < 0)
1300 goto unlock;
1301
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001302 err = update_eir(hdev);
1303 if (err < 0)
1304 goto unlock;
1305
Johan Hedbergaee9b212012-02-18 15:07:59 +02001306 err = cmd_complete(sk, index, MGMT_OP_REMOVE_UUID, 0, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001307
1308unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001309 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001310 hci_dev_put(hdev);
1311
1312 return err;
1313}
1314
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001315static int set_dev_class(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001316{
1317 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001318 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001319 int err;
1320
Szymon Janc4e51eae2011-02-25 19:05:48 +01001321 BT_DBG("request for hci%u", index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001322
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001323 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001324 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS,
1325 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001326
Szymon Janc4e51eae2011-02-25 19:05:48 +01001327 hdev = hci_dev_get(index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001328 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001329 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS,
1330 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001331
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001332 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001333
Johan Hedbergb5235a62012-02-21 14:32:24 +02001334 if (!hdev_is_powered(hdev)) {
1335 err = cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS,
1336 MGMT_STATUS_NOT_POWERED);
1337 goto unlock;
1338 }
1339
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001340 hdev->major_class = cp->major;
1341 hdev->minor_class = cp->minor;
1342
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001343 if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02001344 hci_dev_unlock(hdev);
1345 cancel_delayed_work_sync(&hdev->service_cache);
1346 hci_dev_lock(hdev);
Johan Hedberg14c0b602011-12-15 00:47:37 +02001347 update_eir(hdev);
Johan Hedberg7d785252011-12-15 00:47:39 +02001348 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02001349
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001350 err = update_class(hdev);
1351
1352 if (err == 0)
Johan Hedbergaee9b212012-02-18 15:07:59 +02001353 err = cmd_complete(sk, index, MGMT_OP_SET_DEV_CLASS, 0,
1354 NULL, 0);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001355
Johan Hedbergb5235a62012-02-21 14:32:24 +02001356unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001357 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001358 hci_dev_put(hdev);
1359
1360 return err;
1361}
1362
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001363static int load_link_keys(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001364{
1365 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001366 struct mgmt_cp_load_link_keys *cp = data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001367 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001368 int i;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001369
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001370 if (len < sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001371 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1372 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001373
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001374 key_count = get_unaligned_le16(&cp->key_count);
1375
Johan Hedberg86742e12011-11-07 23:13:38 +02001376 expected_len = sizeof(*cp) + key_count *
1377 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001378 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001379 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001380 len, expected_len);
Johan Hedbergca69b792011-11-11 18:10:00 +02001381 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1382 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001383 }
1384
Szymon Janc4e51eae2011-02-25 19:05:48 +01001385 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001386 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001387 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1388 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001389
Szymon Janc4e51eae2011-02-25 19:05:48 +01001390 BT_DBG("hci%u debug_keys %u key_count %u", index, cp->debug_keys,
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001391 key_count);
1392
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001393 hci_dev_lock(hdev);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001394
1395 hci_link_keys_clear(hdev);
1396
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001397 set_bit(HCI_LINK_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001398
1399 if (cp->debug_keys)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001400 set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001401 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001402 clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001403
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001404 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001405 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001406
Johan Hedbergd753fdc2012-02-17 14:06:34 +02001407 hci_add_link_key(hdev, NULL, 0, &key->addr.bdaddr, key->val,
1408 key->type, key->pin_len);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001409 }
1410
Johan Hedbergaee9b212012-02-18 15:07:59 +02001411 cmd_complete(sk, index, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02001412
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001413 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001414 hci_dev_put(hdev);
1415
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001416 return 0;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001417}
1418
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001419static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
1420 u8 addr_type, struct sock *skip_sk)
1421{
1422 struct mgmt_ev_device_unpaired ev;
1423
1424 bacpy(&ev.addr.bdaddr, bdaddr);
1425 ev.addr.type = addr_type;
1426
1427 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
1428 skip_sk);
1429}
1430
Johan Hedberg124f6e32012-02-09 13:50:12 +02001431static int unpair_device(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001432{
1433 struct hci_dev *hdev;
Johan Hedberg124f6e32012-02-09 13:50:12 +02001434 struct mgmt_cp_unpair_device *cp = data;
1435 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001436 struct hci_cp_disconnect dc;
1437 struct pending_cmd *cmd;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001438 struct hci_conn *conn;
Johan Hedbergaee9b212012-02-18 15:07:59 +02001439 u8 status = 0;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001440 int err;
1441
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001442 if (len != sizeof(*cp))
Johan Hedberg124f6e32012-02-09 13:50:12 +02001443 return cmd_status(sk, index, MGMT_OP_UNPAIR_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02001444 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001445
Szymon Janc4e51eae2011-02-25 19:05:48 +01001446 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001447 if (!hdev)
Johan Hedberg124f6e32012-02-09 13:50:12 +02001448 return cmd_status(sk, index, MGMT_OP_UNPAIR_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02001449 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001450
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001451 hci_dev_lock(hdev);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001452
Johan Hedberga8a1d192011-11-10 15:54:38 +02001453 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02001454 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1455 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001456
Johan Hedberg124f6e32012-02-09 13:50:12 +02001457 if (cp->addr.type == MGMT_ADDR_BREDR)
1458 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
1459 else
1460 err = hci_remove_ltk(hdev, &cp->addr.bdaddr);
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03001461
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001462 if (err < 0) {
Johan Hedbergaee9b212012-02-18 15:07:59 +02001463 status = MGMT_STATUS_NOT_PAIRED;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001464 goto unlock;
1465 }
1466
Johan Hedberga8a1d192011-11-10 15:54:38 +02001467 if (!test_bit(HCI_UP, &hdev->flags) || !cp->disconnect) {
Johan Hedbergaee9b212012-02-18 15:07:59 +02001468 err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE, status,
1469 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001470 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001471 goto unlock;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001472 }
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001473
Johan Hedberg124f6e32012-02-09 13:50:12 +02001474 if (cp->addr.type == MGMT_ADDR_BREDR)
1475 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
1476 &cp->addr.bdaddr);
1477 else
1478 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
1479 &cp->addr.bdaddr);
1480
Johan Hedberga8a1d192011-11-10 15:54:38 +02001481 if (!conn) {
Johan Hedbergaee9b212012-02-18 15:07:59 +02001482 err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE, status,
1483 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001484 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001485 goto unlock;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001486 }
1487
Johan Hedberg124f6e32012-02-09 13:50:12 +02001488 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
1489 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02001490 if (!cmd) {
1491 err = -ENOMEM;
1492 goto unlock;
1493 }
1494
1495 put_unaligned_le16(conn->handle, &dc.handle);
1496 dc.reason = 0x13; /* Remote User Terminated Connection */
1497 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1498 if (err < 0)
1499 mgmt_pending_remove(cmd);
1500
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001501unlock:
Johan Hedbergca69b792011-11-11 18:10:00 +02001502 if (err < 0)
Johan Hedbergaee9b212012-02-18 15:07:59 +02001503 err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE, status,
1504 &rp, sizeof(rp));
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001505 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001506 hci_dev_put(hdev);
1507
1508 return err;
1509}
1510
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001511static int disconnect(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02001512{
1513 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001514 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001515 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03001516 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001517 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001518 int err;
1519
1520 BT_DBG("");
1521
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001522 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001523 return cmd_status(sk, index, MGMT_OP_DISCONNECT,
1524 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001525
Szymon Janc4e51eae2011-02-25 19:05:48 +01001526 hdev = hci_dev_get(index);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001527 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001528 return cmd_status(sk, index, MGMT_OP_DISCONNECT,
1529 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001530
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001531 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001532
1533 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001534 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1535 MGMT_STATUS_NOT_POWERED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001536 goto failed;
1537 }
1538
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001539 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001540 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1541 MGMT_STATUS_BUSY);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001542 goto failed;
1543 }
1544
Johan Hedberg88c3df12012-02-09 14:27:38 +02001545 if (cp->addr.type == MGMT_ADDR_BREDR)
1546 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
1547 else
1548 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03001549
Johan Hedberg8962ee72011-01-20 12:40:27 +02001550 if (!conn) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001551 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1552 MGMT_STATUS_NOT_CONNECTED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001553 goto failed;
1554 }
1555
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001556 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001557 if (!cmd) {
1558 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001559 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001560 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001561
1562 put_unaligned_le16(conn->handle, &dc.handle);
1563 dc.reason = 0x13; /* Remote User Terminated Connection */
1564
1565 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1566 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001567 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001568
1569failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001570 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001571 hci_dev_put(hdev);
1572
1573 return err;
1574}
1575
Johan Hedberg48264f02011-11-09 13:58:58 +02001576static u8 link_to_mgmt(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02001577{
1578 switch (link_type) {
1579 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02001580 switch (addr_type) {
1581 case ADDR_LE_DEV_PUBLIC:
1582 return MGMT_ADDR_LE_PUBLIC;
1583 case ADDR_LE_DEV_RANDOM:
1584 return MGMT_ADDR_LE_RANDOM;
1585 default:
1586 return MGMT_ADDR_INVALID;
1587 }
Johan Hedberg4c659c32011-11-07 23:13:39 +02001588 case ACL_LINK:
1589 return MGMT_ADDR_BREDR;
1590 default:
1591 return MGMT_ADDR_INVALID;
1592 }
1593}
1594
Szymon Janc8ce62842011-03-01 16:55:32 +01001595static int get_connections(struct sock *sk, u16 index)
Johan Hedberg2784eb42011-01-21 13:56:35 +02001596{
Johan Hedberg2784eb42011-01-21 13:56:35 +02001597 struct mgmt_rp_get_connections *rp;
1598 struct hci_dev *hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001599 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02001600 size_t rp_len;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001601 u16 count;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001602 int i, err;
1603
1604 BT_DBG("");
1605
Szymon Janc4e51eae2011-02-25 19:05:48 +01001606 hdev = hci_dev_get(index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001607 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001608 return cmd_status(sk, index, MGMT_OP_GET_CONNECTIONS,
1609 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001610
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001611 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001612
1613 count = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02001614 list_for_each_entry(c, &hdev->conn_hash.list, list) {
1615 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
1616 count++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001617 }
1618
Johan Hedberg4c659c32011-11-07 23:13:39 +02001619 rp_len = sizeof(*rp) + (count * sizeof(struct mgmt_addr_info));
Johan Hedberga38528f2011-01-22 06:46:43 +02001620 rp = kmalloc(rp_len, GFP_ATOMIC);
1621 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02001622 err = -ENOMEM;
1623 goto unlock;
1624 }
1625
Johan Hedberg2784eb42011-01-21 13:56:35 +02001626 put_unaligned_le16(count, &rp->conn_count);
1627
Johan Hedberg2784eb42011-01-21 13:56:35 +02001628 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001629 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02001630 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
1631 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001632 bacpy(&rp->addr[i].bdaddr, &c->dst);
Johan Hedberg48264f02011-11-09 13:58:58 +02001633 rp->addr[i].type = link_to_mgmt(c->type, c->dst_type);
Johan Hedberg4c659c32011-11-07 23:13:39 +02001634 if (rp->addr[i].type == MGMT_ADDR_INVALID)
1635 continue;
1636 i++;
1637 }
1638
1639 /* Recalculate length in case of filtered SCO connections, etc */
1640 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02001641
Johan Hedbergaee9b212012-02-18 15:07:59 +02001642 err = cmd_complete(sk, index, MGMT_OP_GET_CONNECTIONS, 0, rp, rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001643
1644unlock:
Johan Hedberga38528f2011-01-22 06:46:43 +02001645 kfree(rp);
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001646 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001647 hci_dev_put(hdev);
1648 return err;
1649}
1650
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001651static int send_pin_code_neg_reply(struct sock *sk, u16 index,
1652 struct hci_dev *hdev, struct mgmt_cp_pin_code_neg_reply *cp)
1653{
1654 struct pending_cmd *cmd;
1655 int err;
1656
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001657 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001658 sizeof(*cp));
1659 if (!cmd)
1660 return -ENOMEM;
1661
Johan Hedbergd8457692012-02-17 14:24:57 +02001662 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
1663 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001664 if (err < 0)
1665 mgmt_pending_remove(cmd);
1666
1667 return err;
1668}
1669
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001670static int pin_code_reply(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001671{
1672 struct hci_dev *hdev;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001673 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001674 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001675 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03001676 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001677 int err;
1678
1679 BT_DBG("");
1680
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001681 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001682 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1683 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001684
Szymon Janc4e51eae2011-02-25 19:05:48 +01001685 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001686 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001687 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1688 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001689
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001690 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001691
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001692 if (!hdev_is_powered(hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001693 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1694 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001695 goto failed;
1696 }
1697
Johan Hedbergd8457692012-02-17 14:24:57 +02001698 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001699 if (!conn) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001700 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1701 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001702 goto failed;
1703 }
1704
1705 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02001706 struct mgmt_cp_pin_code_neg_reply ncp;
1707
1708 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001709
1710 BT_ERR("PIN code is not 16 bytes long");
1711
1712 err = send_pin_code_neg_reply(sk, index, hdev, &ncp);
1713 if (err >= 0)
1714 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001715 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001716
1717 goto failed;
1718 }
1719
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001720 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data,
1721 len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001722 if (!cmd) {
1723 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001724 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001725 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02001726
Johan Hedbergd8457692012-02-17 14:24:57 +02001727 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001728 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02001729 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02001730
1731 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
1732 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001733 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001734
1735failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001736 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001737 hci_dev_put(hdev);
1738
1739 return err;
1740}
1741
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001742static int pin_code_neg_reply(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001743{
1744 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001745 struct mgmt_cp_pin_code_neg_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001746 int err;
1747
1748 BT_DBG("");
1749
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001750 if (len != sizeof(*cp))
1751 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001752 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001753
Szymon Janc4e51eae2011-02-25 19:05:48 +01001754 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001755 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001756 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001757 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001758
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001759 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001760
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001761 if (!hdev_is_powered(hdev)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001762 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001763 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001764 goto failed;
1765 }
1766
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001767 err = send_pin_code_neg_reply(sk, index, hdev, cp);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001768
1769failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001770 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001771 hci_dev_put(hdev);
1772
1773 return err;
1774}
1775
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001776static int set_io_capability(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001777{
1778 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001779 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001780
1781 BT_DBG("");
1782
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001783 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001784 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY,
1785 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001786
Szymon Janc4e51eae2011-02-25 19:05:48 +01001787 hdev = hci_dev_get(index);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001788 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001789 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY,
1790 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001791
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001792 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001793
1794 hdev->io_capability = cp->io_capability;
1795
1796 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Szymon Jancb8534e02011-03-01 16:55:34 +01001797 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001798
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001799 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001800 hci_dev_put(hdev);
1801
Johan Hedbergaee9b212012-02-18 15:07:59 +02001802 return cmd_complete(sk, index, MGMT_OP_SET_IO_CAPABILITY, 0, NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001803}
1804
Johan Hedberge9a416b2011-02-19 12:05:56 -03001805static inline struct pending_cmd *find_pairing(struct hci_conn *conn)
1806{
1807 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001808 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001809
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001810 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03001811 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
1812 continue;
1813
Johan Hedberge9a416b2011-02-19 12:05:56 -03001814 if (cmd->user_data != conn)
1815 continue;
1816
1817 return cmd;
1818 }
1819
1820 return NULL;
1821}
1822
1823static void pairing_complete(struct pending_cmd *cmd, u8 status)
1824{
1825 struct mgmt_rp_pair_device rp;
1826 struct hci_conn *conn = cmd->user_data;
1827
Johan Hedbergba4e5642011-11-11 00:07:34 +02001828 bacpy(&rp.addr.bdaddr, &conn->dst);
1829 rp.addr.type = link_to_mgmt(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001830
Johan Hedbergaee9b212012-02-18 15:07:59 +02001831 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, status,
1832 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001833
1834 /* So we don't get further callbacks for this connection */
1835 conn->connect_cfm_cb = NULL;
1836 conn->security_cfm_cb = NULL;
1837 conn->disconn_cfm_cb = NULL;
1838
1839 hci_conn_put(conn);
1840
Johan Hedberga664b5b2011-02-19 12:06:02 -03001841 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001842}
1843
1844static void pairing_complete_cb(struct hci_conn *conn, u8 status)
1845{
1846 struct pending_cmd *cmd;
1847
1848 BT_DBG("status %u", status);
1849
Johan Hedberg56e5cb82011-11-08 20:40:16 +02001850 cmd = find_pairing(conn);
1851 if (!cmd)
1852 BT_DBG("Unable to find a pending command");
1853 else
Johan Hedberge2113262012-02-18 15:20:03 +02001854 pairing_complete(cmd, mgmt_status(status));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001855}
1856
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001857static int pair_device(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001858{
1859 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001860 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02001861 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001862 struct pending_cmd *cmd;
1863 u8 sec_level, auth_type;
1864 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001865 int err;
1866
1867 BT_DBG("");
1868
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001869 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001870 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE,
1871 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001872
Szymon Janc4e51eae2011-02-25 19:05:48 +01001873 hdev = hci_dev_get(index);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001874 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001875 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE,
1876 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001877
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001878 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001879
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001880 sec_level = BT_SECURITY_MEDIUM;
1881 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001882 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001883 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03001884 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001885
Johan Hedbergba4e5642011-11-11 00:07:34 +02001886 if (cp->addr.type == MGMT_ADDR_BREDR)
1887 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr, sec_level,
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001888 auth_type);
1889 else
Johan Hedbergba4e5642011-11-11 00:07:34 +02001890 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr, sec_level,
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001891 auth_type);
1892
Johan Hedberg1425acb2011-11-11 00:07:35 +02001893 memset(&rp, 0, sizeof(rp));
1894 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1895 rp.addr.type = cp->addr.type;
1896
Ville Tervo30e76272011-02-22 16:10:53 -03001897 if (IS_ERR(conn)) {
Johan Hedberge2113262012-02-18 15:20:03 +02001898 err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE,
1899 MGMT_STATUS_CONNECT_FAILED,
1900 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001901 goto unlock;
1902 }
1903
1904 if (conn->connect_cfm_cb) {
1905 hci_conn_put(conn);
Johan Hedberge2113262012-02-18 15:20:03 +02001906 err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE,
1907 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001908 goto unlock;
1909 }
1910
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001911 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001912 if (!cmd) {
1913 err = -ENOMEM;
1914 hci_conn_put(conn);
1915 goto unlock;
1916 }
1917
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001918 /* For LE, just connecting isn't a proof that the pairing finished */
Johan Hedbergba4e5642011-11-11 00:07:34 +02001919 if (cp->addr.type == MGMT_ADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001920 conn->connect_cfm_cb = pairing_complete_cb;
1921
Johan Hedberge9a416b2011-02-19 12:05:56 -03001922 conn->security_cfm_cb = pairing_complete_cb;
1923 conn->disconn_cfm_cb = pairing_complete_cb;
1924 conn->io_capability = cp->io_cap;
1925 cmd->user_data = conn;
1926
1927 if (conn->state == BT_CONNECTED &&
1928 hci_conn_security(conn, sec_level, auth_type))
1929 pairing_complete(cmd, 0);
1930
1931 err = 0;
1932
1933unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001934 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001935 hci_dev_put(hdev);
1936
1937 return err;
1938}
1939
Johan Hedberg28424702012-02-02 04:02:29 +02001940static int cancel_pair_device(struct sock *sk, u16 index,
1941 unsigned char *data, u16 len)
1942{
1943 struct mgmt_addr_info *addr = (void *) data;
1944 struct hci_dev *hdev;
1945 struct pending_cmd *cmd;
1946 struct hci_conn *conn;
1947 int err;
1948
1949 BT_DBG("");
1950
1951 if (len != sizeof(*addr))
1952 return cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
1953 MGMT_STATUS_INVALID_PARAMS);
1954
1955 hdev = hci_dev_get(index);
1956 if (!hdev)
1957 return cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
1958 MGMT_STATUS_INVALID_PARAMS);
1959
1960 hci_dev_lock(hdev);
1961
1962 cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
1963 if (!cmd) {
1964 err = cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
1965 MGMT_STATUS_INVALID_PARAMS);
1966 goto unlock;
1967 }
1968
1969 conn = cmd->user_data;
1970
1971 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
1972 err = cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
1973 MGMT_STATUS_INVALID_PARAMS);
1974 goto unlock;
1975 }
1976
1977 pairing_complete(cmd, MGMT_STATUS_CANCELLED);
1978
Johan Hedbergaee9b212012-02-18 15:07:59 +02001979 err = cmd_complete(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE, 0, addr,
Johan Hedberg28424702012-02-02 04:02:29 +02001980 sizeof(*addr));
1981unlock:
1982 hci_dev_unlock(hdev);
1983 hci_dev_put(hdev);
1984
1985 return err;
1986}
1987
Brian Gix0df4c182011-11-16 13:53:13 -08001988static int user_pairing_resp(struct sock *sk, u16 index, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02001989 u8 type, u16 mgmt_op, u16 hci_op,
1990 __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03001991{
Johan Hedberga5c29682011-02-19 12:05:57 -03001992 struct pending_cmd *cmd;
1993 struct hci_dev *hdev;
Brian Gix0df4c182011-11-16 13:53:13 -08001994 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03001995 int err;
1996
Szymon Janc4e51eae2011-02-25 19:05:48 +01001997 hdev = hci_dev_get(index);
Johan Hedberga5c29682011-02-19 12:05:57 -03001998 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001999 return cmd_status(sk, index, mgmt_op,
2000 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga5c29682011-02-19 12:05:57 -03002001
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002002 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02002003
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002004 if (!hdev_is_powered(hdev)) {
Brian Gix0df4c182011-11-16 13:53:13 -08002005 err = cmd_status(sk, index, mgmt_op, MGMT_STATUS_NOT_POWERED);
2006 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002007 }
2008
Johan Hedberg272d90d2012-02-09 15:26:12 +02002009 if (type == MGMT_ADDR_BREDR)
2010 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, bdaddr);
2011 else
Brian Gix47c15e22011-11-16 13:53:14 -08002012 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, bdaddr);
Brian Gix47c15e22011-11-16 13:53:14 -08002013
Johan Hedberg272d90d2012-02-09 15:26:12 +02002014 if (!conn) {
2015 err = cmd_status(sk, index, mgmt_op,
2016 MGMT_STATUS_NOT_CONNECTED);
2017 goto done;
2018 }
2019
2020 if (type == MGMT_ADDR_LE_PUBLIC || type == MGMT_ADDR_LE_RANDOM) {
Brian Gix47c15e22011-11-16 13:53:14 -08002021 /* Continue with pairing via SMP */
Brian Gix5fe57d92011-12-21 16:12:13 -08002022 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix47c15e22011-11-16 13:53:14 -08002023
Brian Gix5fe57d92011-12-21 16:12:13 -08002024 if (!err)
2025 err = cmd_status(sk, index, mgmt_op,
2026 MGMT_STATUS_SUCCESS);
2027 else
2028 err = cmd_status(sk, index, mgmt_op,
2029 MGMT_STATUS_FAILED);
2030
Brian Gix47c15e22011-11-16 13:53:14 -08002031 goto done;
2032 }
2033
Brian Gix0df4c182011-11-16 13:53:13 -08002034 cmd = mgmt_pending_add(sk, mgmt_op, hdev, bdaddr, sizeof(*bdaddr));
Johan Hedberga5c29682011-02-19 12:05:57 -03002035 if (!cmd) {
2036 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08002037 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002038 }
2039
Brian Gix0df4c182011-11-16 13:53:13 -08002040 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08002041 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
2042 struct hci_cp_user_passkey_reply cp;
2043
2044 bacpy(&cp.bdaddr, bdaddr);
2045 cp.passkey = passkey;
2046 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
2047 } else
2048 err = hci_send_cmd(hdev, hci_op, sizeof(*bdaddr), bdaddr);
2049
Johan Hedberga664b5b2011-02-19 12:06:02 -03002050 if (err < 0)
2051 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002052
Brian Gix0df4c182011-11-16 13:53:13 -08002053done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002054 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002055 hci_dev_put(hdev);
2056
2057 return err;
2058}
2059
Brian Gix0df4c182011-11-16 13:53:13 -08002060static int user_confirm_reply(struct sock *sk, u16 index, void *data, u16 len)
2061{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002062 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002063
2064 BT_DBG("");
2065
2066 if (len != sizeof(*cp))
2067 return cmd_status(sk, index, MGMT_OP_USER_CONFIRM_REPLY,
2068 MGMT_STATUS_INVALID_PARAMS);
2069
Johan Hedberg272d90d2012-02-09 15:26:12 +02002070 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
2071 MGMT_OP_USER_CONFIRM_REPLY,
2072 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002073}
2074
2075static int user_confirm_neg_reply(struct sock *sk, u16 index, void *data,
2076 u16 len)
2077{
Johan Hedbergc9c26592011-12-15 00:47:41 +02002078 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002079
2080 BT_DBG("");
2081
2082 if (len != sizeof(*cp))
2083 return cmd_status(sk, index, MGMT_OP_USER_CONFIRM_NEG_REPLY,
2084 MGMT_STATUS_INVALID_PARAMS);
2085
Johan Hedberg272d90d2012-02-09 15:26:12 +02002086 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
2087 MGMT_OP_USER_CONFIRM_NEG_REPLY,
2088 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002089}
2090
Brian Gix604086b2011-11-23 08:28:33 -08002091static int user_passkey_reply(struct sock *sk, u16 index, void *data, u16 len)
2092{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002093 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002094
2095 BT_DBG("");
2096
2097 if (len != sizeof(*cp))
2098 return cmd_status(sk, index, MGMT_OP_USER_PASSKEY_REPLY,
2099 EINVAL);
2100
Johan Hedberg272d90d2012-02-09 15:26:12 +02002101 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
2102 MGMT_OP_USER_PASSKEY_REPLY,
2103 HCI_OP_USER_PASSKEY_REPLY,
2104 cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08002105}
2106
2107static int user_passkey_neg_reply(struct sock *sk, u16 index, void *data,
2108 u16 len)
2109{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002110 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002111
2112 BT_DBG("");
2113
2114 if (len != sizeof(*cp))
2115 return cmd_status(sk, index, MGMT_OP_USER_PASSKEY_NEG_REPLY,
2116 EINVAL);
2117
Johan Hedberg272d90d2012-02-09 15:26:12 +02002118 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
2119 MGMT_OP_USER_PASSKEY_NEG_REPLY,
2120 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08002121}
2122
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002123static int set_local_name(struct sock *sk, u16 index, void *data,
Johan Hedbergb312b1612011-03-16 14:29:37 +02002124 u16 len)
2125{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002126 struct mgmt_cp_set_local_name *mgmt_cp = data;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002127 struct hci_cp_write_local_name hci_cp;
2128 struct hci_dev *hdev;
2129 struct pending_cmd *cmd;
2130 int err;
2131
2132 BT_DBG("");
2133
2134 if (len != sizeof(*mgmt_cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02002135 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME,
2136 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002137
2138 hdev = hci_dev_get(index);
2139 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002140 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME,
2141 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002142
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002143 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002144
Johan Hedbergb5235a62012-02-21 14:32:24 +02002145 if (!hdev_is_powered(hdev)) {
2146 err = cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME,
2147 MGMT_STATUS_NOT_POWERED);
2148 goto failed;
2149 }
2150
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002151 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data,
2152 len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002153 if (!cmd) {
2154 err = -ENOMEM;
2155 goto failed;
2156 }
2157
2158 memcpy(hci_cp.name, mgmt_cp->name, sizeof(hci_cp.name));
2159 err = hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(hci_cp),
2160 &hci_cp);
2161 if (err < 0)
2162 mgmt_pending_remove(cmd);
2163
2164failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002165 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002166 hci_dev_put(hdev);
2167
2168 return err;
2169}
2170
Szymon Jancc35938b2011-03-22 13:12:21 +01002171static int read_local_oob_data(struct sock *sk, u16 index)
2172{
2173 struct hci_dev *hdev;
2174 struct pending_cmd *cmd;
2175 int err;
2176
2177 BT_DBG("hci%u", index);
2178
2179 hdev = hci_dev_get(index);
2180 if (!hdev)
2181 return cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002182 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancc35938b2011-03-22 13:12:21 +01002183
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002184 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002185
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002186 if (!hdev_is_powered(hdev)) {
Szymon Jancc35938b2011-03-22 13:12:21 +01002187 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002188 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002189 goto unlock;
2190 }
2191
2192 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
2193 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002194 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002195 goto unlock;
2196 }
2197
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002198 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02002199 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2200 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01002201 goto unlock;
2202 }
2203
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002204 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01002205 if (!cmd) {
2206 err = -ENOMEM;
2207 goto unlock;
2208 }
2209
2210 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
2211 if (err < 0)
2212 mgmt_pending_remove(cmd);
2213
2214unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002215 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002216 hci_dev_put(hdev);
2217
2218 return err;
2219}
2220
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002221static int add_remote_oob_data(struct sock *sk, u16 index, void *data,
2222 u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002223{
2224 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002225 struct mgmt_cp_add_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002226 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002227 int err;
2228
2229 BT_DBG("hci%u ", index);
2230
2231 if (len != sizeof(*cp))
2232 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002233 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01002234
2235 hdev = hci_dev_get(index);
2236 if (!hdev)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002237 return cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
2238 MGMT_STATUS_INVALID_PARAMS,
2239 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002240
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002241 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002242
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002243 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, cp->hash,
Szymon Janc2763eda2011-03-22 13:12:22 +01002244 cp->randomizer);
2245 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002246 status = MGMT_STATUS_FAILED;
Szymon Janc2763eda2011-03-22 13:12:22 +01002247 else
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002248 status = 0;
2249
2250 err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, status,
2251 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002252
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002253 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002254 hci_dev_put(hdev);
2255
2256 return err;
2257}
2258
2259static int remove_remote_oob_data(struct sock *sk, u16 index,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002260 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002261{
2262 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002263 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002264 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002265 int err;
2266
2267 BT_DBG("hci%u ", index);
2268
2269 if (len != sizeof(*cp))
2270 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002271 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01002272
2273 hdev = hci_dev_get(index);
2274 if (!hdev)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002275 return cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2276 MGMT_STATUS_INVALID_PARAMS,
2277 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002278
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002279 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002280
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002281 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr);
Szymon Janc2763eda2011-03-22 13:12:22 +01002282 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002283 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01002284 else
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002285 status = 0;
2286
2287 err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA, status,
2288 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002289
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002290 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002291 hci_dev_put(hdev);
2292
2293 return err;
2294}
2295
Andre Guedes5e0452c2012-02-17 20:39:38 -03002296static int discovery(struct hci_dev *hdev)
2297{
2298 int err;
2299
2300 if (lmp_host_le_capable(hdev)) {
2301 if (lmp_bredr_capable(hdev)) {
2302 err = hci_le_scan(hdev, LE_SCAN_TYPE,
2303 LE_SCAN_INT, LE_SCAN_WIN,
2304 LE_SCAN_TIMEOUT_BREDR_LE);
2305 } else {
2306 hdev->discovery.type = DISCOV_TYPE_LE;
2307 err = hci_le_scan(hdev, LE_SCAN_TYPE,
2308 LE_SCAN_INT, LE_SCAN_WIN,
2309 LE_SCAN_TIMEOUT_LE_ONLY);
2310 }
2311 } else {
2312 hdev->discovery.type = DISCOV_TYPE_BREDR;
2313 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
2314 }
2315
2316 return err;
2317}
2318
2319int mgmt_interleaved_discovery(struct hci_dev *hdev)
2320{
2321 int err;
2322
2323 BT_DBG("%s", hdev->name);
2324
2325 hci_dev_lock(hdev);
2326
2327 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR_LE);
2328 if (err < 0)
2329 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2330
2331 hci_dev_unlock(hdev);
2332
2333 return err;
2334}
2335
Johan Hedberg450dfda2011-11-12 11:58:22 +02002336static int start_discovery(struct sock *sk, u16 index,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002337 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002338{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002339 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002340 struct pending_cmd *cmd;
2341 struct hci_dev *hdev;
2342 int err;
2343
2344 BT_DBG("hci%u", index);
2345
Johan Hedberg450dfda2011-11-12 11:58:22 +02002346 if (len != sizeof(*cp))
2347 return cmd_status(sk, index, MGMT_OP_START_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_START_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 Hedberg4b34ee782012-02-21 14:13:02 +02002357 if (!hdev_is_powered(hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02002358 err = cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2359 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02002360 goto failed;
2361 }
2362
Johan Hedbergff9ef572012-01-04 14:23:45 +02002363 if (hdev->discovery.state != DISCOVERY_STOPPED) {
2364 err = cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2365 MGMT_STATUS_BUSY);
2366 goto failed;
2367 }
2368
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002369 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002370 if (!cmd) {
2371 err = -ENOMEM;
2372 goto failed;
2373 }
2374
Andre Guedes4aab14e2012-02-17 20:39:36 -03002375 hdev->discovery.type = cp->type;
2376
2377 switch (hdev->discovery.type) {
Andre Guedesf39799f2012-02-17 20:39:35 -03002378 case DISCOV_TYPE_BREDR:
Andre Guedes3fd24152012-02-03 17:48:01 -03002379 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
Andre Guedesf39799f2012-02-17 20:39:35 -03002380 break;
2381
2382 case DISCOV_TYPE_LE:
Andre Guedes3fd24152012-02-03 17:48:01 -03002383 err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT,
2384 LE_SCAN_WIN, LE_SCAN_TIMEOUT_LE_ONLY);
Andre Guedesf39799f2012-02-17 20:39:35 -03002385 break;
2386
Andre Guedes5e0452c2012-02-17 20:39:38 -03002387 case DISCOV_TYPE_INTERLEAVED:
2388 err = discovery(hdev);
2389 break;
2390
Andre Guedesf39799f2012-02-17 20:39:35 -03002391 default:
Andre Guedes3fd24152012-02-03 17:48:01 -03002392 err = -EINVAL;
Andre Guedesf39799f2012-02-17 20:39:35 -03002393 }
Andre Guedes3fd24152012-02-03 17:48:01 -03002394
Johan Hedberg14a53662011-04-27 10:29:56 -04002395 if (err < 0)
2396 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002397 else
2398 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002399
2400failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002401 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002402 hci_dev_put(hdev);
2403
2404 return err;
2405}
2406
Johan Hedbergd9306502012-02-20 23:25:18 +02002407static int stop_discovery(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002408{
Johan Hedbergd9306502012-02-20 23:25:18 +02002409 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002410 struct hci_dev *hdev;
2411 struct pending_cmd *cmd;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002412 struct hci_cp_remote_name_req_cancel cp;
2413 struct inquiry_entry *e;
Johan Hedberg14a53662011-04-27 10:29:56 -04002414 int err;
2415
2416 BT_DBG("hci%u", index);
2417
Johan Hedbergd9306502012-02-20 23:25:18 +02002418 if (len != sizeof(*mgmt_cp))
2419 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY,
2420 MGMT_STATUS_INVALID_PARAMS);
2421
Johan Hedberg14a53662011-04-27 10:29:56 -04002422 hdev = hci_dev_get(index);
2423 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002424 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY,
2425 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg14a53662011-04-27 10:29:56 -04002426
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002427 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002428
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002429 if (!hci_discovery_active(hdev)) {
Johan Hedbergd9306502012-02-20 23:25:18 +02002430 err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY,
2431 MGMT_STATUS_REJECTED,
2432 &mgmt_cp->type, sizeof(mgmt_cp->type));
2433 goto unlock;
2434 }
2435
2436 if (hdev->discovery.type != mgmt_cp->type) {
2437 err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY,
2438 MGMT_STATUS_INVALID_PARAMS,
2439 &mgmt_cp->type, sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002440 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02002441 }
2442
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002443 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002444 if (!cmd) {
2445 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002446 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04002447 }
2448
Andre Guedes343f9352012-02-17 20:39:37 -03002449 if (hdev->discovery.state == DISCOVERY_FINDING) {
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002450 err = hci_cancel_inquiry(hdev);
2451 if (err < 0)
2452 mgmt_pending_remove(cmd);
2453 else
2454 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
2455 goto unlock;
2456 }
2457
2458 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY, NAME_PENDING);
2459 if (!e) {
2460 mgmt_pending_remove(cmd);
Johan Hedbergaee9b212012-02-18 15:07:59 +02002461 err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY, 0,
Johan Hedbergd9306502012-02-20 23:25:18 +02002462 &mgmt_cp->type, sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002463 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2464 goto unlock;
2465 }
2466
2467 bacpy(&cp.bdaddr, &e->data.bdaddr);
2468 err = hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ_CANCEL,
2469 sizeof(cp), &cp);
Johan Hedberg14a53662011-04-27 10:29:56 -04002470 if (err < 0)
2471 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002472 else
2473 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002474
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002475unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002476 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002477 hci_dev_put(hdev);
2478
2479 return err;
2480}
2481
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002482static int confirm_name(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02002483{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002484 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002485 struct inquiry_entry *e;
2486 struct hci_dev *hdev;
2487 int err;
2488
2489 BT_DBG("hci%u", index);
2490
2491 if (len != sizeof(*cp))
2492 return cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2493 MGMT_STATUS_INVALID_PARAMS);
2494
2495 hdev = hci_dev_get(index);
2496 if (!hdev)
2497 return cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2498 MGMT_STATUS_INVALID_PARAMS);
2499
2500 hci_dev_lock(hdev);
2501
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002502 if (!hci_discovery_active(hdev)) {
2503 err = cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2504 MGMT_STATUS_FAILED);
2505 goto failed;
2506 }
2507
Johan Hedberga198e7b2012-02-17 14:27:06 +02002508 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002509 if (!e) {
2510 err = cmd_status (sk, index, MGMT_OP_CONFIRM_NAME,
2511 MGMT_STATUS_INVALID_PARAMS);
2512 goto failed;
2513 }
2514
2515 if (cp->name_known) {
2516 e->name_state = NAME_KNOWN;
2517 list_del(&e->list);
2518 } else {
2519 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e202012-01-09 00:53:02 +02002520 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002521 }
2522
2523 err = 0;
2524
2525failed:
2526 hci_dev_unlock(hdev);
2527
2528 return err;
2529}
2530
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002531static int block_device(struct sock *sk, u16 index, void *data, u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002532{
2533 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002534 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002535 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03002536 int err;
2537
2538 BT_DBG("hci%u", index);
2539
Antti Julku7fbec222011-06-15 12:01:15 +03002540 if (len != sizeof(*cp))
2541 return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002542 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002543
2544 hdev = hci_dev_get(index);
2545 if (!hdev)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002546 return cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE,
2547 MGMT_STATUS_INVALID_PARAMS,
2548 &cp->addr, sizeof(cp->addr));
Antti Julku7fbec222011-06-15 12:01:15 +03002549
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002550 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002551
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002552 err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002553 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002554 status = MGMT_STATUS_FAILED;
Antti Julku7fbec222011-06-15 12:01:15 +03002555 else
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002556 status = 0;
2557
2558 err = cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE, status,
2559 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03002560
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002561 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002562 hci_dev_put(hdev);
2563
2564 return err;
2565}
2566
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002567static int unblock_device(struct sock *sk, u16 index, void *data, u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002568{
2569 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002570 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002571 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03002572 int err;
2573
2574 BT_DBG("hci%u", index);
2575
Antti Julku7fbec222011-06-15 12:01:15 +03002576 if (len != sizeof(*cp))
2577 return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002578 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002579
2580 hdev = hci_dev_get(index);
2581 if (!hdev)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002582 return cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE,
2583 MGMT_STATUS_INVALID_PARAMS,
2584 &cp->addr, sizeof(cp->addr));
Antti Julku7fbec222011-06-15 12:01:15 +03002585
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002586 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002587
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002588 err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002589 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002590 status = MGMT_STATUS_INVALID_PARAMS;
Antti Julku7fbec222011-06-15 12:01:15 +03002591 else
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002592 status = 0;
2593
2594 err = cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE, status,
2595 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03002596
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002597 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002598 hci_dev_put(hdev);
2599
2600 return err;
2601}
2602
Antti Julkuf6422ec2011-06-22 13:11:56 +03002603static int set_fast_connectable(struct sock *sk, u16 index,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002604 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03002605{
2606 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002607 struct mgmt_mode *cp = data;
Antti Julkuf6422ec2011-06-22 13:11:56 +03002608 struct hci_cp_write_page_scan_activity acp;
2609 u8 type;
2610 int err;
2611
2612 BT_DBG("hci%u", index);
2613
2614 if (len != sizeof(*cp))
2615 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002616 MGMT_STATUS_INVALID_PARAMS);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002617
2618 hdev = hci_dev_get(index);
2619 if (!hdev)
2620 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002621 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg5400c042012-02-21 16:40:33 +02002622 if (!hdev_is_powered(hdev))
2623 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
2624 MGMT_STATUS_NOT_POWERED);
2625
2626 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
2627 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
2628 MGMT_STATUS_REJECTED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002629
2630 hci_dev_lock(hdev);
2631
Johan Hedbergf7c68692011-12-15 00:47:36 +02002632 if (cp->val) {
Antti Julkuf6422ec2011-06-22 13:11:56 +03002633 type = PAGE_SCAN_TYPE_INTERLACED;
2634 acp.interval = 0x0024; /* 22.5 msec page scan interval */
2635 } else {
2636 type = PAGE_SCAN_TYPE_STANDARD; /* default */
2637 acp.interval = 0x0800; /* default 1.28 sec page scan */
2638 }
2639
2640 acp.window = 0x0012; /* default 11.25 msec page scan window */
2641
2642 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
2643 sizeof(acp), &acp);
2644 if (err < 0) {
2645 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002646 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002647 goto done;
2648 }
2649
2650 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
2651 if (err < 0) {
2652 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002653 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002654 goto done;
2655 }
2656
Johan Hedbergaee9b212012-02-18 15:07:59 +02002657 err = cmd_complete(sk, index, MGMT_OP_SET_FAST_CONNECTABLE, 0,
2658 NULL, 0);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002659done:
2660 hci_dev_unlock(hdev);
2661 hci_dev_put(hdev);
2662
2663 return err;
2664}
2665
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002666static int load_long_term_keys(struct sock *sk, u16 index,
2667 void *cp_data, u16 len)
2668{
2669 struct hci_dev *hdev;
2670 struct mgmt_cp_load_long_term_keys *cp = cp_data;
2671 u16 key_count, expected_len;
2672 int i;
2673
2674 if (len < sizeof(*cp))
2675 return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS,
2676 EINVAL);
2677
2678 key_count = get_unaligned_le16(&cp->key_count);
2679
2680 expected_len = sizeof(*cp) + key_count *
2681 sizeof(struct mgmt_ltk_info);
2682 if (expected_len != len) {
2683 BT_ERR("load_keys: expected %u bytes, got %u bytes",
2684 len, expected_len);
2685 return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS,
2686 EINVAL);
2687 }
2688
2689 hdev = hci_dev_get(index);
2690 if (!hdev)
2691 return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS,
2692 ENODEV);
2693
2694 BT_DBG("hci%u key_count %u", index, key_count);
2695
2696 hci_dev_lock(hdev);
2697
2698 hci_smp_ltks_clear(hdev);
2699
2700 for (i = 0; i < key_count; i++) {
2701 struct mgmt_ltk_info *key = &cp->keys[i];
2702 u8 type;
2703
2704 if (key->master)
2705 type = HCI_SMP_LTK;
2706 else
2707 type = HCI_SMP_LTK_SLAVE;
2708
2709 hci_add_ltk(hdev, &key->addr.bdaddr, key->addr.type,
2710 type, 0, key->authenticated, key->val,
2711 key->enc_size, key->ediv, key->rand);
2712 }
2713
2714 hci_dev_unlock(hdev);
2715 hci_dev_put(hdev);
2716
2717 return 0;
2718}
2719
Johan Hedberg03811012010-12-08 00:21:06 +02002720int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
2721{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002722 void *buf;
2723 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02002724 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002725 u16 opcode, index, len;
Johan Hedberg03811012010-12-08 00:21:06 +02002726 int err;
2727
2728 BT_DBG("got %zu bytes", msglen);
2729
2730 if (msglen < sizeof(*hdr))
2731 return -EINVAL;
2732
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03002733 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02002734 if (!buf)
2735 return -ENOMEM;
2736
2737 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
2738 err = -EFAULT;
2739 goto done;
2740 }
2741
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002742 hdr = buf;
Johan Hedberg03811012010-12-08 00:21:06 +02002743 opcode = get_unaligned_le16(&hdr->opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002744 index = get_unaligned_le16(&hdr->index);
Johan Hedberg03811012010-12-08 00:21:06 +02002745 len = get_unaligned_le16(&hdr->len);
2746
2747 if (len != msglen - sizeof(*hdr)) {
2748 err = -EINVAL;
2749 goto done;
2750 }
2751
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002752 cp = buf + sizeof(*hdr);
2753
Johan Hedberg03811012010-12-08 00:21:06 +02002754 switch (opcode) {
Johan Hedberg02d98122010-12-13 21:07:04 +02002755 case MGMT_OP_READ_VERSION:
2756 err = read_version(sk);
2757 break;
Johan Hedberge70bb2e2012-02-13 16:59:33 +02002758 case MGMT_OP_READ_COMMANDS:
2759 err = read_commands(sk);
2760 break;
Johan Hedbergfaba42e2010-12-13 21:07:05 +02002761 case MGMT_OP_READ_INDEX_LIST:
2762 err = read_index_list(sk);
2763 break;
Johan Hedbergf7b64e62010-12-13 21:07:06 +02002764 case MGMT_OP_READ_INFO:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002765 err = read_controller_info(sk, index);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02002766 break;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002767 case MGMT_OP_SET_POWERED:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002768 err = set_powered(sk, index, cp, len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002769 break;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002770 case MGMT_OP_SET_DISCOVERABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002771 err = set_discoverable(sk, index, cp, len);
Johan Hedberg73f22f62010-12-29 16:00:25 +02002772 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002773 case MGMT_OP_SET_CONNECTABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002774 err = set_connectable(sk, index, cp, len);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002775 break;
Johan Hedbergf7c68692011-12-15 00:47:36 +02002776 case MGMT_OP_SET_FAST_CONNECTABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002777 err = set_fast_connectable(sk, index, cp, len);
Johan Hedbergf7c68692011-12-15 00:47:36 +02002778 break;
Johan Hedbergc542a062011-01-26 13:11:03 +02002779 case MGMT_OP_SET_PAIRABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002780 err = set_pairable(sk, index, cp, len);
Johan Hedbergc542a062011-01-26 13:11:03 +02002781 break;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02002782 case MGMT_OP_SET_LINK_SECURITY:
2783 err = set_link_security(sk, index, cp, len);
2784 break;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02002785 case MGMT_OP_SET_SSP:
2786 err = set_ssp(sk, index, cp, len);
2787 break;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02002788 case MGMT_OP_SET_HS:
2789 err = set_hs(sk, index, cp, len);
2790 break;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002791 case MGMT_OP_ADD_UUID:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002792 err = add_uuid(sk, index, cp, len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002793 break;
2794 case MGMT_OP_REMOVE_UUID:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002795 err = remove_uuid(sk, index, cp, len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002796 break;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002797 case MGMT_OP_SET_DEV_CLASS:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002798 err = set_dev_class(sk, index, cp, len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002799 break;
Johan Hedberg86742e12011-11-07 23:13:38 +02002800 case MGMT_OP_LOAD_LINK_KEYS:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002801 err = load_link_keys(sk, index, cp, len);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002802 break;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002803 case MGMT_OP_DISCONNECT:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002804 err = disconnect(sk, index, cp, len);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002805 break;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002806 case MGMT_OP_GET_CONNECTIONS:
Szymon Janc8ce62842011-03-01 16:55:32 +01002807 err = get_connections(sk, index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002808 break;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002809 case MGMT_OP_PIN_CODE_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002810 err = pin_code_reply(sk, index, cp, len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002811 break;
2812 case MGMT_OP_PIN_CODE_NEG_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002813 err = pin_code_neg_reply(sk, index, cp, len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002814 break;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002815 case MGMT_OP_SET_IO_CAPABILITY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002816 err = set_io_capability(sk, index, cp, len);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002817 break;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002818 case MGMT_OP_PAIR_DEVICE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002819 err = pair_device(sk, index, cp, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002820 break;
Johan Hedberg28424702012-02-02 04:02:29 +02002821 case MGMT_OP_CANCEL_PAIR_DEVICE:
2822 err = cancel_pair_device(sk, index, buf + sizeof(*hdr), len);
2823 break;
Johan Hedberg124f6e32012-02-09 13:50:12 +02002824 case MGMT_OP_UNPAIR_DEVICE:
2825 err = unpair_device(sk, index, cp, len);
2826 break;
Johan Hedberga5c29682011-02-19 12:05:57 -03002827 case MGMT_OP_USER_CONFIRM_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002828 err = user_confirm_reply(sk, index, cp, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03002829 break;
2830 case MGMT_OP_USER_CONFIRM_NEG_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002831 err = user_confirm_neg_reply(sk, index, cp, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03002832 break;
Brian Gix604086b2011-11-23 08:28:33 -08002833 case MGMT_OP_USER_PASSKEY_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002834 err = user_passkey_reply(sk, index, cp, len);
Brian Gix604086b2011-11-23 08:28:33 -08002835 break;
2836 case MGMT_OP_USER_PASSKEY_NEG_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002837 err = user_passkey_neg_reply(sk, index, cp, len);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002838 break;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002839 case MGMT_OP_SET_LOCAL_NAME:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002840 err = set_local_name(sk, index, cp, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002841 break;
Szymon Jancc35938b2011-03-22 13:12:21 +01002842 case MGMT_OP_READ_LOCAL_OOB_DATA:
2843 err = read_local_oob_data(sk, index);
2844 break;
Szymon Janc2763eda2011-03-22 13:12:22 +01002845 case MGMT_OP_ADD_REMOTE_OOB_DATA:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002846 err = add_remote_oob_data(sk, index, cp, len);
Szymon Janc2763eda2011-03-22 13:12:22 +01002847 break;
2848 case MGMT_OP_REMOVE_REMOTE_OOB_DATA:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002849 err = remove_remote_oob_data(sk, index, cp, len);
Szymon Janc2763eda2011-03-22 13:12:22 +01002850 break;
Johan Hedberg14a53662011-04-27 10:29:56 -04002851 case MGMT_OP_START_DISCOVERY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002852 err = start_discovery(sk, index, cp, len);
Johan Hedberg14a53662011-04-27 10:29:56 -04002853 break;
2854 case MGMT_OP_STOP_DISCOVERY:
Johan Hedbergd9306502012-02-20 23:25:18 +02002855 err = stop_discovery(sk, index, cp, len);
Johan Hedberg14a53662011-04-27 10:29:56 -04002856 break;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002857 case MGMT_OP_CONFIRM_NAME:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002858 err = confirm_name(sk, index, cp, len);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002859 break;
Antti Julku7fbec222011-06-15 12:01:15 +03002860 case MGMT_OP_BLOCK_DEVICE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002861 err = block_device(sk, index, cp, len);
Antti Julku7fbec222011-06-15 12:01:15 +03002862 break;
2863 case MGMT_OP_UNBLOCK_DEVICE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002864 err = unblock_device(sk, index, cp, len);
Antti Julku7fbec222011-06-15 12:01:15 +03002865 break;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002866 case MGMT_OP_LOAD_LONG_TERM_KEYS:
2867 err = load_long_term_keys(sk, index, cp, len);
2868 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002869 default:
Johan Hedberg72a734e2010-12-30 00:38:22 +02002870 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02002871 err = cmd_status(sk, index, opcode,
2872 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002873 break;
2874 }
Johan Hedberg72a734e2010-12-30 00:38:22 +02002875
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002876 if (err < 0)
Johan Hedberg72a734e2010-12-30 00:38:22 +02002877 goto done;
2878
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002879 err = msglen;
2880
2881done:
2882 kfree(buf);
2883 return err;
2884}
2885
Johan Hedbergb24752f2011-11-03 14:40:33 +02002886static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
2887{
2888 u8 *status = data;
2889
2890 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
2891 mgmt_pending_remove(cmd);
2892}
2893
Johan Hedberg744cf192011-11-08 20:40:14 +02002894int mgmt_index_added(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +02002895{
Johan Hedberg744cf192011-11-08 20:40:14 +02002896 return mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02002897}
2898
Johan Hedberg744cf192011-11-08 20:40:14 +02002899int mgmt_index_removed(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +02002900{
Johan Hedbergb24752f2011-11-03 14:40:33 +02002901 u8 status = ENODEV;
2902
Johan Hedberg744cf192011-11-08 20:40:14 +02002903 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002904
Johan Hedberg744cf192011-11-08 20:40:14 +02002905 return mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02002906}
2907
2908struct cmd_lookup {
Johan Hedberg03811012010-12-08 00:21:06 +02002909 struct sock *sk;
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002910 struct hci_dev *hdev;
Johan Hedberg03811012010-12-08 00:21:06 +02002911};
2912
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002913static void settings_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberg03811012010-12-08 00:21:06 +02002914{
Johan Hedberg03811012010-12-08 00:21:06 +02002915 struct cmd_lookup *match = data;
2916
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002917 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02002918
2919 list_del(&cmd->list);
2920
2921 if (match->sk == NULL) {
2922 match->sk = cmd->sk;
2923 sock_hold(match->sk);
2924 }
2925
2926 mgmt_pending_free(cmd);
2927}
2928
Johan Hedberg744cf192011-11-08 20:40:14 +02002929int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg03811012010-12-08 00:21:06 +02002930{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002931 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002932 int err;
Johan Hedberg03811012010-12-08 00:21:06 +02002933
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002934 if (!test_bit(HCI_MGMT, &hdev->dev_flags))
2935 return 0;
2936
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002937 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
Johan Hedberg03811012010-12-08 00:21:06 +02002938
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002939 if (powered) {
2940 u8 scan = 0;
2941
2942 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
2943 scan |= SCAN_PAGE;
2944 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
2945 scan |= SCAN_INQUIRY;
2946
2947 if (scan)
2948 hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
2949 } else {
Johan Hedbergb24752f2011-11-03 14:40:33 +02002950 u8 status = ENETDOWN;
Johan Hedberg744cf192011-11-08 20:40:14 +02002951 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002952 }
2953
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02002954 err = new_settings(hdev, match.sk);
Johan Hedberg03811012010-12-08 00:21:06 +02002955
2956 if (match.sk)
2957 sock_put(match.sk);
2958
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002959 return err;
Johan Hedberg03811012010-12-08 00:21:06 +02002960}
2961
Johan Hedberg744cf192011-11-08 20:40:14 +02002962int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg03811012010-12-08 00:21:06 +02002963{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002964 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002965 bool changed = false;
2966 int err = 0;
Johan Hedberg03811012010-12-08 00:21:06 +02002967
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002968 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp, &match);
Johan Hedberg03811012010-12-08 00:21:06 +02002969
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002970 if (discoverable) {
2971 if (!test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
2972 changed = true;
2973 } else {
2974 if (test_and_clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
2975 changed = true;
2976 }
Johan Hedberg03811012010-12-08 00:21:06 +02002977
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02002978 if (changed)
2979 err = new_settings(hdev, match.sk);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002980
Johan Hedberg03811012010-12-08 00:21:06 +02002981 if (match.sk)
2982 sock_put(match.sk);
2983
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002984 return err;
Johan Hedberg03811012010-12-08 00:21:06 +02002985}
2986
Johan Hedberg744cf192011-11-08 20:40:14 +02002987int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg03811012010-12-08 00:21:06 +02002988{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002989 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002990 bool changed = false;
2991 int err = 0;
Johan Hedberg03811012010-12-08 00:21:06 +02002992
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002993 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev, settings_rsp,
2994 &match);
Johan Hedberg03811012010-12-08 00:21:06 +02002995
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002996 if (connectable) {
2997 if (!test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags))
2998 changed = true;
2999 } else {
3000 if (test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3001 changed = true;
3002 }
Johan Hedberg03811012010-12-08 00:21:06 +02003003
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003004 if (changed)
3005 err = new_settings(hdev, match.sk);
Johan Hedberg03811012010-12-08 00:21:06 +02003006
3007 if (match.sk)
3008 sock_put(match.sk);
3009
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003010 return err;
Johan Hedberg03811012010-12-08 00:21:06 +02003011}
3012
Johan Hedberg744cf192011-11-08 20:40:14 +02003013int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003014{
Johan Hedbergca69b792011-11-11 18:10:00 +02003015 u8 mgmt_err = mgmt_status(status);
3016
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003017 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02003018 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Johan Hedbergca69b792011-11-11 18:10:00 +02003019 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003020
3021 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02003022 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Johan Hedbergca69b792011-11-11 18:10:00 +02003023 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003024
3025 return 0;
3026}
3027
Johan Hedberg744cf192011-11-08 20:40:14 +02003028int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
3029 u8 persistent)
Johan Hedberg03811012010-12-08 00:21:06 +02003030{
Johan Hedberg86742e12011-11-07 23:13:38 +02003031 struct mgmt_ev_new_link_key ev;
Johan Hedberg03811012010-12-08 00:21:06 +02003032
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003033 memset(&ev, 0, sizeof(ev));
Johan Hedberg03811012010-12-08 00:21:06 +02003034
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003035 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02003036 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
3037 ev.key.addr.type = MGMT_ADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003038 ev.key.type = key->type;
3039 memcpy(ev.key.val, key->val, 16);
3040 ev.key.pin_len = key->pin_len;
Johan Hedberg03811012010-12-08 00:21:06 +02003041
Johan Hedberg744cf192011-11-08 20:40:14 +02003042 return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02003043}
Johan Hedbergf7520542011-01-20 12:34:39 +02003044
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003045int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
3046{
3047 struct mgmt_ev_new_long_term_key ev;
3048
3049 memset(&ev, 0, sizeof(ev));
3050
3051 ev.store_hint = persistent;
3052 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
3053 ev.key.addr.type = key->bdaddr_type;
3054 ev.key.authenticated = key->authenticated;
3055 ev.key.enc_size = key->enc_size;
3056 ev.key.ediv = key->ediv;
3057
3058 if (key->type == HCI_SMP_LTK)
3059 ev.key.master = 1;
3060
3061 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
3062 memcpy(ev.key.val, key->val, sizeof(key->val));
3063
3064 return mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev,
3065 &ev, sizeof(ev), NULL);
3066}
3067
Johan Hedbergafc747a2012-01-15 18:11:07 +02003068int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Johan Hedbergb644ba32012-01-17 21:48:47 +02003069 u8 addr_type, u8 *name, u8 name_len,
3070 u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02003071{
Johan Hedbergb644ba32012-01-17 21:48:47 +02003072 char buf[512];
3073 struct mgmt_ev_device_connected *ev = (void *) buf;
3074 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02003075
Johan Hedbergb644ba32012-01-17 21:48:47 +02003076 bacpy(&ev->addr.bdaddr, bdaddr);
3077 ev->addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02003078
Johan Hedbergb644ba32012-01-17 21:48:47 +02003079 if (name_len > 0)
3080 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
3081 name, name_len);
3082
3083 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
3084 eir_len = eir_append_data(&ev->eir[eir_len], eir_len,
3085 EIR_CLASS_OF_DEV, dev_class, 3);
3086
3087 put_unaligned_le16(eir_len, &ev->eir_len);
3088
3089 return mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
3090 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02003091}
3092
Johan Hedberg8962ee72011-01-20 12:40:27 +02003093static void disconnect_rsp(struct pending_cmd *cmd, void *data)
3094{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01003095 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003096 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02003097 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003098
Johan Hedberg88c3df12012-02-09 14:27:38 +02003099 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3100 rp.addr.type = cp->addr.type;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003101
Johan Hedbergaee9b212012-02-18 15:07:59 +02003102 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, 0, &rp,
3103 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003104
3105 *sk = cmd->sk;
3106 sock_hold(*sk);
3107
Johan Hedberga664b5b2011-02-19 12:06:02 -03003108 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003109}
3110
Johan Hedberg124f6e32012-02-09 13:50:12 +02003111static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02003112{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003113 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02003114 struct mgmt_cp_unpair_device *cp = cmd->param;
3115 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02003116
3117 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02003118 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3119 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02003120
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003121 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
3122
Johan Hedbergaee9b212012-02-18 15:07:59 +02003123 cmd_complete(cmd->sk, cmd->index, cmd->opcode, 0, &rp, sizeof(rp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02003124
3125 mgmt_pending_remove(cmd);
3126}
3127
Johan Hedbergafc747a2012-01-15 18:11:07 +02003128int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
3129 u8 link_type, u8 addr_type)
Johan Hedbergf7520542011-01-20 12:34:39 +02003130{
Johan Hedberg4c659c32011-11-07 23:13:39 +02003131 struct mgmt_addr_info ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003132 struct sock *sk = NULL;
3133 int err;
3134
Johan Hedberg744cf192011-11-08 20:40:14 +02003135 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02003136
Johan Hedbergf7520542011-01-20 12:34:39 +02003137 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02003138 ev.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02003139
Johan Hedbergafc747a2012-01-15 18:11:07 +02003140 err = mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev),
3141 sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003142
3143 if (sk)
3144 sock_put(sk);
3145
Johan Hedberg124f6e32012-02-09 13:50:12 +02003146 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003147 hdev);
Johan Hedberga8a1d192011-11-10 15:54:38 +02003148
Johan Hedberg8962ee72011-01-20 12:40:27 +02003149 return err;
3150}
3151
Johan Hedberg88c3df12012-02-09 14:27:38 +02003152int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
3153 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02003154{
Johan Hedberg88c3df12012-02-09 14:27:38 +02003155 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003156 struct pending_cmd *cmd;
3157 int err;
3158
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003159 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003160 if (!cmd)
3161 return -ENOENT;
3162
Johan Hedberg88c3df12012-02-09 14:27:38 +02003163 bacpy(&rp.addr.bdaddr, bdaddr);
3164 rp.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02003165
Johan Hedberg88c3df12012-02-09 14:27:38 +02003166 err = cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
Johan Hedbergaee9b212012-02-18 15:07:59 +02003167 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003168
Johan Hedberga664b5b2011-02-19 12:06:02 -03003169 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003170
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003171 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
3172 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003173 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02003174}
Johan Hedberg17d5c042011-01-22 06:09:08 +02003175
Johan Hedberg48264f02011-11-09 13:58:58 +02003176int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
3177 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02003178{
3179 struct mgmt_ev_connect_failed ev;
3180
Johan Hedberg4c659c32011-11-07 23:13:39 +02003181 bacpy(&ev.addr.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02003182 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003183 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003184
Johan Hedberg744cf192011-11-08 20:40:14 +02003185 return mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003186}
Johan Hedberg980e1a52011-01-22 06:10:07 +02003187
Johan Hedberg744cf192011-11-08 20:40:14 +02003188int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003189{
3190 struct mgmt_ev_pin_code_request ev;
3191
Johan Hedbergd8457692012-02-17 14:24:57 +02003192 bacpy(&ev.addr.bdaddr, bdaddr);
3193 ev.addr.type = MGMT_ADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02003194 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003195
Johan Hedberg744cf192011-11-08 20:40:14 +02003196 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01003197 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003198}
3199
Johan Hedberg744cf192011-11-08 20:40:14 +02003200int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3201 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003202{
3203 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003204 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003205 int err;
3206
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003207 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003208 if (!cmd)
3209 return -ENOENT;
3210
Johan Hedbergd8457692012-02-17 14:24:57 +02003211 bacpy(&rp.addr.bdaddr, bdaddr);
3212 rp.addr.type = MGMT_ADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003213
Johan Hedbergaee9b212012-02-18 15:07:59 +02003214 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
3215 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003216
Johan Hedberga664b5b2011-02-19 12:06:02 -03003217 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003218
3219 return err;
3220}
3221
Johan Hedberg744cf192011-11-08 20:40:14 +02003222int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3223 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003224{
3225 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003226 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003227 int err;
3228
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003229 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003230 if (!cmd)
3231 return -ENOENT;
3232
Johan Hedbergd8457692012-02-17 14:24:57 +02003233 bacpy(&rp.addr.bdaddr, bdaddr);
3234 rp.addr.type = MGMT_ADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003235
Johan Hedbergaee9b212012-02-18 15:07:59 +02003236 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
3237 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003238
Johan Hedberga664b5b2011-02-19 12:06:02 -03003239 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003240
3241 return err;
3242}
Johan Hedberga5c29682011-02-19 12:05:57 -03003243
Johan Hedberg744cf192011-11-08 20:40:14 +02003244int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003245 u8 link_type, u8 addr_type, __le32 value,
3246 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03003247{
3248 struct mgmt_ev_user_confirm_request ev;
3249
Johan Hedberg744cf192011-11-08 20:40:14 +02003250 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03003251
Johan Hedberg272d90d2012-02-09 15:26:12 +02003252 bacpy(&ev.addr.bdaddr, bdaddr);
3253 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07003254 ev.confirm_hint = confirm_hint;
Johan Hedberga5c29682011-02-19 12:05:57 -03003255 put_unaligned_le32(value, &ev.value);
3256
Johan Hedberg744cf192011-11-08 20:40:14 +02003257 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01003258 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03003259}
3260
Johan Hedberg272d90d2012-02-09 15:26:12 +02003261int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
3262 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08003263{
3264 struct mgmt_ev_user_passkey_request ev;
3265
3266 BT_DBG("%s", hdev->name);
3267
Johan Hedberg272d90d2012-02-09 15:26:12 +02003268 bacpy(&ev.addr.bdaddr, bdaddr);
3269 ev.addr.type = link_to_mgmt(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08003270
3271 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
3272 NULL);
3273}
3274
Brian Gix0df4c182011-11-16 13:53:13 -08003275static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003276 u8 link_type, u8 addr_type, u8 status,
3277 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03003278{
3279 struct pending_cmd *cmd;
3280 struct mgmt_rp_user_confirm_reply rp;
3281 int err;
3282
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003283 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03003284 if (!cmd)
3285 return -ENOENT;
3286
Johan Hedberg272d90d2012-02-09 15:26:12 +02003287 bacpy(&rp.addr.bdaddr, bdaddr);
3288 rp.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergaee9b212012-02-18 15:07:59 +02003289 err = cmd_complete(cmd->sk, hdev->id, opcode, mgmt_status(status),
3290 &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03003291
Johan Hedberga664b5b2011-02-19 12:06:02 -03003292 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03003293
3294 return err;
3295}
3296
Johan Hedberg744cf192011-11-08 20:40:14 +02003297int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003298 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003299{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003300 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3301 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003302}
3303
Johan Hedberg272d90d2012-02-09 15:26:12 +02003304int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3305 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003306{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003307 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3308 status, MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003309}
Johan Hedberg2a611692011-02-19 12:06:00 -03003310
Brian Gix604086b2011-11-23 08:28:33 -08003311int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003312 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003313{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003314 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3315 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003316}
3317
Johan Hedberg272d90d2012-02-09 15:26:12 +02003318int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3319 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003320{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003321 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3322 status, MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003323}
3324
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003325int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
3326 u8 addr_type, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03003327{
3328 struct mgmt_ev_auth_failed ev;
3329
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003330 bacpy(&ev.addr.bdaddr, bdaddr);
3331 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003332 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03003333
Johan Hedberg744cf192011-11-08 20:40:14 +02003334 return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03003335}
Johan Hedbergb312b1612011-03-16 14:29:37 +02003336
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003337int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
3338{
3339 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003340 int err;
3341
3342 if (status) {
3343 u8 mgmt_err = mgmt_status(status);
3344 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
3345 cmd_status_rsp, &mgmt_err);
3346 return 0;
3347 }
3348
3349 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
3350 &match);
3351
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003352 err = new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003353
3354 if (match.sk)
3355 sock_put(match.sk);
3356
3357 return err;
3358}
3359
Johan Hedbergcacaf522012-02-21 00:52:42 +02003360static int clear_eir(struct hci_dev *hdev)
3361{
3362 struct hci_cp_write_eir cp;
3363
3364 if (!(hdev->features[6] & LMP_EXT_INQ))
3365 return 0;
3366
3367 memset(&cp, 0, sizeof(cp));
3368
3369 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
3370}
3371
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003372int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 status)
3373{
3374 struct cmd_lookup match = { NULL, hdev };
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003375 int err;
3376
3377 if (status) {
3378 u8 mgmt_err = mgmt_status(status);
3379 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev,
3380 cmd_status_rsp, &mgmt_err);
3381 return 0;
3382 }
3383
3384 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
3385
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003386 err = new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003387
Johan Hedbergcacaf522012-02-21 00:52:42 +02003388 if (match.sk) {
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003389 sock_put(match.sk);
3390
Johan Hedbergcacaf522012-02-21 00:52:42 +02003391 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3392 update_eir(hdev);
3393 else
3394 clear_eir(hdev);
3395 }
3396
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003397 return err;
3398}
3399
Johan Hedberg744cf192011-11-08 20:40:14 +02003400int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02003401{
3402 struct pending_cmd *cmd;
3403 struct mgmt_cp_set_local_name ev;
3404 int err;
3405
3406 memset(&ev, 0, sizeof(ev));
3407 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
3408
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003409 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003410 if (!cmd)
3411 goto send_event;
3412
3413 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02003414 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
Johan Hedbergca69b792011-11-11 18:10:00 +02003415 mgmt_status(status));
Johan Hedbergb312b1612011-03-16 14:29:37 +02003416 goto failed;
3417 }
3418
Johan Hedberg744cf192011-11-08 20:40:14 +02003419 update_eir(hdev);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03003420
Johan Hedbergaee9b212012-02-18 15:07:59 +02003421 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0, &ev,
Johan Hedbergb312b1612011-03-16 14:29:37 +02003422 sizeof(ev));
3423 if (err < 0)
3424 goto failed;
3425
3426send_event:
Johan Hedberg744cf192011-11-08 20:40:14 +02003427 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
Johan Hedbergb312b1612011-03-16 14:29:37 +02003428 cmd ? cmd->sk : NULL);
3429
3430failed:
3431 if (cmd)
3432 mgmt_pending_remove(cmd);
3433 return err;
3434}
Szymon Jancc35938b2011-03-22 13:12:21 +01003435
Johan Hedberg744cf192011-11-08 20:40:14 +02003436int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
3437 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01003438{
3439 struct pending_cmd *cmd;
3440 int err;
3441
Johan Hedberg744cf192011-11-08 20:40:14 +02003442 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01003443
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003444 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003445 if (!cmd)
3446 return -ENOENT;
3447
3448 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02003449 err = cmd_status(cmd->sk, hdev->id,
Johan Hedbergca69b792011-11-11 18:10:00 +02003450 MGMT_OP_READ_LOCAL_OOB_DATA,
3451 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01003452 } else {
3453 struct mgmt_rp_read_local_oob_data rp;
3454
3455 memcpy(rp.hash, hash, sizeof(rp.hash));
3456 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
3457
Johan Hedberg744cf192011-11-08 20:40:14 +02003458 err = cmd_complete(cmd->sk, hdev->id,
3459 MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergaee9b212012-02-18 15:07:59 +02003460 0, &rp, sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01003461 }
3462
3463 mgmt_pending_remove(cmd);
3464
3465 return err;
3466}
Johan Hedberge17acd42011-03-30 23:57:16 +03003467
Johan Hedberg48264f02011-11-09 13:58:58 +02003468int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Johan Hedberg561aafb2012-01-04 13:31:59 +02003469 u8 addr_type, u8 *dev_class, s8 rssi,
Johan Hedberge319d2e2012-01-15 19:51:59 +02003470 u8 cfm_name, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03003471{
Johan Hedberge319d2e2012-01-15 19:51:59 +02003472 char buf[512];
3473 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02003474 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03003475
Johan Hedberg1dc06092012-01-15 21:01:23 +02003476 /* Leave 5 bytes for a potential CoD field */
3477 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Andre Guedes7d262f82012-01-10 18:20:49 -03003478 return -EINVAL;
3479
Johan Hedberg1dc06092012-01-15 21:01:23 +02003480 memset(buf, 0, sizeof(buf));
3481
Johan Hedberge319d2e2012-01-15 19:51:59 +02003482 bacpy(&ev->addr.bdaddr, bdaddr);
3483 ev->addr.type = link_to_mgmt(link_type, addr_type);
3484 ev->rssi = rssi;
3485 ev->confirm_name = cfm_name;
Johan Hedberge17acd42011-03-30 23:57:16 +03003486
Johan Hedberg1dc06092012-01-15 21:01:23 +02003487 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02003488 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03003489
Johan Hedberg1dc06092012-01-15 21:01:23 +02003490 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
3491 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
3492 dev_class, 3);
3493
3494 put_unaligned_le16(eir_len, &ev->eir_len);
3495
3496 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03003497
Johan Hedberge319d2e2012-01-15 19:51:59 +02003498 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03003499}
Johan Hedberga88a9652011-03-30 13:18:12 +03003500
Johan Hedbergb644ba32012-01-17 21:48:47 +02003501int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
3502 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03003503{
Johan Hedbergb644ba32012-01-17 21:48:47 +02003504 struct mgmt_ev_device_found *ev;
3505 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
3506 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03003507
Johan Hedbergb644ba32012-01-17 21:48:47 +02003508 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03003509
Johan Hedbergb644ba32012-01-17 21:48:47 +02003510 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03003511
Johan Hedbergb644ba32012-01-17 21:48:47 +02003512 bacpy(&ev->addr.bdaddr, bdaddr);
3513 ev->addr.type = link_to_mgmt(link_type, addr_type);
3514 ev->rssi = rssi;
3515
3516 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
3517 name_len);
3518
3519 put_unaligned_le16(eir_len, &ev->eir_len);
3520
Johan Hedberg053c7e02012-02-04 00:06:00 +02003521 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev,
3522 sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03003523}
Johan Hedberg314b2382011-04-27 10:29:57 -04003524
Andre Guedes7a135102011-11-09 17:14:25 -03003525int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
Johan Hedberg164a6e72011-11-01 17:06:44 +02003526{
3527 struct pending_cmd *cmd;
Johan Hedbergf808e162012-02-19 12:52:07 +02003528 u8 type;
Johan Hedberg164a6e72011-11-01 17:06:44 +02003529 int err;
3530
Andre Guedes203159d2012-02-13 15:41:01 -03003531 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3532
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003533 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003534 if (!cmd)
3535 return -ENOENT;
3536
Johan Hedbergf808e162012-02-19 12:52:07 +02003537 type = hdev->discovery.type;
3538
3539 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
3540 &type, sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02003541 mgmt_pending_remove(cmd);
3542
3543 return err;
3544}
3545
Andre Guedese6d465c2011-11-09 17:14:26 -03003546int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
3547{
3548 struct pending_cmd *cmd;
3549 int err;
3550
3551 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
3552 if (!cmd)
3553 return -ENOENT;
3554
Johan Hedbergd9306502012-02-20 23:25:18 +02003555 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
3556 &hdev->discovery.type,
3557 sizeof(hdev->discovery.type));
Johan Hedberg03811012010-12-08 00:21:06 +02003558 mgmt_pending_remove(cmd);
3559
3560 return err;
3561}
Johan Hedberg314b2382011-04-27 10:29:57 -04003562
Johan Hedberg744cf192011-11-08 20:40:14 +02003563int mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04003564{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02003565 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02003566 struct pending_cmd *cmd;
3567
Andre Guedes343fb142011-11-22 17:14:19 -03003568 BT_DBG("%s discovering %u", hdev->name, discovering);
3569
Johan Hedberg164a6e72011-11-01 17:06:44 +02003570 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003571 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003572 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003573 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003574
3575 if (cmd != NULL) {
Johan Hedbergf808e162012-02-19 12:52:07 +02003576 u8 type = hdev->discovery.type;
3577
Johan Hedbergd9306502012-02-20 23:25:18 +02003578 cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0,
Johan Hedbergf808e162012-02-19 12:52:07 +02003579 &type, sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02003580 mgmt_pending_remove(cmd);
3581 }
3582
Johan Hedbergf963e8e2012-02-20 23:30:44 +02003583 memset(&ev, 0, sizeof(ev));
3584 ev.type = hdev->discovery.type;
3585 ev.discovering = discovering;
3586
3587 return mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04003588}
Antti Julku5e762442011-08-25 16:48:02 +03003589
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003590int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003591{
3592 struct pending_cmd *cmd;
3593 struct mgmt_ev_device_blocked ev;
3594
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003595 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003596
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003597 bacpy(&ev.addr.bdaddr, bdaddr);
3598 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003599
Johan Hedberg744cf192011-11-08 20:40:14 +02003600 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
3601 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003602}
3603
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003604int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003605{
3606 struct pending_cmd *cmd;
3607 struct mgmt_ev_device_unblocked ev;
3608
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003609 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003610
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003611 bacpy(&ev.addr.bdaddr, bdaddr);
3612 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003613
Johan Hedberg744cf192011-11-08 20:40:14 +02003614 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
3615 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003616}
Marcel Holtmannd7b7e792012-02-20 21:47:49 +01003617
3618module_param(enable_hs, bool, 0644);
3619MODULE_PARM_DESC(enable_hs, "Enable High Speed support");
3620
3621module_param(enable_le, bool, 0644);
3622MODULE_PARM_DESC(enable_le, "Enable Low Energy support");