blob: eec70a4ba36cd4d84a6975bcb25967ad8958f499 [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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-12-13 21:07:06 +0200231 kfree_skb(skb);
232
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300233 return err;
Johan Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-12-13 21:07:06 +0200387
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200388 return settings;
389}
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200390
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200391static u32 get_current_settings(struct hci_dev *hdev)
392{
393 u32 settings = 0;
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200394
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100395 if (!test_bit(HCI_UP, &hdev->flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200396 return settings;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200397
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100398 if (!test_bit(HCI_AUTO_OFF, &hdev->dev_flags))
399 settings |= MGMT_SETTING_POWERED;
400
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200401 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200402 settings |= MGMT_SETTING_CONNECTABLE;
403
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200404 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200405 settings |= MGMT_SETTING_DISCOVERABLE;
406
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200407 if (test_bit(HCI_PAIRABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200408 settings |= MGMT_SETTING_PAIRABLE;
409
410 if (!(hdev->features[4] & LMP_NO_BREDR))
411 settings |= MGMT_SETTING_BREDR;
412
Andre Guedes59e29402011-12-30 10:34:03 -0300413 if (hdev->host_features[0] & LMP_HOST_LE)
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200414 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200415
416 if (test_bit(HCI_AUTH, &hdev->flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200417 settings |= MGMT_SETTING_LINK_SECURITY;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200418
Johan Hedberg84bde9d6c2012-01-25 14:21:06 +0200419 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200420 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200421
Johan Hedberg6d80dfd2012-02-20 23:50:38 +0200422 if (test_bit(HCI_HS_ENABLED, &hdev->dev_flags))
423 settings |= MGMT_SETTING_HS;
424
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200425 return settings;
Johan Hedbergc542a062011-01-26 13:11:03 +0200426}
427
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300428#define PNP_INFO_SVCLASS_ID 0x1200
429
430static u8 bluetooth_base_uuid[] = {
431 0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80,
432 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
433};
434
435static u16 get_uuid16(u8 *uuid128)
436{
437 u32 val;
438 int i;
439
440 for (i = 0; i < 12; i++) {
441 if (bluetooth_base_uuid[i] != uuid128[i])
442 return 0;
443 }
444
445 memcpy(&val, &uuid128[12], 4);
446
447 val = le32_to_cpu(val);
448 if (val > 0xffff)
449 return 0;
450
451 return (u16) val;
452}
453
454static void create_eir(struct hci_dev *hdev, u8 *data)
455{
456 u8 *ptr = data;
457 u16 eir_len = 0;
458 u16 uuid16_list[HCI_MAX_EIR_LENGTH / sizeof(u16)];
459 int i, truncated = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200460 struct bt_uuid *uuid;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300461 size_t name_len;
462
463 name_len = strlen(hdev->dev_name);
464
465 if (name_len > 0) {
466 /* EIR Data type */
467 if (name_len > 48) {
468 name_len = 48;
469 ptr[1] = EIR_NAME_SHORT;
470 } else
471 ptr[1] = EIR_NAME_COMPLETE;
472
473 /* EIR Data length */
474 ptr[0] = name_len + 1;
475
476 memcpy(ptr + 2, hdev->dev_name, name_len);
477
478 eir_len += (name_len + 2);
479 ptr += (name_len + 2);
480 }
481
482 memset(uuid16_list, 0, sizeof(uuid16_list));
483
484 /* Group all UUID16 types */
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200485 list_for_each_entry(uuid, &hdev->uuids, list) {
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300486 u16 uuid16;
487
488 uuid16 = get_uuid16(uuid->uuid);
489 if (uuid16 == 0)
490 return;
491
492 if (uuid16 < 0x1100)
493 continue;
494
495 if (uuid16 == PNP_INFO_SVCLASS_ID)
496 continue;
497
498 /* Stop if not enough space to put next UUID */
499 if (eir_len + 2 + sizeof(u16) > HCI_MAX_EIR_LENGTH) {
500 truncated = 1;
501 break;
502 }
503
504 /* Check for duplicates */
505 for (i = 0; uuid16_list[i] != 0; i++)
506 if (uuid16_list[i] == uuid16)
507 break;
508
509 if (uuid16_list[i] == 0) {
510 uuid16_list[i] = uuid16;
511 eir_len += sizeof(u16);
512 }
513 }
514
515 if (uuid16_list[0] != 0) {
516 u8 *length = ptr;
517
518 /* EIR Data type */
519 ptr[1] = truncated ? EIR_UUID16_SOME : EIR_UUID16_ALL;
520
521 ptr += 2;
522 eir_len += 2;
523
524 for (i = 0; uuid16_list[i] != 0; i++) {
525 *ptr++ = (uuid16_list[i] & 0x00ff);
526 *ptr++ = (uuid16_list[i] & 0xff00) >> 8;
527 }
528
529 /* EIR Data length */
530 *length = (i * sizeof(u16)) + 1;
531 }
532}
533
534static int update_eir(struct hci_dev *hdev)
535{
536 struct hci_cp_write_eir cp;
537
538 if (!(hdev->features[6] & LMP_EXT_INQ))
539 return 0;
540
Johan Hedberg84bde9d6c2012-01-25 14:21:06 +0200541 if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300542 return 0;
543
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200544 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300545 return 0;
546
547 memset(&cp, 0, sizeof(cp));
548
549 create_eir(hdev, cp.data);
550
551 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
552 return 0;
553
554 memcpy(hdev->eir, cp.data, sizeof(cp.data));
555
556 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
557}
558
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200559static u8 get_service_classes(struct hci_dev *hdev)
560{
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300561 struct bt_uuid *uuid;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200562 u8 val = 0;
563
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300564 list_for_each_entry(uuid, &hdev->uuids, list)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200565 val |= uuid->svc_hint;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200566
567 return val;
568}
569
570static int update_class(struct hci_dev *hdev)
571{
572 u8 cod[3];
573
574 BT_DBG("%s", hdev->name);
575
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200576 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200577 return 0;
578
579 cod[0] = hdev->minor_class;
580 cod[1] = hdev->major_class;
581 cod[2] = get_service_classes(hdev);
582
583 if (memcmp(cod, hdev->dev_class, 3) == 0)
584 return 0;
585
586 return hci_send_cmd(hdev, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
587}
588
Johan Hedberg7d785252011-12-15 00:47:39 +0200589static void service_cache_off(struct work_struct *work)
590{
591 struct hci_dev *hdev = container_of(work, struct hci_dev,
592 service_cache.work);
593
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200594 if (!test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200595 return;
596
597 hci_dev_lock(hdev);
598
599 update_eir(hdev);
600 update_class(hdev);
601
602 hci_dev_unlock(hdev);
603}
604
605static void mgmt_init_hdev(struct hci_dev *hdev)
606{
Johan Hedberg0cbf4ed2012-02-21 17:25:22 +0200607 if (!test_and_set_bit(HCI_MGMT, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +0200608 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
609
Johan Hedberg0cbf4ed2012-02-21 17:25:22 +0200610 /* Non-mgmt controlled devices get this bit set
611 * implicitly so that pairing works for them, however
612 * for mgmt we require user-space to explicitly enable
613 * it
614 */
615 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
616 }
617
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200618 if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200619 schedule_delayed_work(&hdev->service_cache,
620 msecs_to_jiffies(SERVICE_CACHE_TIMEOUT));
621}
622
Johan Hedberg03811012010-12-08 00:21:06 +0200623static int read_controller_info(struct sock *sk, u16 index)
624{
625 struct mgmt_rp_read_info rp;
626 struct hci_dev *hdev;
627
628 BT_DBG("sock %p hci%u", sk, index);
629
630 hdev = hci_dev_get(index);
631 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200632 return cmd_status(sk, index, MGMT_OP_READ_INFO,
633 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200634
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300635 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200636
Johan Hedberg7d785252011-12-15 00:47:39 +0200637 if (test_and_clear_bit(HCI_PI_MGMT_INIT, &hci_pi(sk)->flags))
638 mgmt_init_hdev(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200639
640 memset(&rp, 0, sizeof(rp));
641
Johan Hedberg03811012010-12-08 00:21:06 +0200642 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200643
644 rp.version = hdev->hci_ver;
645
Johan Hedberg03811012010-12-08 00:21:06 +0200646 put_unaligned_le16(hdev->manufacturer, &rp.manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200647
648 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
649 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
650
651 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedberg03811012010-12-08 00:21:06 +0200652
653 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
654
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300655 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200656 hci_dev_put(hdev);
657
Johan Hedbergaee9b212012-02-18 15:07:59 +0200658 return cmd_complete(sk, index, MGMT_OP_READ_INFO, 0, &rp, sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +0200659}
660
661static void mgmt_pending_free(struct pending_cmd *cmd)
662{
663 sock_put(cmd->sk);
664 kfree(cmd->param);
665 kfree(cmd);
666}
667
668static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
669 struct hci_dev *hdev,
670 void *data, u16 len)
671{
672 struct pending_cmd *cmd;
673
674 cmd = kmalloc(sizeof(*cmd), GFP_ATOMIC);
675 if (!cmd)
676 return NULL;
677
678 cmd->opcode = opcode;
679 cmd->index = hdev->id;
680
681 cmd->param = kmalloc(len, GFP_ATOMIC);
682 if (!cmd->param) {
683 kfree(cmd);
684 return NULL;
685 }
686
687 if (data)
688 memcpy(cmd->param, data, len);
689
690 cmd->sk = sk;
691 sock_hold(sk);
692
693 list_add(&cmd->list, &hdev->mgmt_pending);
694
695 return cmd;
696}
697
698static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
699 void (*cb)(struct pending_cmd *cmd, void *data),
700 void *data)
701{
702 struct list_head *p, *n;
703
704 list_for_each_safe(p, n, &hdev->mgmt_pending) {
705 struct pending_cmd *cmd;
706
707 cmd = list_entry(p, struct pending_cmd, list);
708
709 if (opcode > 0 && cmd->opcode != opcode)
710 continue;
711
712 cb(cmd, data);
713 }
714}
715
716static struct pending_cmd *mgmt_pending_find(u16 opcode, struct hci_dev *hdev)
717{
718 struct pending_cmd *cmd;
719
720 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
721 if (cmd->opcode == opcode)
722 return cmd;
723 }
724
725 return NULL;
726}
727
728static void mgmt_pending_remove(struct pending_cmd *cmd)
729{
730 list_del(&cmd->list);
731 mgmt_pending_free(cmd);
732}
733
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200734static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +0200735{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200736 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +0200737
Johan Hedbergaee9b212012-02-18 15:07:59 +0200738 return cmd_complete(sk, hdev->id, opcode, 0, &settings,
739 sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +0200740}
741
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300742static int set_powered(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200743{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300744 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200745 struct hci_dev *hdev;
746 struct pending_cmd *cmd;
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200747 int err;
Johan Hedberg03811012010-12-08 00:21:06 +0200748
Johan Hedberg03811012010-12-08 00:21:06 +0200749 BT_DBG("request for hci%u", index);
750
751 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200752 return cmd_status(sk, index, MGMT_OP_SET_POWERED,
753 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200754
755 hdev = hci_dev_get(index);
756 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200757 return cmd_status(sk, index, MGMT_OP_SET_POWERED,
758 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200759
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300760 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200761
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100762 if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) {
763 cancel_delayed_work(&hdev->power_off);
764
765 if (cp->val) {
766 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
767 mgmt_powered(hdev, 1);
768 goto failed;
769 }
770 }
771
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200772 if (!!cp->val == hdev_is_powered(hdev)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200773 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200774 goto failed;
775 }
776
777 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200778 err = cmd_status(sk, index, MGMT_OP_SET_POWERED,
779 MGMT_STATUS_BUSY);
Johan Hedberg03811012010-12-08 00:21:06 +0200780 goto failed;
781 }
782
783 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
784 if (!cmd) {
785 err = -ENOMEM;
786 goto failed;
787 }
788
789 if (cp->val)
Gustavo F. Padovan7f971042011-12-18 12:40:32 -0200790 schedule_work(&hdev->power_on);
Johan Hedberg03811012010-12-08 00:21:06 +0200791 else
Gustavo F. Padovan80b7ab32011-12-17 14:52:27 -0200792 schedule_work(&hdev->power_off.work);
Johan Hedberg03811012010-12-08 00:21:06 +0200793
794 err = 0;
795
796failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300797 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200798 hci_dev_put(hdev);
799 return err;
800}
801
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300802static int set_discoverable(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200803{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300804 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberge41d8b42010-12-13 21:07:03 +0200805 struct hci_dev *hdev;
Johan Hedberg03811012010-12-08 00:21:06 +0200806 struct pending_cmd *cmd;
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200807 u16 timeout;
Johan Hedberg03811012010-12-08 00:21:06 +0200808 u8 scan;
809 int err;
810
Johan Hedberg03811012010-12-08 00:21:06 +0200811 BT_DBG("request for hci%u", index);
812
813 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200814 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
815 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200816
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200817 hdev = hci_dev_get(index);
818 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200819 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
820 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200821
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200822 timeout = get_unaligned_le16(&cp->timeout);
823
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300824 hci_dev_lock(hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200825
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200826 if (!hdev_is_powered(hdev) && timeout > 0) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200827 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
828 MGMT_STATUS_NOT_POWERED);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200829 goto failed;
830 }
831
832 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
833 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200834 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
835 MGMT_STATUS_BUSY);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200836 goto failed;
837 }
838
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200839 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) {
840 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
841 MGMT_STATUS_REJECTED);
842 goto failed;
843 }
844
845 if (!hdev_is_powered(hdev)) {
846 if (cp->val)
847 set_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
848 else
849 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
850 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
851 goto failed;
852 }
853
854 if (!!cp->val == test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200855 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200856 goto failed;
857 }
858
859 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
860 if (!cmd) {
861 err = -ENOMEM;
862 goto failed;
863 }
864
865 scan = SCAN_PAGE;
866
867 if (cp->val)
868 scan |= SCAN_INQUIRY;
869 else
870 cancel_delayed_work(&hdev->discov_off);
871
872 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
873 if (err < 0)
874 mgmt_pending_remove(cmd);
875
Johan Hedberg03811012010-12-08 00:21:06 +0200876 if (cp->val)
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200877 hdev->discov_timeout = timeout;
Johan Hedberg03811012010-12-08 00:21:06 +0200878
879failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300880 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200881 hci_dev_put(hdev);
882
883 return err;
884}
885
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300886static int set_connectable(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200887{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300888 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200889 struct hci_dev *hdev;
890 struct pending_cmd *cmd;
891 u8 scan;
892 int err;
893
Johan Hedberge41d8b42010-12-13 21:07:03 +0200894 BT_DBG("request for hci%u", index);
895
Johan Hedberg03811012010-12-08 00:21:06 +0200896 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200897 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
898 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200899
900 hdev = hci_dev_get(index);
901 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200902 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
903 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200904
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300905 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200906
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200907 if (!hdev_is_powered(hdev)) {
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200908 if (cp->val)
909 set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
910 else {
911 clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
912 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
913 }
914 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200915 goto failed;
916 }
917
918 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
919 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200920 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
921 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200922 goto failed;
923 }
924
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200925 if (!!cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200926 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200927 goto failed;
928 }
929
930 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
931 if (!cmd) {
932 err = -ENOMEM;
933 goto failed;
934 }
935
936 if (cp->val)
937 scan = SCAN_PAGE;
Johan Hedbergdf2c6c52012-02-21 19:15:49 +0200938 else {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200939 scan = 0;
940
Johan Hedbergdf2c6c52012-02-21 19:15:49 +0200941 if (test_bit(HCI_ISCAN, &hdev->flags) &&
942 hdev->discov_timeout > 0)
943 cancel_delayed_work(&hdev->discov_off);
944 }
945
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200946 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
947 if (err < 0)
948 mgmt_pending_remove(cmd);
949
950failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300951 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200952 hci_dev_put(hdev);
953
954 return err;
955}
956
957static int mgmt_event(u16 event, struct hci_dev *hdev, void *data,
958 u16 data_len, struct sock *skip_sk)
959{
960 struct sk_buff *skb;
961 struct mgmt_hdr *hdr;
962
963 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_ATOMIC);
964 if (!skb)
965 return -ENOMEM;
966
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200967 hdr = (void *) skb_put(skb, sizeof(*hdr));
968 hdr->opcode = cpu_to_le16(event);
969 if (hdev)
970 hdr->index = cpu_to_le16(hdev->id);
971 else
972 hdr->index = cpu_to_le16(MGMT_INDEX_NONE);
973 hdr->len = cpu_to_le16(data_len);
974
975 if (data)
976 memcpy(skb_put(skb, data_len), data, data_len);
977
Marcel Holtmann470fe1b2012-02-20 14:50:30 +0100978 hci_send_to_control(skb, skip_sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200979 kfree_skb(skb);
980
981 return 0;
982}
983
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300984static int set_pairable(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +0200985{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300986 struct mgmt_mode *cp = data;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200987 struct hci_dev *hdev;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200988 __le32 ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200989 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200990
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200991 BT_DBG("request for hci%u", index);
992
993 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200994 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE,
995 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200996
997 hdev = hci_dev_get(index);
998 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200999 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE,
1000 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001001
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001002 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001003
1004 if (cp->val)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001005 set_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001006 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001007 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001008
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001009 err = send_settings_rsp(sk, MGMT_OP_SET_PAIRABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001010 if (err < 0)
1011 goto failed;
1012
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001013 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001014
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001015 err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001016
1017failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001018 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001019 hci_dev_put(hdev);
1020
1021 return err;
1022}
Johan Hedberg72a734e2010-12-30 00:38:22 +02001023
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001024static int set_link_security(struct sock *sk, u16 index, void *data, u16 len)
1025{
1026 struct mgmt_mode *cp = data;
1027 struct pending_cmd *cmd;
1028 struct hci_dev *hdev;
1029 uint8_t val;
1030 int err;
1031
1032 BT_DBG("request for hci%u", index);
1033
1034 if (len != sizeof(*cp))
1035 return cmd_status(sk, index, MGMT_OP_SET_LINK_SECURITY,
1036 MGMT_STATUS_INVALID_PARAMS);
1037
1038 hdev = hci_dev_get(index);
1039 if (!hdev)
1040 return cmd_status(sk, index, MGMT_OP_SET_LINK_SECURITY,
1041 MGMT_STATUS_INVALID_PARAMS);
1042
1043 hci_dev_lock(hdev);
1044
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001045 if (!hdev_is_powered(hdev)) {
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001046 err = cmd_status(sk, index, MGMT_OP_SET_LINK_SECURITY,
1047 MGMT_STATUS_NOT_POWERED);
1048 goto failed;
1049 }
1050
1051 if (mgmt_pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
1052 err = cmd_status(sk, index, MGMT_OP_SET_LINK_SECURITY,
1053 MGMT_STATUS_BUSY);
1054 goto failed;
1055 }
1056
1057 val = !!cp->val;
1058
1059 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1060 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1061 goto failed;
1062 }
1063
1064 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1065 if (!cmd) {
1066 err = -ENOMEM;
1067 goto failed;
1068 }
1069
1070 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1071 if (err < 0) {
1072 mgmt_pending_remove(cmd);
1073 goto failed;
1074 }
1075
1076failed:
1077 hci_dev_unlock(hdev);
1078 hci_dev_put(hdev);
1079
1080 return err;
1081}
1082
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001083static int set_ssp(struct sock *sk, u16 index, void *data, u16 len)
1084{
1085 struct mgmt_mode *cp = data;
1086 struct pending_cmd *cmd;
1087 struct hci_dev *hdev;
1088 uint8_t val;
1089 int err;
1090
1091 BT_DBG("request for hci%u", index);
1092
1093 if (len != sizeof(*cp))
1094 return cmd_status(sk, index, MGMT_OP_SET_SSP,
1095 MGMT_STATUS_INVALID_PARAMS);
1096
1097 hdev = hci_dev_get(index);
1098 if (!hdev)
1099 return cmd_status(sk, index, MGMT_OP_SET_SSP,
1100 MGMT_STATUS_INVALID_PARAMS);
1101
1102 hci_dev_lock(hdev);
1103
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001104 if (!hdev_is_powered(hdev)) {
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001105 err = cmd_status(sk, index, MGMT_OP_SET_SSP,
1106 MGMT_STATUS_NOT_POWERED);
1107 goto failed;
1108 }
1109
Johan Hedberg1e163572012-02-20 23:53:46 +02001110 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
1111 err = cmd_status(sk, index, MGMT_OP_SET_SSP,
1112 MGMT_STATUS_NOT_SUPPORTED);
1113 goto failed;
1114 }
1115
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001116 if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev)) {
1117 err = cmd_status(sk, index, MGMT_OP_SET_SSP, MGMT_STATUS_BUSY);
1118 goto failed;
1119 }
1120
1121 val = !!cp->val;
1122
1123 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) == val) {
1124 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1125 goto failed;
1126 }
1127
1128 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1129 if (!cmd) {
1130 err = -ENOMEM;
1131 goto failed;
1132 }
1133
1134 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, sizeof(val), &val);
1135 if (err < 0) {
1136 mgmt_pending_remove(cmd);
1137 goto failed;
1138 }
1139
1140failed:
1141 hci_dev_unlock(hdev);
1142 hci_dev_put(hdev);
1143
1144 return err;
1145}
1146
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001147static int set_hs(struct sock *sk, u16 index, void *data, u16 len)
1148{
1149 struct mgmt_mode *cp = data;
1150 struct hci_dev *hdev;
1151 int err;
1152
1153 BT_DBG("request for hci%u", index);
1154
1155 if (len != sizeof(*cp))
1156 return cmd_status(sk, index, MGMT_OP_SET_HS,
1157 MGMT_STATUS_INVALID_PARAMS);
1158
1159 hdev = hci_dev_get(index);
1160 if (!hdev)
1161 return cmd_status(sk, index, MGMT_OP_SET_HS,
1162 MGMT_STATUS_INVALID_PARAMS);
1163
1164 if (!enable_hs) {
1165 err = cmd_status(sk, index, MGMT_OP_SET_HS,
1166 MGMT_STATUS_NOT_SUPPORTED);
1167 goto failed;
1168 }
1169
1170 if (cp->val)
1171 set_bit(HCI_HS_ENABLED, &hdev->dev_flags);
1172 else
1173 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
1174
1175 err = send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
1176
1177failed:
1178 hci_dev_put(hdev);
1179 return err;
1180}
1181
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001182static int add_uuid(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001183{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001184 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001185 struct hci_dev *hdev;
1186 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001187 int err;
1188
Szymon Janc4e51eae2011-02-25 19:05:48 +01001189 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001190
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001191 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001192 return cmd_status(sk, index, MGMT_OP_ADD_UUID,
1193 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001194
Szymon Janc4e51eae2011-02-25 19:05:48 +01001195 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001196 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001197 return cmd_status(sk, index, MGMT_OP_ADD_UUID,
1198 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001199
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001200 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001201
1202 uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC);
1203 if (!uuid) {
1204 err = -ENOMEM;
1205 goto failed;
1206 }
1207
1208 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001209 uuid->svc_hint = cp->svc_hint;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001210
1211 list_add(&uuid->list, &hdev->uuids);
1212
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001213 err = update_class(hdev);
1214 if (err < 0)
1215 goto failed;
1216
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001217 err = update_eir(hdev);
1218 if (err < 0)
1219 goto failed;
1220
Johan Hedbergaee9b212012-02-18 15:07:59 +02001221 err = cmd_complete(sk, index, MGMT_OP_ADD_UUID, 0, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001222
1223failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001224 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001225 hci_dev_put(hdev);
1226
1227 return err;
1228}
1229
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001230static int remove_uuid(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001231{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001232 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001233 struct list_head *p, *n;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001234 struct hci_dev *hdev;
1235 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 +02001236 int err, found;
1237
Szymon Janc4e51eae2011-02-25 19:05:48 +01001238 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001239
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001240 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001241 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
1242 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001243
Szymon Janc4e51eae2011-02-25 19:05:48 +01001244 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001245 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001246 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
1247 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001248
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001249 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001250
1251 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
1252 err = hci_uuids_clear(hdev);
1253 goto unlock;
1254 }
1255
1256 found = 0;
1257
1258 list_for_each_safe(p, n, &hdev->uuids) {
1259 struct bt_uuid *match = list_entry(p, struct bt_uuid, list);
1260
1261 if (memcmp(match->uuid, cp->uuid, 16) != 0)
1262 continue;
1263
1264 list_del(&match->list);
1265 found++;
1266 }
1267
1268 if (found == 0) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001269 err = cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
1270 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001271 goto unlock;
1272 }
1273
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001274 err = update_class(hdev);
1275 if (err < 0)
1276 goto unlock;
1277
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001278 err = update_eir(hdev);
1279 if (err < 0)
1280 goto unlock;
1281
Johan Hedbergaee9b212012-02-18 15:07:59 +02001282 err = cmd_complete(sk, index, MGMT_OP_REMOVE_UUID, 0, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001283
1284unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001285 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001286 hci_dev_put(hdev);
1287
1288 return err;
1289}
1290
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001291static int set_dev_class(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001292{
1293 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001294 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001295 int err;
1296
Szymon Janc4e51eae2011-02-25 19:05:48 +01001297 BT_DBG("request for hci%u", index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001298
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001299 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001300 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS,
1301 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001302
Szymon Janc4e51eae2011-02-25 19:05:48 +01001303 hdev = hci_dev_get(index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001304 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001305 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS,
1306 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001307
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001308 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001309
Johan Hedbergb5235a62012-02-21 14:32:24 +02001310 if (!hdev_is_powered(hdev)) {
1311 err = cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS,
1312 MGMT_STATUS_NOT_POWERED);
1313 goto unlock;
1314 }
1315
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001316 hdev->major_class = cp->major;
1317 hdev->minor_class = cp->minor;
1318
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001319 if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02001320 hci_dev_unlock(hdev);
1321 cancel_delayed_work_sync(&hdev->service_cache);
1322 hci_dev_lock(hdev);
Johan Hedberg14c0b602011-12-15 00:47:37 +02001323 update_eir(hdev);
Johan Hedberg7d785252011-12-15 00:47:39 +02001324 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02001325
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001326 err = update_class(hdev);
1327
1328 if (err == 0)
Johan Hedbergaee9b212012-02-18 15:07:59 +02001329 err = cmd_complete(sk, index, MGMT_OP_SET_DEV_CLASS, 0,
1330 NULL, 0);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001331
Johan Hedbergb5235a62012-02-21 14:32:24 +02001332unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001333 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001334 hci_dev_put(hdev);
1335
1336 return err;
1337}
1338
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001339static int load_link_keys(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001340{
1341 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001342 struct mgmt_cp_load_link_keys *cp = data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001343 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001344 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001345
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001346 if (len < sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001347 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1348 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001349
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001350 key_count = get_unaligned_le16(&cp->key_count);
1351
Johan Hedberg86742e12011-11-07 23:13:38 +02001352 expected_len = sizeof(*cp) + key_count *
1353 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001354 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001355 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001356 len, expected_len);
Johan Hedbergca69b792011-11-11 18:10:00 +02001357 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1358 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001359 }
1360
Szymon Janc4e51eae2011-02-25 19:05:48 +01001361 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001362 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001363 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1364 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001365
Szymon Janc4e51eae2011-02-25 19:05:48 +01001366 BT_DBG("hci%u debug_keys %u key_count %u", index, cp->debug_keys,
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001367 key_count);
1368
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001369 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001370
1371 hci_link_keys_clear(hdev);
1372
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001373 set_bit(HCI_LINK_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001374
1375 if (cp->debug_keys)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001376 set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001377 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001378 clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001379
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001380 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001381 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001382
Johan Hedbergd753fdc2012-02-17 14:06:34 +02001383 hci_add_link_key(hdev, NULL, 0, &key->addr.bdaddr, key->val,
1384 key->type, key->pin_len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001385 }
1386
Johan Hedbergaee9b212012-02-18 15:07:59 +02001387 cmd_complete(sk, index, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02001388
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001389 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001390 hci_dev_put(hdev);
1391
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001392 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001393}
1394
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001395static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
1396 u8 addr_type, struct sock *skip_sk)
1397{
1398 struct mgmt_ev_device_unpaired ev;
1399
1400 bacpy(&ev.addr.bdaddr, bdaddr);
1401 ev.addr.type = addr_type;
1402
1403 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
1404 skip_sk);
1405}
1406
Johan Hedberg124f6e32012-02-09 13:50:12 +02001407static int unpair_device(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001408{
1409 struct hci_dev *hdev;
Johan Hedberg124f6e32012-02-09 13:50:12 +02001410 struct mgmt_cp_unpair_device *cp = data;
1411 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001412 struct hci_cp_disconnect dc;
1413 struct pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001414 struct hci_conn *conn;
Johan Hedbergaee9b212012-02-18 15:07:59 +02001415 u8 status = 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001416 int err;
1417
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001418 if (len != sizeof(*cp))
Johan Hedberg124f6e32012-02-09 13:50:12 +02001419 return cmd_status(sk, index, MGMT_OP_UNPAIR_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02001420 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001421
Szymon Janc4e51eae2011-02-25 19:05:48 +01001422 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001423 if (!hdev)
Johan Hedberg124f6e32012-02-09 13:50:12 +02001424 return cmd_status(sk, index, MGMT_OP_UNPAIR_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02001425 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001426
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001427 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001428
Johan Hedberga8a1d192011-11-10 15:54:38 +02001429 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02001430 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1431 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001432
Johan Hedberg124f6e32012-02-09 13:50:12 +02001433 if (cp->addr.type == MGMT_ADDR_BREDR)
1434 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
1435 else
1436 err = hci_remove_ltk(hdev, &cp->addr.bdaddr);
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03001437
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001438 if (err < 0) {
Johan Hedbergaee9b212012-02-18 15:07:59 +02001439 status = MGMT_STATUS_NOT_PAIRED;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001440 goto unlock;
1441 }
1442
Johan Hedberga8a1d192011-11-10 15:54:38 +02001443 if (!test_bit(HCI_UP, &hdev->flags) || !cp->disconnect) {
Johan Hedbergaee9b212012-02-18 15:07:59 +02001444 err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE, status,
1445 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001446 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001447 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001448 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001449
Johan Hedberg124f6e32012-02-09 13:50:12 +02001450 if (cp->addr.type == MGMT_ADDR_BREDR)
1451 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
1452 &cp->addr.bdaddr);
1453 else
1454 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
1455 &cp->addr.bdaddr);
1456
Johan Hedberga8a1d192011-11-10 15:54:38 +02001457 if (!conn) {
Johan Hedbergaee9b212012-02-18 15:07:59 +02001458 err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE, status,
1459 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001460 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001461 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001462 }
1463
Johan Hedberg124f6e32012-02-09 13:50:12 +02001464 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
1465 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02001466 if (!cmd) {
1467 err = -ENOMEM;
1468 goto unlock;
1469 }
1470
1471 put_unaligned_le16(conn->handle, &dc.handle);
1472 dc.reason = 0x13; /* Remote User Terminated Connection */
1473 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1474 if (err < 0)
1475 mgmt_pending_remove(cmd);
1476
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001477unlock:
Johan Hedbergca69b792011-11-11 18:10:00 +02001478 if (err < 0)
Johan Hedbergaee9b212012-02-18 15:07:59 +02001479 err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE, status,
1480 &rp, sizeof(rp));
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001481 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001482 hci_dev_put(hdev);
1483
1484 return err;
1485}
1486
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001487static int disconnect(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02001488{
1489 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001490 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001491 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03001492 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001493 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001494 int err;
1495
1496 BT_DBG("");
1497
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001498 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001499 return cmd_status(sk, index, MGMT_OP_DISCONNECT,
1500 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001501
Szymon Janc4e51eae2011-02-25 19:05:48 +01001502 hdev = hci_dev_get(index);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001503 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001504 return cmd_status(sk, index, MGMT_OP_DISCONNECT,
1505 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001506
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001507 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001508
1509 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001510 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1511 MGMT_STATUS_NOT_POWERED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001512 goto failed;
1513 }
1514
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001515 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001516 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1517 MGMT_STATUS_BUSY);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001518 goto failed;
1519 }
1520
Johan Hedberg88c3df12012-02-09 14:27:38 +02001521 if (cp->addr.type == MGMT_ADDR_BREDR)
1522 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
1523 else
1524 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03001525
Johan Hedberg8962ee72011-01-20 12:40:27 +02001526 if (!conn) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001527 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1528 MGMT_STATUS_NOT_CONNECTED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001529 goto failed;
1530 }
1531
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001532 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001533 if (!cmd) {
1534 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001535 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001536 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001537
1538 put_unaligned_le16(conn->handle, &dc.handle);
1539 dc.reason = 0x13; /* Remote User Terminated Connection */
1540
1541 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1542 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001543 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001544
1545failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001546 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001547 hci_dev_put(hdev);
1548
1549 return err;
1550}
1551
Johan Hedberg48264f02011-11-09 13:58:58 +02001552static u8 link_to_mgmt(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02001553{
1554 switch (link_type) {
1555 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02001556 switch (addr_type) {
1557 case ADDR_LE_DEV_PUBLIC:
1558 return MGMT_ADDR_LE_PUBLIC;
1559 case ADDR_LE_DEV_RANDOM:
1560 return MGMT_ADDR_LE_RANDOM;
1561 default:
1562 return MGMT_ADDR_INVALID;
1563 }
Johan Hedberg4c659c32011-11-07 23:13:39 +02001564 case ACL_LINK:
1565 return MGMT_ADDR_BREDR;
1566 default:
1567 return MGMT_ADDR_INVALID;
1568 }
1569}
1570
Szymon Janc8ce62842011-03-01 16:55:32 +01001571static int get_connections(struct sock *sk, u16 index)
Johan Hedberg2784eb42011-01-21 13:56:35 +02001572{
Johan Hedberg2784eb42011-01-21 13:56:35 +02001573 struct mgmt_rp_get_connections *rp;
1574 struct hci_dev *hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001575 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02001576 size_t rp_len;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001577 u16 count;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001578 int i, err;
1579
1580 BT_DBG("");
1581
Szymon Janc4e51eae2011-02-25 19:05:48 +01001582 hdev = hci_dev_get(index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001583 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001584 return cmd_status(sk, index, MGMT_OP_GET_CONNECTIONS,
1585 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001586
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001587 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001588
1589 count = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02001590 list_for_each_entry(c, &hdev->conn_hash.list, list) {
1591 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
1592 count++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001593 }
1594
Johan Hedberg4c659c32011-11-07 23:13:39 +02001595 rp_len = sizeof(*rp) + (count * sizeof(struct mgmt_addr_info));
Johan Hedberga38528f2011-01-22 06:46:43 +02001596 rp = kmalloc(rp_len, GFP_ATOMIC);
1597 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02001598 err = -ENOMEM;
1599 goto unlock;
1600 }
1601
Johan Hedberg2784eb42011-01-21 13:56:35 +02001602 put_unaligned_le16(count, &rp->conn_count);
1603
Johan Hedberg2784eb42011-01-21 13:56:35 +02001604 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001605 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02001606 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
1607 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001608 bacpy(&rp->addr[i].bdaddr, &c->dst);
Johan Hedberg48264f02011-11-09 13:58:58 +02001609 rp->addr[i].type = link_to_mgmt(c->type, c->dst_type);
Johan Hedberg4c659c32011-11-07 23:13:39 +02001610 if (rp->addr[i].type == MGMT_ADDR_INVALID)
1611 continue;
1612 i++;
1613 }
1614
1615 /* Recalculate length in case of filtered SCO connections, etc */
1616 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02001617
Johan Hedbergaee9b212012-02-18 15:07:59 +02001618 err = cmd_complete(sk, index, MGMT_OP_GET_CONNECTIONS, 0, rp, rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001619
1620unlock:
Johan Hedberga38528f2011-01-22 06:46:43 +02001621 kfree(rp);
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001622 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001623 hci_dev_put(hdev);
1624 return err;
1625}
1626
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001627static int send_pin_code_neg_reply(struct sock *sk, u16 index,
1628 struct hci_dev *hdev, struct mgmt_cp_pin_code_neg_reply *cp)
1629{
1630 struct pending_cmd *cmd;
1631 int err;
1632
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001633 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001634 sizeof(*cp));
1635 if (!cmd)
1636 return -ENOMEM;
1637
Johan Hedbergd8457692012-02-17 14:24:57 +02001638 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
1639 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001640 if (err < 0)
1641 mgmt_pending_remove(cmd);
1642
1643 return err;
1644}
1645
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001646static int pin_code_reply(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001647{
1648 struct hci_dev *hdev;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001649 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001650 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001651 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03001652 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001653 int err;
1654
1655 BT_DBG("");
1656
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001657 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001658 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1659 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001660
Szymon Janc4e51eae2011-02-25 19:05:48 +01001661 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001662 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001663 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1664 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001665
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001666 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001667
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001668 if (!hdev_is_powered(hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001669 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1670 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001671 goto failed;
1672 }
1673
Johan Hedbergd8457692012-02-17 14:24:57 +02001674 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001675 if (!conn) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001676 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1677 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001678 goto failed;
1679 }
1680
1681 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02001682 struct mgmt_cp_pin_code_neg_reply ncp;
1683
1684 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001685
1686 BT_ERR("PIN code is not 16 bytes long");
1687
1688 err = send_pin_code_neg_reply(sk, index, hdev, &ncp);
1689 if (err >= 0)
1690 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001691 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001692
1693 goto failed;
1694 }
1695
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001696 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data,
1697 len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001698 if (!cmd) {
1699 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001700 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001701 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02001702
Johan Hedbergd8457692012-02-17 14:24:57 +02001703 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001704 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02001705 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02001706
1707 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
1708 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001709 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001710
1711failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001712 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001713 hci_dev_put(hdev);
1714
1715 return err;
1716}
1717
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001718static int pin_code_neg_reply(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001719{
1720 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001721 struct mgmt_cp_pin_code_neg_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001722 int err;
1723
1724 BT_DBG("");
1725
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001726 if (len != sizeof(*cp))
1727 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001728 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001729
Szymon Janc4e51eae2011-02-25 19:05:48 +01001730 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001731 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001732 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001733 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001734
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001735 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001736
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001737 if (!hdev_is_powered(hdev)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001738 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001739 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001740 goto failed;
1741 }
1742
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001743 err = send_pin_code_neg_reply(sk, index, hdev, cp);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001744
1745failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001746 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001747 hci_dev_put(hdev);
1748
1749 return err;
1750}
1751
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001752static int set_io_capability(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001753{
1754 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001755 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001756
1757 BT_DBG("");
1758
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001759 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001760 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY,
1761 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001762
Szymon Janc4e51eae2011-02-25 19:05:48 +01001763 hdev = hci_dev_get(index);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001764 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001765 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY,
1766 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001767
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001768 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001769
1770 hdev->io_capability = cp->io_capability;
1771
1772 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Szymon Jancb8534e02011-03-01 16:55:34 +01001773 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001774
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001775 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001776 hci_dev_put(hdev);
1777
Johan Hedbergaee9b212012-02-18 15:07:59 +02001778 return cmd_complete(sk, index, MGMT_OP_SET_IO_CAPABILITY, 0, NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001779}
1780
Johan Hedberge9a416b2011-02-19 12:05:56 -03001781static inline struct pending_cmd *find_pairing(struct hci_conn *conn)
1782{
1783 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001784 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001785
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001786 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03001787 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
1788 continue;
1789
Johan Hedberge9a416b2011-02-19 12:05:56 -03001790 if (cmd->user_data != conn)
1791 continue;
1792
1793 return cmd;
1794 }
1795
1796 return NULL;
1797}
1798
1799static void pairing_complete(struct pending_cmd *cmd, u8 status)
1800{
1801 struct mgmt_rp_pair_device rp;
1802 struct hci_conn *conn = cmd->user_data;
1803
Johan Hedbergba4e5642011-11-11 00:07:34 +02001804 bacpy(&rp.addr.bdaddr, &conn->dst);
1805 rp.addr.type = link_to_mgmt(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001806
Johan Hedbergaee9b212012-02-18 15:07:59 +02001807 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, status,
1808 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001809
1810 /* So we don't get further callbacks for this connection */
1811 conn->connect_cfm_cb = NULL;
1812 conn->security_cfm_cb = NULL;
1813 conn->disconn_cfm_cb = NULL;
1814
1815 hci_conn_put(conn);
1816
Johan Hedberga664b5b2011-02-19 12:06:02 -03001817 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001818}
1819
1820static void pairing_complete_cb(struct hci_conn *conn, u8 status)
1821{
1822 struct pending_cmd *cmd;
1823
1824 BT_DBG("status %u", status);
1825
Johan Hedberg56e5cb82011-11-08 20:40:16 +02001826 cmd = find_pairing(conn);
1827 if (!cmd)
1828 BT_DBG("Unable to find a pending command");
1829 else
Johan Hedberge2113262012-02-18 15:20:03 +02001830 pairing_complete(cmd, mgmt_status(status));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001831}
1832
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001833static int pair_device(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001834{
1835 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001836 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02001837 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001838 struct pending_cmd *cmd;
1839 u8 sec_level, auth_type;
1840 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001841 int err;
1842
1843 BT_DBG("");
1844
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001845 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001846 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE,
1847 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001848
Szymon Janc4e51eae2011-02-25 19:05:48 +01001849 hdev = hci_dev_get(index);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001850 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001851 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE,
1852 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001853
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001854 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001855
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001856 sec_level = BT_SECURITY_MEDIUM;
1857 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001858 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001859 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03001860 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001861
Johan Hedbergba4e5642011-11-11 00:07:34 +02001862 if (cp->addr.type == MGMT_ADDR_BREDR)
1863 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr, sec_level,
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001864 auth_type);
1865 else
Johan Hedbergba4e5642011-11-11 00:07:34 +02001866 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr, sec_level,
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001867 auth_type);
1868
Johan Hedberg1425acb2011-11-11 00:07:35 +02001869 memset(&rp, 0, sizeof(rp));
1870 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1871 rp.addr.type = cp->addr.type;
1872
Ville Tervo30e76272011-02-22 16:10:53 -03001873 if (IS_ERR(conn)) {
Johan Hedberge2113262012-02-18 15:20:03 +02001874 err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE,
1875 MGMT_STATUS_CONNECT_FAILED,
1876 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001877 goto unlock;
1878 }
1879
1880 if (conn->connect_cfm_cb) {
1881 hci_conn_put(conn);
Johan Hedberge2113262012-02-18 15:20:03 +02001882 err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE,
1883 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001884 goto unlock;
1885 }
1886
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001887 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001888 if (!cmd) {
1889 err = -ENOMEM;
1890 hci_conn_put(conn);
1891 goto unlock;
1892 }
1893
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001894 /* For LE, just connecting isn't a proof that the pairing finished */
Johan Hedbergba4e5642011-11-11 00:07:34 +02001895 if (cp->addr.type == MGMT_ADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001896 conn->connect_cfm_cb = pairing_complete_cb;
1897
Johan Hedberge9a416b2011-02-19 12:05:56 -03001898 conn->security_cfm_cb = pairing_complete_cb;
1899 conn->disconn_cfm_cb = pairing_complete_cb;
1900 conn->io_capability = cp->io_cap;
1901 cmd->user_data = conn;
1902
1903 if (conn->state == BT_CONNECTED &&
1904 hci_conn_security(conn, sec_level, auth_type))
1905 pairing_complete(cmd, 0);
1906
1907 err = 0;
1908
1909unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001910 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001911 hci_dev_put(hdev);
1912
1913 return err;
1914}
1915
Johan Hedberg28424702012-02-02 04:02:29 +02001916static int cancel_pair_device(struct sock *sk, u16 index,
1917 unsigned char *data, u16 len)
1918{
1919 struct mgmt_addr_info *addr = (void *) data;
1920 struct hci_dev *hdev;
1921 struct pending_cmd *cmd;
1922 struct hci_conn *conn;
1923 int err;
1924
1925 BT_DBG("");
1926
1927 if (len != sizeof(*addr))
1928 return cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
1929 MGMT_STATUS_INVALID_PARAMS);
1930
1931 hdev = hci_dev_get(index);
1932 if (!hdev)
1933 return cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
1934 MGMT_STATUS_INVALID_PARAMS);
1935
1936 hci_dev_lock(hdev);
1937
1938 cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
1939 if (!cmd) {
1940 err = cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
1941 MGMT_STATUS_INVALID_PARAMS);
1942 goto unlock;
1943 }
1944
1945 conn = cmd->user_data;
1946
1947 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
1948 err = cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
1949 MGMT_STATUS_INVALID_PARAMS);
1950 goto unlock;
1951 }
1952
1953 pairing_complete(cmd, MGMT_STATUS_CANCELLED);
1954
Johan Hedbergaee9b212012-02-18 15:07:59 +02001955 err = cmd_complete(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE, 0, addr,
Johan Hedberg28424702012-02-02 04:02:29 +02001956 sizeof(*addr));
1957unlock:
1958 hci_dev_unlock(hdev);
1959 hci_dev_put(hdev);
1960
1961 return err;
1962}
1963
Brian Gix0df4c182011-11-16 13:53:13 -08001964static int user_pairing_resp(struct sock *sk, u16 index, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02001965 u8 type, u16 mgmt_op, u16 hci_op,
1966 __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03001967{
Johan Hedberga5c29682011-02-19 12:05:57 -03001968 struct pending_cmd *cmd;
1969 struct hci_dev *hdev;
Brian Gix0df4c182011-11-16 13:53:13 -08001970 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03001971 int err;
1972
Szymon Janc4e51eae2011-02-25 19:05:48 +01001973 hdev = hci_dev_get(index);
Johan Hedberga5c29682011-02-19 12:05:57 -03001974 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001975 return cmd_status(sk, index, mgmt_op,
1976 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga5c29682011-02-19 12:05:57 -03001977
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001978 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02001979
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001980 if (!hdev_is_powered(hdev)) {
Brian Gix0df4c182011-11-16 13:53:13 -08001981 err = cmd_status(sk, index, mgmt_op, MGMT_STATUS_NOT_POWERED);
1982 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03001983 }
1984
Johan Hedberg272d90d2012-02-09 15:26:12 +02001985 if (type == MGMT_ADDR_BREDR)
1986 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, bdaddr);
1987 else
Brian Gix47c15e22011-11-16 13:53:14 -08001988 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, bdaddr);
Brian Gix47c15e22011-11-16 13:53:14 -08001989
Johan Hedberg272d90d2012-02-09 15:26:12 +02001990 if (!conn) {
1991 err = cmd_status(sk, index, mgmt_op,
1992 MGMT_STATUS_NOT_CONNECTED);
1993 goto done;
1994 }
1995
1996 if (type == MGMT_ADDR_LE_PUBLIC || type == MGMT_ADDR_LE_RANDOM) {
Brian Gix47c15e22011-11-16 13:53:14 -08001997 /* Continue with pairing via SMP */
Brian Gix5fe57d92011-12-21 16:12:13 -08001998 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix47c15e22011-11-16 13:53:14 -08001999
Brian Gix5fe57d92011-12-21 16:12:13 -08002000 if (!err)
2001 err = cmd_status(sk, index, mgmt_op,
2002 MGMT_STATUS_SUCCESS);
2003 else
2004 err = cmd_status(sk, index, mgmt_op,
2005 MGMT_STATUS_FAILED);
2006
Brian Gix47c15e22011-11-16 13:53:14 -08002007 goto done;
2008 }
2009
Brian Gix0df4c182011-11-16 13:53:13 -08002010 cmd = mgmt_pending_add(sk, mgmt_op, hdev, bdaddr, sizeof(*bdaddr));
Johan Hedberga5c29682011-02-19 12:05:57 -03002011 if (!cmd) {
2012 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08002013 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002014 }
2015
Brian Gix0df4c182011-11-16 13:53:13 -08002016 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08002017 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
2018 struct hci_cp_user_passkey_reply cp;
2019
2020 bacpy(&cp.bdaddr, bdaddr);
2021 cp.passkey = passkey;
2022 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
2023 } else
2024 err = hci_send_cmd(hdev, hci_op, sizeof(*bdaddr), bdaddr);
2025
Johan Hedberga664b5b2011-02-19 12:06:02 -03002026 if (err < 0)
2027 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002028
Brian Gix0df4c182011-11-16 13:53:13 -08002029done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002030 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002031 hci_dev_put(hdev);
2032
2033 return err;
2034}
2035
Brian Gix0df4c182011-11-16 13:53:13 -08002036static int user_confirm_reply(struct sock *sk, u16 index, void *data, u16 len)
2037{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002038 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002039
2040 BT_DBG("");
2041
2042 if (len != sizeof(*cp))
2043 return cmd_status(sk, index, MGMT_OP_USER_CONFIRM_REPLY,
2044 MGMT_STATUS_INVALID_PARAMS);
2045
Johan Hedberg272d90d2012-02-09 15:26:12 +02002046 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
2047 MGMT_OP_USER_CONFIRM_REPLY,
2048 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002049}
2050
2051static int user_confirm_neg_reply(struct sock *sk, u16 index, void *data,
2052 u16 len)
2053{
Johan Hedbergc9c26592011-12-15 00:47:41 +02002054 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002055
2056 BT_DBG("");
2057
2058 if (len != sizeof(*cp))
2059 return cmd_status(sk, index, MGMT_OP_USER_CONFIRM_NEG_REPLY,
2060 MGMT_STATUS_INVALID_PARAMS);
2061
Johan Hedberg272d90d2012-02-09 15:26:12 +02002062 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
2063 MGMT_OP_USER_CONFIRM_NEG_REPLY,
2064 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002065}
2066
Brian Gix604086b2011-11-23 08:28:33 -08002067static int user_passkey_reply(struct sock *sk, u16 index, void *data, u16 len)
2068{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002069 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002070
2071 BT_DBG("");
2072
2073 if (len != sizeof(*cp))
2074 return cmd_status(sk, index, MGMT_OP_USER_PASSKEY_REPLY,
2075 EINVAL);
2076
Johan Hedberg272d90d2012-02-09 15:26:12 +02002077 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
2078 MGMT_OP_USER_PASSKEY_REPLY,
2079 HCI_OP_USER_PASSKEY_REPLY,
2080 cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08002081}
2082
2083static int user_passkey_neg_reply(struct sock *sk, u16 index, void *data,
2084 u16 len)
2085{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002086 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002087
2088 BT_DBG("");
2089
2090 if (len != sizeof(*cp))
2091 return cmd_status(sk, index, MGMT_OP_USER_PASSKEY_NEG_REPLY,
2092 EINVAL);
2093
Johan Hedberg272d90d2012-02-09 15:26:12 +02002094 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
2095 MGMT_OP_USER_PASSKEY_NEG_REPLY,
2096 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08002097}
2098
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002099static int set_local_name(struct sock *sk, u16 index, void *data,
Johan Hedbergb312b1612011-03-16 14:29:37 +02002100 u16 len)
2101{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002102 struct mgmt_cp_set_local_name *mgmt_cp = data;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002103 struct hci_cp_write_local_name hci_cp;
2104 struct hci_dev *hdev;
2105 struct pending_cmd *cmd;
2106 int err;
2107
2108 BT_DBG("");
2109
2110 if (len != sizeof(*mgmt_cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02002111 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME,
2112 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002113
2114 hdev = hci_dev_get(index);
2115 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002116 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME,
2117 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002118
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002119 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002120
Johan Hedbergb5235a62012-02-21 14:32:24 +02002121 if (!hdev_is_powered(hdev)) {
2122 err = cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME,
2123 MGMT_STATUS_NOT_POWERED);
2124 goto failed;
2125 }
2126
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002127 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data,
2128 len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002129 if (!cmd) {
2130 err = -ENOMEM;
2131 goto failed;
2132 }
2133
2134 memcpy(hci_cp.name, mgmt_cp->name, sizeof(hci_cp.name));
2135 err = hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(hci_cp),
2136 &hci_cp);
2137 if (err < 0)
2138 mgmt_pending_remove(cmd);
2139
2140failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002141 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002142 hci_dev_put(hdev);
2143
2144 return err;
2145}
2146
Szymon Jancc35938b2011-03-22 13:12:21 +01002147static int read_local_oob_data(struct sock *sk, u16 index)
2148{
2149 struct hci_dev *hdev;
2150 struct pending_cmd *cmd;
2151 int err;
2152
2153 BT_DBG("hci%u", index);
2154
2155 hdev = hci_dev_get(index);
2156 if (!hdev)
2157 return cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002158 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancc35938b2011-03-22 13:12:21 +01002159
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002160 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002161
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002162 if (!hdev_is_powered(hdev)) {
Szymon Jancc35938b2011-03-22 13:12:21 +01002163 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002164 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002165 goto unlock;
2166 }
2167
2168 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
2169 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002170 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002171 goto unlock;
2172 }
2173
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002174 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02002175 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2176 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01002177 goto unlock;
2178 }
2179
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002180 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01002181 if (!cmd) {
2182 err = -ENOMEM;
2183 goto unlock;
2184 }
2185
2186 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
2187 if (err < 0)
2188 mgmt_pending_remove(cmd);
2189
2190unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002191 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002192 hci_dev_put(hdev);
2193
2194 return err;
2195}
2196
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002197static int add_remote_oob_data(struct sock *sk, u16 index, void *data,
2198 u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002199{
2200 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002201 struct mgmt_cp_add_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002202 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002203 int err;
2204
2205 BT_DBG("hci%u ", index);
2206
2207 if (len != sizeof(*cp))
2208 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002209 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01002210
2211 hdev = hci_dev_get(index);
2212 if (!hdev)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002213 return cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
2214 MGMT_STATUS_INVALID_PARAMS,
2215 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002216
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002217 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002218
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002219 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, cp->hash,
Szymon Janc2763eda2011-03-22 13:12:22 +01002220 cp->randomizer);
2221 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002222 status = MGMT_STATUS_FAILED;
Szymon Janc2763eda2011-03-22 13:12:22 +01002223 else
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002224 status = 0;
2225
2226 err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, status,
2227 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002228
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002229 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002230 hci_dev_put(hdev);
2231
2232 return err;
2233}
2234
2235static int remove_remote_oob_data(struct sock *sk, u16 index,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002236 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002237{
2238 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002239 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002240 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002241 int err;
2242
2243 BT_DBG("hci%u ", index);
2244
2245 if (len != sizeof(*cp))
2246 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002247 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01002248
2249 hdev = hci_dev_get(index);
2250 if (!hdev)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002251 return cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2252 MGMT_STATUS_INVALID_PARAMS,
2253 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002254
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002255 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002256
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002257 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr);
Szymon Janc2763eda2011-03-22 13:12:22 +01002258 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002259 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01002260 else
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002261 status = 0;
2262
2263 err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA, status,
2264 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002265
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002266 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002267 hci_dev_put(hdev);
2268
2269 return err;
2270}
2271
Andre Guedes5e0452c2012-02-17 20:39:38 -03002272static int discovery(struct hci_dev *hdev)
2273{
2274 int err;
2275
2276 if (lmp_host_le_capable(hdev)) {
2277 if (lmp_bredr_capable(hdev)) {
2278 err = hci_le_scan(hdev, LE_SCAN_TYPE,
2279 LE_SCAN_INT, LE_SCAN_WIN,
2280 LE_SCAN_TIMEOUT_BREDR_LE);
2281 } else {
2282 hdev->discovery.type = DISCOV_TYPE_LE;
2283 err = hci_le_scan(hdev, LE_SCAN_TYPE,
2284 LE_SCAN_INT, LE_SCAN_WIN,
2285 LE_SCAN_TIMEOUT_LE_ONLY);
2286 }
2287 } else {
2288 hdev->discovery.type = DISCOV_TYPE_BREDR;
2289 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
2290 }
2291
2292 return err;
2293}
2294
2295int mgmt_interleaved_discovery(struct hci_dev *hdev)
2296{
2297 int err;
2298
2299 BT_DBG("%s", hdev->name);
2300
2301 hci_dev_lock(hdev);
2302
2303 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR_LE);
2304 if (err < 0)
2305 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2306
2307 hci_dev_unlock(hdev);
2308
2309 return err;
2310}
2311
Johan Hedberg450dfda2011-11-12 11:58:22 +02002312static int start_discovery(struct sock *sk, u16 index,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002313 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002314{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002315 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002316 struct pending_cmd *cmd;
2317 struct hci_dev *hdev;
2318 int err;
2319
2320 BT_DBG("hci%u", index);
2321
Johan Hedberg450dfda2011-11-12 11:58:22 +02002322 if (len != sizeof(*cp))
2323 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2324 MGMT_STATUS_INVALID_PARAMS);
2325
Johan Hedberg14a53662011-04-27 10:29:56 -04002326 hdev = hci_dev_get(index);
2327 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002328 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2329 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg14a53662011-04-27 10:29:56 -04002330
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002331 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002332
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002333 if (!hdev_is_powered(hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02002334 err = cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2335 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02002336 goto failed;
2337 }
2338
Johan Hedbergff9ef572012-01-04 14:23:45 +02002339 if (hdev->discovery.state != DISCOVERY_STOPPED) {
2340 err = cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2341 MGMT_STATUS_BUSY);
2342 goto failed;
2343 }
2344
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002345 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002346 if (!cmd) {
2347 err = -ENOMEM;
2348 goto failed;
2349 }
2350
Andre Guedes4aab14e2012-02-17 20:39:36 -03002351 hdev->discovery.type = cp->type;
2352
2353 switch (hdev->discovery.type) {
Andre Guedesf39799f2012-02-17 20:39:35 -03002354 case DISCOV_TYPE_BREDR:
Andre Guedes3fd24152012-02-03 17:48:01 -03002355 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
Andre Guedesf39799f2012-02-17 20:39:35 -03002356 break;
2357
2358 case DISCOV_TYPE_LE:
Andre Guedes3fd24152012-02-03 17:48:01 -03002359 err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT,
2360 LE_SCAN_WIN, LE_SCAN_TIMEOUT_LE_ONLY);
Andre Guedesf39799f2012-02-17 20:39:35 -03002361 break;
2362
Andre Guedes5e0452c2012-02-17 20:39:38 -03002363 case DISCOV_TYPE_INTERLEAVED:
2364 err = discovery(hdev);
2365 break;
2366
Andre Guedesf39799f2012-02-17 20:39:35 -03002367 default:
Andre Guedes3fd24152012-02-03 17:48:01 -03002368 err = -EINVAL;
Andre Guedesf39799f2012-02-17 20:39:35 -03002369 }
Andre Guedes3fd24152012-02-03 17:48:01 -03002370
Johan Hedberg14a53662011-04-27 10:29:56 -04002371 if (err < 0)
2372 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002373 else
2374 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002375
2376failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002377 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002378 hci_dev_put(hdev);
2379
2380 return err;
2381}
2382
Johan Hedbergd9306502012-02-20 23:25:18 +02002383static int stop_discovery(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002384{
Johan Hedbergd9306502012-02-20 23:25:18 +02002385 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002386 struct hci_dev *hdev;
2387 struct pending_cmd *cmd;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002388 struct hci_cp_remote_name_req_cancel cp;
2389 struct inquiry_entry *e;
Johan Hedberg14a53662011-04-27 10:29:56 -04002390 int err;
2391
2392 BT_DBG("hci%u", index);
2393
Johan Hedbergd9306502012-02-20 23:25:18 +02002394 if (len != sizeof(*mgmt_cp))
2395 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY,
2396 MGMT_STATUS_INVALID_PARAMS);
2397
Johan Hedberg14a53662011-04-27 10:29:56 -04002398 hdev = hci_dev_get(index);
2399 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002400 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY,
2401 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg14a53662011-04-27 10:29:56 -04002402
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002403 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002404
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002405 if (!hci_discovery_active(hdev)) {
Johan Hedbergd9306502012-02-20 23:25:18 +02002406 err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY,
2407 MGMT_STATUS_REJECTED,
2408 &mgmt_cp->type, sizeof(mgmt_cp->type));
2409 goto unlock;
2410 }
2411
2412 if (hdev->discovery.type != mgmt_cp->type) {
2413 err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY,
2414 MGMT_STATUS_INVALID_PARAMS,
2415 &mgmt_cp->type, sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002416 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02002417 }
2418
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002419 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002420 if (!cmd) {
2421 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002422 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04002423 }
2424
Andre Guedes343f9352012-02-17 20:39:37 -03002425 if (hdev->discovery.state == DISCOVERY_FINDING) {
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002426 err = hci_cancel_inquiry(hdev);
2427 if (err < 0)
2428 mgmt_pending_remove(cmd);
2429 else
2430 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
2431 goto unlock;
2432 }
2433
2434 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY, NAME_PENDING);
2435 if (!e) {
2436 mgmt_pending_remove(cmd);
Johan Hedbergaee9b212012-02-18 15:07:59 +02002437 err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY, 0,
Johan Hedbergd9306502012-02-20 23:25:18 +02002438 &mgmt_cp->type, sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002439 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2440 goto unlock;
2441 }
2442
2443 bacpy(&cp.bdaddr, &e->data.bdaddr);
2444 err = hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ_CANCEL,
2445 sizeof(cp), &cp);
Johan Hedberg14a53662011-04-27 10:29:56 -04002446 if (err < 0)
2447 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002448 else
2449 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002450
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002451unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002452 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002453 hci_dev_put(hdev);
2454
2455 return err;
2456}
2457
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002458static int confirm_name(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02002459{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002460 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002461 struct inquiry_entry *e;
2462 struct hci_dev *hdev;
2463 int err;
2464
2465 BT_DBG("hci%u", index);
2466
2467 if (len != sizeof(*cp))
2468 return cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2469 MGMT_STATUS_INVALID_PARAMS);
2470
2471 hdev = hci_dev_get(index);
2472 if (!hdev)
2473 return cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2474 MGMT_STATUS_INVALID_PARAMS);
2475
2476 hci_dev_lock(hdev);
2477
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002478 if (!hci_discovery_active(hdev)) {
2479 err = cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2480 MGMT_STATUS_FAILED);
2481 goto failed;
2482 }
2483
Johan Hedberga198e7b2012-02-17 14:27:06 +02002484 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002485 if (!e) {
2486 err = cmd_status (sk, index, MGMT_OP_CONFIRM_NAME,
2487 MGMT_STATUS_INVALID_PARAMS);
2488 goto failed;
2489 }
2490
2491 if (cp->name_known) {
2492 e->name_state = NAME_KNOWN;
2493 list_del(&e->list);
2494 } else {
2495 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e202012-01-09 00:53:02 +02002496 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002497 }
2498
2499 err = 0;
2500
2501failed:
2502 hci_dev_unlock(hdev);
2503
2504 return err;
2505}
2506
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002507static int block_device(struct sock *sk, u16 index, void *data, u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002508{
2509 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002510 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002511 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03002512 int err;
2513
2514 BT_DBG("hci%u", index);
2515
Antti Julku7fbec222011-06-15 12:01:15 +03002516 if (len != sizeof(*cp))
2517 return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002518 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002519
2520 hdev = hci_dev_get(index);
2521 if (!hdev)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002522 return cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE,
2523 MGMT_STATUS_INVALID_PARAMS,
2524 &cp->addr, sizeof(cp->addr));
Antti Julku7fbec222011-06-15 12:01:15 +03002525
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002526 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002527
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002528 err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002529 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002530 status = MGMT_STATUS_FAILED;
Antti Julku7fbec222011-06-15 12:01:15 +03002531 else
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002532 status = 0;
2533
2534 err = cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE, status,
2535 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03002536
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002537 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002538 hci_dev_put(hdev);
2539
2540 return err;
2541}
2542
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002543static int unblock_device(struct sock *sk, u16 index, void *data, u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002544{
2545 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002546 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002547 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03002548 int err;
2549
2550 BT_DBG("hci%u", index);
2551
Antti Julku7fbec222011-06-15 12:01:15 +03002552 if (len != sizeof(*cp))
2553 return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002554 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002555
2556 hdev = hci_dev_get(index);
2557 if (!hdev)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002558 return cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE,
2559 MGMT_STATUS_INVALID_PARAMS,
2560 &cp->addr, sizeof(cp->addr));
Antti Julku7fbec222011-06-15 12:01:15 +03002561
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002562 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002563
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002564 err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002565 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002566 status = MGMT_STATUS_INVALID_PARAMS;
Antti Julku7fbec222011-06-15 12:01:15 +03002567 else
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002568 status = 0;
2569
2570 err = cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE, status,
2571 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03002572
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002573 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002574 hci_dev_put(hdev);
2575
2576 return err;
2577}
2578
Antti Julkuf6422ec2011-06-22 13:11:56 +03002579static int set_fast_connectable(struct sock *sk, u16 index,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002580 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03002581{
2582 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002583 struct mgmt_mode *cp = data;
Antti Julkuf6422ec2011-06-22 13:11:56 +03002584 struct hci_cp_write_page_scan_activity acp;
2585 u8 type;
2586 int err;
2587
2588 BT_DBG("hci%u", index);
2589
2590 if (len != sizeof(*cp))
2591 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002592 MGMT_STATUS_INVALID_PARAMS);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002593
2594 hdev = hci_dev_get(index);
2595 if (!hdev)
2596 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002597 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg5400c042012-02-21 16:40:33 +02002598 if (!hdev_is_powered(hdev))
2599 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
2600 MGMT_STATUS_NOT_POWERED);
2601
2602 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
2603 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
2604 MGMT_STATUS_REJECTED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002605
2606 hci_dev_lock(hdev);
2607
Johan Hedbergf7c6869ce2011-12-15 00:47:36 +02002608 if (cp->val) {
Antti Julkuf6422ec2011-06-22 13:11:56 +03002609 type = PAGE_SCAN_TYPE_INTERLACED;
2610 acp.interval = 0x0024; /* 22.5 msec page scan interval */
2611 } else {
2612 type = PAGE_SCAN_TYPE_STANDARD; /* default */
2613 acp.interval = 0x0800; /* default 1.28 sec page scan */
2614 }
2615
2616 acp.window = 0x0012; /* default 11.25 msec page scan window */
2617
2618 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
2619 sizeof(acp), &acp);
2620 if (err < 0) {
2621 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002622 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002623 goto done;
2624 }
2625
2626 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
2627 if (err < 0) {
2628 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002629 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002630 goto done;
2631 }
2632
Johan Hedbergaee9b212012-02-18 15:07:59 +02002633 err = cmd_complete(sk, index, MGMT_OP_SET_FAST_CONNECTABLE, 0,
2634 NULL, 0);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002635done:
2636 hci_dev_unlock(hdev);
2637 hci_dev_put(hdev);
2638
2639 return err;
2640}
2641
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002642static int load_long_term_keys(struct sock *sk, u16 index,
2643 void *cp_data, u16 len)
2644{
2645 struct hci_dev *hdev;
2646 struct mgmt_cp_load_long_term_keys *cp = cp_data;
2647 u16 key_count, expected_len;
2648 int i;
2649
2650 if (len < sizeof(*cp))
2651 return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS,
2652 EINVAL);
2653
2654 key_count = get_unaligned_le16(&cp->key_count);
2655
2656 expected_len = sizeof(*cp) + key_count *
2657 sizeof(struct mgmt_ltk_info);
2658 if (expected_len != len) {
2659 BT_ERR("load_keys: expected %u bytes, got %u bytes",
2660 len, expected_len);
2661 return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS,
2662 EINVAL);
2663 }
2664
2665 hdev = hci_dev_get(index);
2666 if (!hdev)
2667 return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS,
2668 ENODEV);
2669
2670 BT_DBG("hci%u key_count %u", index, key_count);
2671
2672 hci_dev_lock(hdev);
2673
2674 hci_smp_ltks_clear(hdev);
2675
2676 for (i = 0; i < key_count; i++) {
2677 struct mgmt_ltk_info *key = &cp->keys[i];
2678 u8 type;
2679
2680 if (key->master)
2681 type = HCI_SMP_LTK;
2682 else
2683 type = HCI_SMP_LTK_SLAVE;
2684
2685 hci_add_ltk(hdev, &key->addr.bdaddr, key->addr.type,
2686 type, 0, key->authenticated, key->val,
2687 key->enc_size, key->ediv, key->rand);
2688 }
2689
2690 hci_dev_unlock(hdev);
2691 hci_dev_put(hdev);
2692
2693 return 0;
2694}
2695
Johan Hedberg03811012010-12-08 00:21:06 +02002696int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
2697{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002698 void *buf;
2699 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02002700 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002701 u16 opcode, index, len;
Johan Hedberg03811012010-12-08 00:21:06 +02002702 int err;
2703
2704 BT_DBG("got %zu bytes", msglen);
2705
2706 if (msglen < sizeof(*hdr))
2707 return -EINVAL;
2708
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03002709 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02002710 if (!buf)
2711 return -ENOMEM;
2712
2713 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
2714 err = -EFAULT;
2715 goto done;
2716 }
2717
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002718 hdr = buf;
Johan Hedberg03811012010-12-08 00:21:06 +02002719 opcode = get_unaligned_le16(&hdr->opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002720 index = get_unaligned_le16(&hdr->index);
Johan Hedberg03811012010-12-08 00:21:06 +02002721 len = get_unaligned_le16(&hdr->len);
2722
2723 if (len != msglen - sizeof(*hdr)) {
2724 err = -EINVAL;
2725 goto done;
2726 }
2727
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002728 cp = buf + sizeof(*hdr);
2729
Johan Hedberg03811012010-12-08 00:21:06 +02002730 switch (opcode) {
Johan Hedberg02d98122010-12-13 21:07:04 +02002731 case MGMT_OP_READ_VERSION:
2732 err = read_version(sk);
2733 break;
Johan Hedberge70bb2e2012-02-13 16:59:33 +02002734 case MGMT_OP_READ_COMMANDS:
2735 err = read_commands(sk);
2736 break;
Johan Hedbergfaba42e2010-12-13 21:07:05 +02002737 case MGMT_OP_READ_INDEX_LIST:
2738 err = read_index_list(sk);
2739 break;
Johan Hedbergf7b64e692010-12-13 21:07:06 +02002740 case MGMT_OP_READ_INFO:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002741 err = read_controller_info(sk, index);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02002742 break;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002743 case MGMT_OP_SET_POWERED:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002744 err = set_powered(sk, index, cp, len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002745 break;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002746 case MGMT_OP_SET_DISCOVERABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002747 err = set_discoverable(sk, index, cp, len);
Johan Hedberg73f22f62010-12-29 16:00:25 +02002748 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002749 case MGMT_OP_SET_CONNECTABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002750 err = set_connectable(sk, index, cp, len);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002751 break;
Johan Hedbergf7c6869ce2011-12-15 00:47:36 +02002752 case MGMT_OP_SET_FAST_CONNECTABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002753 err = set_fast_connectable(sk, index, cp, len);
Johan Hedbergf7c6869ce2011-12-15 00:47:36 +02002754 break;
Johan Hedbergc542a062011-01-26 13:11:03 +02002755 case MGMT_OP_SET_PAIRABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002756 err = set_pairable(sk, index, cp, len);
Johan Hedbergc542a062011-01-26 13:11:03 +02002757 break;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02002758 case MGMT_OP_SET_LINK_SECURITY:
2759 err = set_link_security(sk, index, cp, len);
2760 break;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02002761 case MGMT_OP_SET_SSP:
2762 err = set_ssp(sk, index, cp, len);
2763 break;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02002764 case MGMT_OP_SET_HS:
2765 err = set_hs(sk, index, cp, len);
2766 break;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002767 case MGMT_OP_ADD_UUID:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002768 err = add_uuid(sk, index, cp, len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002769 break;
2770 case MGMT_OP_REMOVE_UUID:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002771 err = remove_uuid(sk, index, cp, len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002772 break;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002773 case MGMT_OP_SET_DEV_CLASS:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002774 err = set_dev_class(sk, index, cp, len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002775 break;
Johan Hedberg86742e12011-11-07 23:13:38 +02002776 case MGMT_OP_LOAD_LINK_KEYS:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002777 err = load_link_keys(sk, index, cp, len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002778 break;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002779 case MGMT_OP_DISCONNECT:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002780 err = disconnect(sk, index, cp, len);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002781 break;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002782 case MGMT_OP_GET_CONNECTIONS:
Szymon Janc8ce62842011-03-01 16:55:32 +01002783 err = get_connections(sk, index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002784 break;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002785 case MGMT_OP_PIN_CODE_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002786 err = pin_code_reply(sk, index, cp, len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002787 break;
2788 case MGMT_OP_PIN_CODE_NEG_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002789 err = pin_code_neg_reply(sk, index, cp, len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002790 break;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002791 case MGMT_OP_SET_IO_CAPABILITY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002792 err = set_io_capability(sk, index, cp, len);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002793 break;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002794 case MGMT_OP_PAIR_DEVICE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002795 err = pair_device(sk, index, cp, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002796 break;
Johan Hedberg28424702012-02-02 04:02:29 +02002797 case MGMT_OP_CANCEL_PAIR_DEVICE:
2798 err = cancel_pair_device(sk, index, buf + sizeof(*hdr), len);
2799 break;
Johan Hedberg124f6e32012-02-09 13:50:12 +02002800 case MGMT_OP_UNPAIR_DEVICE:
2801 err = unpair_device(sk, index, cp, len);
2802 break;
Johan Hedberga5c29682011-02-19 12:05:57 -03002803 case MGMT_OP_USER_CONFIRM_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002804 err = user_confirm_reply(sk, index, cp, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03002805 break;
2806 case MGMT_OP_USER_CONFIRM_NEG_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002807 err = user_confirm_neg_reply(sk, index, cp, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03002808 break;
Brian Gix604086b2011-11-23 08:28:33 -08002809 case MGMT_OP_USER_PASSKEY_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002810 err = user_passkey_reply(sk, index, cp, len);
Brian Gix604086b2011-11-23 08:28:33 -08002811 break;
2812 case MGMT_OP_USER_PASSKEY_NEG_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002813 err = user_passkey_neg_reply(sk, index, cp, len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002814 break;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002815 case MGMT_OP_SET_LOCAL_NAME:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002816 err = set_local_name(sk, index, cp, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002817 break;
Szymon Jancc35938b2011-03-22 13:12:21 +01002818 case MGMT_OP_READ_LOCAL_OOB_DATA:
2819 err = read_local_oob_data(sk, index);
2820 break;
Szymon Janc2763eda2011-03-22 13:12:22 +01002821 case MGMT_OP_ADD_REMOTE_OOB_DATA:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002822 err = add_remote_oob_data(sk, index, cp, len);
Szymon Janc2763eda2011-03-22 13:12:22 +01002823 break;
2824 case MGMT_OP_REMOVE_REMOTE_OOB_DATA:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002825 err = remove_remote_oob_data(sk, index, cp, len);
Szymon Janc2763eda2011-03-22 13:12:22 +01002826 break;
Johan Hedberg14a53662011-04-27 10:29:56 -04002827 case MGMT_OP_START_DISCOVERY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002828 err = start_discovery(sk, index, cp, len);
Johan Hedberg14a53662011-04-27 10:29:56 -04002829 break;
2830 case MGMT_OP_STOP_DISCOVERY:
Johan Hedbergd9306502012-02-20 23:25:18 +02002831 err = stop_discovery(sk, index, cp, len);
Johan Hedberg14a53662011-04-27 10:29:56 -04002832 break;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002833 case MGMT_OP_CONFIRM_NAME:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002834 err = confirm_name(sk, index, cp, len);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002835 break;
Antti Julku7fbec222011-06-15 12:01:15 +03002836 case MGMT_OP_BLOCK_DEVICE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002837 err = block_device(sk, index, cp, len);
Antti Julku7fbec222011-06-15 12:01:15 +03002838 break;
2839 case MGMT_OP_UNBLOCK_DEVICE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002840 err = unblock_device(sk, index, cp, len);
Antti Julku7fbec222011-06-15 12:01:15 +03002841 break;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002842 case MGMT_OP_LOAD_LONG_TERM_KEYS:
2843 err = load_long_term_keys(sk, index, cp, len);
2844 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002845 default:
Johan Hedberg72a734e2010-12-30 00:38:22 +02002846 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02002847 err = cmd_status(sk, index, opcode,
2848 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002849 break;
2850 }
Johan Hedberg72a734e2010-12-30 00:38:22 +02002851
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002852 if (err < 0)
Johan Hedberg72a734e2010-12-30 00:38:22 +02002853 goto done;
2854
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002855 err = msglen;
2856
2857done:
2858 kfree(buf);
2859 return err;
2860}
2861
Johan Hedbergb24752f2011-11-03 14:40:33 +02002862static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
2863{
2864 u8 *status = data;
2865
2866 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
2867 mgmt_pending_remove(cmd);
2868}
2869
Johan Hedberg744cf192011-11-08 20:40:14 +02002870int mgmt_index_added(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +02002871{
Johan Hedberg744cf192011-11-08 20:40:14 +02002872 return mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02002873}
2874
Johan Hedberg744cf192011-11-08 20:40:14 +02002875int mgmt_index_removed(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +02002876{
Johan Hedbergb24752f2011-11-03 14:40:33 +02002877 u8 status = ENODEV;
2878
Johan Hedberg744cf192011-11-08 20:40:14 +02002879 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002880
Johan Hedberg744cf192011-11-08 20:40:14 +02002881 return mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02002882}
2883
2884struct cmd_lookup {
Johan Hedberg03811012010-12-08 00:21:06 +02002885 struct sock *sk;
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002886 struct hci_dev *hdev;
Johan Hedberg03811012010-12-08 00:21:06 +02002887};
2888
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002889static void settings_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberg03811012010-12-08 00:21:06 +02002890{
Johan Hedberg03811012010-12-08 00:21:06 +02002891 struct cmd_lookup *match = data;
2892
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002893 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02002894
2895 list_del(&cmd->list);
2896
2897 if (match->sk == NULL) {
2898 match->sk = cmd->sk;
2899 sock_hold(match->sk);
2900 }
2901
2902 mgmt_pending_free(cmd);
2903}
2904
Johan Hedberg744cf192011-11-08 20:40:14 +02002905int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg03811012010-12-08 00:21:06 +02002906{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002907 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002908 __le32 ev;
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002909 int err;
Johan Hedberg03811012010-12-08 00:21:06 +02002910
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002911 if (!test_bit(HCI_MGMT, &hdev->dev_flags))
2912 return 0;
2913
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002914 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
Johan Hedberg03811012010-12-08 00:21:06 +02002915
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002916 if (powered) {
2917 u8 scan = 0;
2918
2919 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
2920 scan |= SCAN_PAGE;
2921 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
2922 scan |= SCAN_INQUIRY;
2923
2924 if (scan)
2925 hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
2926 } else {
Johan Hedbergb24752f2011-11-03 14:40:33 +02002927 u8 status = ENETDOWN;
Johan Hedberg744cf192011-11-08 20:40:14 +02002928 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002929 }
2930
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002931 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg03811012010-12-08 00:21:06 +02002932
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002933 err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev),
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002934 match.sk);
Johan Hedberg03811012010-12-08 00:21:06 +02002935
2936 if (match.sk)
2937 sock_put(match.sk);
2938
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002939 return err;
Johan Hedberg03811012010-12-08 00:21:06 +02002940}
2941
Johan Hedberg744cf192011-11-08 20:40:14 +02002942int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg03811012010-12-08 00:21:06 +02002943{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002944 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002945 bool changed = false;
2946 int err = 0;
Johan Hedberg03811012010-12-08 00:21:06 +02002947
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002948 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp, &match);
Johan Hedberg03811012010-12-08 00:21:06 +02002949
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002950 if (discoverable) {
2951 if (!test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
2952 changed = true;
2953 } else {
2954 if (test_and_clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
2955 changed = true;
2956 }
Johan Hedberg03811012010-12-08 00:21:06 +02002957
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002958 if (changed) {
2959 __le32 ev = cpu_to_le32(get_current_settings(hdev));
2960 err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01002961 match.sk);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002962 }
2963
Johan Hedberg03811012010-12-08 00:21:06 +02002964 if (match.sk)
2965 sock_put(match.sk);
2966
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002967 return err;
Johan Hedberg03811012010-12-08 00:21:06 +02002968}
2969
Johan Hedberg744cf192011-11-08 20:40:14 +02002970int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg03811012010-12-08 00:21:06 +02002971{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002972 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002973 bool changed = false;
2974 int err = 0;
Johan Hedberg03811012010-12-08 00:21:06 +02002975
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002976 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev, settings_rsp,
2977 &match);
Johan Hedberg03811012010-12-08 00:21:06 +02002978
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002979 if (connectable) {
2980 if (!test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags))
2981 changed = true;
2982 } else {
2983 if (test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags))
2984 changed = true;
2985 }
Johan Hedberg03811012010-12-08 00:21:06 +02002986
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002987 if (changed) {
2988 __le32 ev = cpu_to_le32(get_current_settings(hdev));
2989 err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev),
2990 match.sk);
2991 }
Johan Hedberg03811012010-12-08 00:21:06 +02002992
2993 if (match.sk)
2994 sock_put(match.sk);
2995
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002996 return err;
Johan Hedberg03811012010-12-08 00:21:06 +02002997}
2998
Johan Hedberg744cf192011-11-08 20:40:14 +02002999int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003000{
Johan Hedbergca69b792011-11-11 18:10:00 +02003001 u8 mgmt_err = mgmt_status(status);
3002
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003003 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02003004 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Johan Hedbergca69b792011-11-11 18:10:00 +02003005 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003006
3007 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02003008 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Johan Hedbergca69b792011-11-11 18:10:00 +02003009 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003010
3011 return 0;
3012}
3013
Johan Hedberg744cf192011-11-08 20:40:14 +02003014int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
3015 u8 persistent)
Johan Hedberg03811012010-12-08 00:21:06 +02003016{
Johan Hedberg86742e12011-11-07 23:13:38 +02003017 struct mgmt_ev_new_link_key ev;
Johan Hedberg03811012010-12-08 00:21:06 +02003018
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003019 memset(&ev, 0, sizeof(ev));
Johan Hedberg03811012010-12-08 00:21:06 +02003020
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003021 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02003022 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
3023 ev.key.addr.type = MGMT_ADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003024 ev.key.type = key->type;
3025 memcpy(ev.key.val, key->val, 16);
3026 ev.key.pin_len = key->pin_len;
Johan Hedberg03811012010-12-08 00:21:06 +02003027
Johan Hedberg744cf192011-11-08 20:40:14 +02003028 return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02003029}
Johan Hedbergf7520542011-01-20 12:34:39 +02003030
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003031int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
3032{
3033 struct mgmt_ev_new_long_term_key ev;
3034
3035 memset(&ev, 0, sizeof(ev));
3036
3037 ev.store_hint = persistent;
3038 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
3039 ev.key.addr.type = key->bdaddr_type;
3040 ev.key.authenticated = key->authenticated;
3041 ev.key.enc_size = key->enc_size;
3042 ev.key.ediv = key->ediv;
3043
3044 if (key->type == HCI_SMP_LTK)
3045 ev.key.master = 1;
3046
3047 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
3048 memcpy(ev.key.val, key->val, sizeof(key->val));
3049
3050 return mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev,
3051 &ev, sizeof(ev), NULL);
3052}
3053
Johan Hedbergafc747a2012-01-15 18:11:07 +02003054int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Johan Hedbergb644ba32012-01-17 21:48:47 +02003055 u8 addr_type, u8 *name, u8 name_len,
3056 u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02003057{
Johan Hedbergb644ba32012-01-17 21:48:47 +02003058 char buf[512];
3059 struct mgmt_ev_device_connected *ev = (void *) buf;
3060 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02003061
Johan Hedbergb644ba32012-01-17 21:48:47 +02003062 bacpy(&ev->addr.bdaddr, bdaddr);
3063 ev->addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02003064
Johan Hedbergb644ba32012-01-17 21:48:47 +02003065 if (name_len > 0)
3066 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
3067 name, name_len);
3068
3069 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
3070 eir_len = eir_append_data(&ev->eir[eir_len], eir_len,
3071 EIR_CLASS_OF_DEV, dev_class, 3);
3072
3073 put_unaligned_le16(eir_len, &ev->eir_len);
3074
3075 return mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
3076 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02003077}
3078
Johan Hedberg8962ee72011-01-20 12:40:27 +02003079static void disconnect_rsp(struct pending_cmd *cmd, void *data)
3080{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01003081 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003082 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02003083 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003084
Johan Hedberg88c3df12012-02-09 14:27:38 +02003085 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3086 rp.addr.type = cp->addr.type;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003087
Johan Hedbergaee9b212012-02-18 15:07:59 +02003088 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, 0, &rp,
3089 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003090
3091 *sk = cmd->sk;
3092 sock_hold(*sk);
3093
Johan Hedberga664b5b2011-02-19 12:06:02 -03003094 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003095}
3096
Johan Hedberg124f6e32012-02-09 13:50:12 +02003097static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02003098{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003099 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02003100 struct mgmt_cp_unpair_device *cp = cmd->param;
3101 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02003102
3103 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02003104 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3105 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02003106
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003107 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
3108
Johan Hedbergaee9b212012-02-18 15:07:59 +02003109 cmd_complete(cmd->sk, cmd->index, cmd->opcode, 0, &rp, sizeof(rp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02003110
3111 mgmt_pending_remove(cmd);
3112}
3113
Johan Hedbergafc747a2012-01-15 18:11:07 +02003114int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
3115 u8 link_type, u8 addr_type)
Johan Hedbergf7520542011-01-20 12:34:39 +02003116{
Johan Hedberg4c659c32011-11-07 23:13:39 +02003117 struct mgmt_addr_info ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003118 struct sock *sk = NULL;
3119 int err;
3120
Johan Hedberg744cf192011-11-08 20:40:14 +02003121 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02003122
Johan Hedbergf7520542011-01-20 12:34:39 +02003123 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02003124 ev.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02003125
Johan Hedbergafc747a2012-01-15 18:11:07 +02003126 err = mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev),
3127 sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003128
3129 if (sk)
3130 sock_put(sk);
3131
Johan Hedberg124f6e32012-02-09 13:50:12 +02003132 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003133 hdev);
Johan Hedberga8a1d192011-11-10 15:54:38 +02003134
Johan Hedberg8962ee72011-01-20 12:40:27 +02003135 return err;
3136}
3137
Johan Hedberg88c3df12012-02-09 14:27:38 +02003138int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
3139 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02003140{
Johan Hedberg88c3df12012-02-09 14:27:38 +02003141 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003142 struct pending_cmd *cmd;
3143 int err;
3144
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003145 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003146 if (!cmd)
3147 return -ENOENT;
3148
Johan Hedberg88c3df12012-02-09 14:27:38 +02003149 bacpy(&rp.addr.bdaddr, bdaddr);
3150 rp.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02003151
Johan Hedberg88c3df12012-02-09 14:27:38 +02003152 err = cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
Johan Hedbergaee9b212012-02-18 15:07:59 +02003153 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003154
Johan Hedberga664b5b2011-02-19 12:06:02 -03003155 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003156
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003157 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
3158 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003159 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02003160}
Johan Hedberg17d5c042011-01-22 06:09:08 +02003161
Johan Hedberg48264f02011-11-09 13:58:58 +02003162int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
3163 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02003164{
3165 struct mgmt_ev_connect_failed ev;
3166
Johan Hedberg4c659c32011-11-07 23:13:39 +02003167 bacpy(&ev.addr.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02003168 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003169 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003170
Johan Hedberg744cf192011-11-08 20:40:14 +02003171 return mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003172}
Johan Hedberg980e1a52011-01-22 06:10:07 +02003173
Johan Hedberg744cf192011-11-08 20:40:14 +02003174int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003175{
3176 struct mgmt_ev_pin_code_request ev;
3177
Johan Hedbergd8457692012-02-17 14:24:57 +02003178 bacpy(&ev.addr.bdaddr, bdaddr);
3179 ev.addr.type = MGMT_ADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02003180 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003181
Johan Hedberg744cf192011-11-08 20:40:14 +02003182 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01003183 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003184}
3185
Johan Hedberg744cf192011-11-08 20:40:14 +02003186int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3187 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003188{
3189 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003190 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003191 int err;
3192
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003193 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003194 if (!cmd)
3195 return -ENOENT;
3196
Johan Hedbergd8457692012-02-17 14:24:57 +02003197 bacpy(&rp.addr.bdaddr, bdaddr);
3198 rp.addr.type = MGMT_ADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003199
Johan Hedbergaee9b212012-02-18 15:07:59 +02003200 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
3201 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003202
Johan Hedberga664b5b2011-02-19 12:06:02 -03003203 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003204
3205 return err;
3206}
3207
Johan Hedberg744cf192011-11-08 20:40:14 +02003208int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3209 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003210{
3211 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003212 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003213 int err;
3214
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003215 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003216 if (!cmd)
3217 return -ENOENT;
3218
Johan Hedbergd8457692012-02-17 14:24:57 +02003219 bacpy(&rp.addr.bdaddr, bdaddr);
3220 rp.addr.type = MGMT_ADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003221
Johan Hedbergaee9b212012-02-18 15:07:59 +02003222 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
3223 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003224
Johan Hedberga664b5b2011-02-19 12:06:02 -03003225 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003226
3227 return err;
3228}
Johan Hedberga5c29682011-02-19 12:05:57 -03003229
Johan Hedberg744cf192011-11-08 20:40:14 +02003230int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003231 u8 link_type, u8 addr_type, __le32 value,
3232 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03003233{
3234 struct mgmt_ev_user_confirm_request ev;
3235
Johan Hedberg744cf192011-11-08 20:40:14 +02003236 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03003237
Johan Hedberg272d90d2012-02-09 15:26:12 +02003238 bacpy(&ev.addr.bdaddr, bdaddr);
3239 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07003240 ev.confirm_hint = confirm_hint;
Johan Hedberga5c29682011-02-19 12:05:57 -03003241 put_unaligned_le32(value, &ev.value);
3242
Johan Hedberg744cf192011-11-08 20:40:14 +02003243 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01003244 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03003245}
3246
Johan Hedberg272d90d2012-02-09 15:26:12 +02003247int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
3248 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08003249{
3250 struct mgmt_ev_user_passkey_request ev;
3251
3252 BT_DBG("%s", hdev->name);
3253
Johan Hedberg272d90d2012-02-09 15:26:12 +02003254 bacpy(&ev.addr.bdaddr, bdaddr);
3255 ev.addr.type = link_to_mgmt(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08003256
3257 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
3258 NULL);
3259}
3260
Brian Gix0df4c182011-11-16 13:53:13 -08003261static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003262 u8 link_type, u8 addr_type, u8 status,
3263 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03003264{
3265 struct pending_cmd *cmd;
3266 struct mgmt_rp_user_confirm_reply rp;
3267 int err;
3268
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003269 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03003270 if (!cmd)
3271 return -ENOENT;
3272
Johan Hedberg272d90d2012-02-09 15:26:12 +02003273 bacpy(&rp.addr.bdaddr, bdaddr);
3274 rp.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergaee9b212012-02-18 15:07:59 +02003275 err = cmd_complete(cmd->sk, hdev->id, opcode, mgmt_status(status),
3276 &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03003277
Johan Hedberga664b5b2011-02-19 12:06:02 -03003278 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03003279
3280 return err;
3281}
3282
Johan Hedberg744cf192011-11-08 20:40:14 +02003283int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003284 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003285{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003286 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3287 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003288}
3289
Johan Hedberg272d90d2012-02-09 15:26:12 +02003290int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3291 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003292{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003293 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3294 status, MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003295}
Johan Hedberg2a611692011-02-19 12:06:00 -03003296
Brian Gix604086b2011-11-23 08:28:33 -08003297int mgmt_user_passkey_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)
Brian Gix604086b2011-11-23 08:28:33 -08003299{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003300 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3301 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003302}
3303
Johan Hedberg272d90d2012-02-09 15:26:12 +02003304int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3305 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003306{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003307 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3308 status, MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003309}
3310
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003311int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
3312 u8 addr_type, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03003313{
3314 struct mgmt_ev_auth_failed ev;
3315
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003316 bacpy(&ev.addr.bdaddr, bdaddr);
3317 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003318 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03003319
Johan Hedberg744cf192011-11-08 20:40:14 +02003320 return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03003321}
Johan Hedbergb312b1612011-03-16 14:29:37 +02003322
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003323int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
3324{
3325 struct cmd_lookup match = { NULL, hdev };
3326 __le32 ev;
3327 int err;
3328
3329 if (status) {
3330 u8 mgmt_err = mgmt_status(status);
3331 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
3332 cmd_status_rsp, &mgmt_err);
3333 return 0;
3334 }
3335
3336 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
3337 &match);
3338
3339 ev = cpu_to_le32(get_current_settings(hdev));
3340 err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), match.sk);
3341
3342 if (match.sk)
3343 sock_put(match.sk);
3344
3345 return err;
3346}
3347
Johan Hedbergcacaf522012-02-21 00:52:42 +02003348static int clear_eir(struct hci_dev *hdev)
3349{
3350 struct hci_cp_write_eir cp;
3351
3352 if (!(hdev->features[6] & LMP_EXT_INQ))
3353 return 0;
3354
3355 memset(&cp, 0, sizeof(cp));
3356
3357 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
3358}
3359
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003360int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 status)
3361{
3362 struct cmd_lookup match = { NULL, hdev };
3363 __le32 ev;
3364 int err;
3365
3366 if (status) {
3367 u8 mgmt_err = mgmt_status(status);
3368 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev,
3369 cmd_status_rsp, &mgmt_err);
3370 return 0;
3371 }
3372
3373 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
3374
3375 ev = cpu_to_le32(get_current_settings(hdev));
3376 err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), match.sk);
3377
Johan Hedbergcacaf522012-02-21 00:52:42 +02003378 if (match.sk) {
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003379 sock_put(match.sk);
3380
Johan Hedbergcacaf522012-02-21 00:52:42 +02003381 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3382 update_eir(hdev);
3383 else
3384 clear_eir(hdev);
3385 }
3386
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003387 return err;
3388}
3389
Johan Hedberg744cf192011-11-08 20:40:14 +02003390int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02003391{
3392 struct pending_cmd *cmd;
3393 struct mgmt_cp_set_local_name ev;
3394 int err;
3395
3396 memset(&ev, 0, sizeof(ev));
3397 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
3398
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003399 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003400 if (!cmd)
3401 goto send_event;
3402
3403 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02003404 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
Johan Hedbergca69b792011-11-11 18:10:00 +02003405 mgmt_status(status));
Johan Hedbergb312b1612011-03-16 14:29:37 +02003406 goto failed;
3407 }
3408
Johan Hedberg744cf192011-11-08 20:40:14 +02003409 update_eir(hdev);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03003410
Johan Hedbergaee9b212012-02-18 15:07:59 +02003411 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0, &ev,
Johan Hedbergb312b1612011-03-16 14:29:37 +02003412 sizeof(ev));
3413 if (err < 0)
3414 goto failed;
3415
3416send_event:
Johan Hedberg744cf192011-11-08 20:40:14 +02003417 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
Johan Hedbergb312b1612011-03-16 14:29:37 +02003418 cmd ? cmd->sk : NULL);
3419
3420failed:
3421 if (cmd)
3422 mgmt_pending_remove(cmd);
3423 return err;
3424}
Szymon Jancc35938b2011-03-22 13:12:21 +01003425
Johan Hedberg744cf192011-11-08 20:40:14 +02003426int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
3427 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01003428{
3429 struct pending_cmd *cmd;
3430 int err;
3431
Johan Hedberg744cf192011-11-08 20:40:14 +02003432 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01003433
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003434 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003435 if (!cmd)
3436 return -ENOENT;
3437
3438 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02003439 err = cmd_status(cmd->sk, hdev->id,
Johan Hedbergca69b792011-11-11 18:10:00 +02003440 MGMT_OP_READ_LOCAL_OOB_DATA,
3441 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01003442 } else {
3443 struct mgmt_rp_read_local_oob_data rp;
3444
3445 memcpy(rp.hash, hash, sizeof(rp.hash));
3446 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
3447
Johan Hedberg744cf192011-11-08 20:40:14 +02003448 err = cmd_complete(cmd->sk, hdev->id,
3449 MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergaee9b212012-02-18 15:07:59 +02003450 0, &rp, sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01003451 }
3452
3453 mgmt_pending_remove(cmd);
3454
3455 return err;
3456}
Johan Hedberge17acd42011-03-30 23:57:16 +03003457
Johan Hedberg48264f02011-11-09 13:58:58 +02003458int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Johan Hedberg561aafb2012-01-04 13:31:59 +02003459 u8 addr_type, u8 *dev_class, s8 rssi,
Johan Hedberge319d2e2012-01-15 19:51:59 +02003460 u8 cfm_name, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03003461{
Johan Hedberge319d2e2012-01-15 19:51:59 +02003462 char buf[512];
3463 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02003464 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03003465
Johan Hedberg1dc06092012-01-15 21:01:23 +02003466 /* Leave 5 bytes for a potential CoD field */
3467 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Andre Guedes7d262f82012-01-10 18:20:49 -03003468 return -EINVAL;
3469
Johan Hedberg1dc06092012-01-15 21:01:23 +02003470 memset(buf, 0, sizeof(buf));
3471
Johan Hedberge319d2e2012-01-15 19:51:59 +02003472 bacpy(&ev->addr.bdaddr, bdaddr);
3473 ev->addr.type = link_to_mgmt(link_type, addr_type);
3474 ev->rssi = rssi;
3475 ev->confirm_name = cfm_name;
Johan Hedberge17acd42011-03-30 23:57:16 +03003476
Johan Hedberg1dc06092012-01-15 21:01:23 +02003477 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02003478 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03003479
Johan Hedberg1dc06092012-01-15 21:01:23 +02003480 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
3481 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
3482 dev_class, 3);
3483
3484 put_unaligned_le16(eir_len, &ev->eir_len);
3485
3486 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03003487
Johan Hedberge319d2e2012-01-15 19:51:59 +02003488 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03003489}
Johan Hedberga88a9652011-03-30 13:18:12 +03003490
Johan Hedbergb644ba32012-01-17 21:48:47 +02003491int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
3492 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03003493{
Johan Hedbergb644ba32012-01-17 21:48:47 +02003494 struct mgmt_ev_device_found *ev;
3495 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
3496 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03003497
Johan Hedbergb644ba32012-01-17 21:48:47 +02003498 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03003499
Johan Hedbergb644ba32012-01-17 21:48:47 +02003500 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03003501
Johan Hedbergb644ba32012-01-17 21:48:47 +02003502 bacpy(&ev->addr.bdaddr, bdaddr);
3503 ev->addr.type = link_to_mgmt(link_type, addr_type);
3504 ev->rssi = rssi;
3505
3506 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
3507 name_len);
3508
3509 put_unaligned_le16(eir_len, &ev->eir_len);
3510
Johan Hedberg053c7e02012-02-04 00:06:00 +02003511 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev,
3512 sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03003513}
Johan Hedberg314b2382011-04-27 10:29:57 -04003514
Andre Guedes7a135102011-11-09 17:14:25 -03003515int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
Johan Hedberg164a6e72011-11-01 17:06:44 +02003516{
3517 struct pending_cmd *cmd;
Johan Hedbergf808e162012-02-19 12:52:07 +02003518 u8 type;
Johan Hedberg164a6e72011-11-01 17:06:44 +02003519 int err;
3520
Andre Guedes203159d2012-02-13 15:41:01 -03003521 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3522
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003523 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003524 if (!cmd)
3525 return -ENOENT;
3526
Johan Hedbergf808e162012-02-19 12:52:07 +02003527 type = hdev->discovery.type;
3528
3529 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
3530 &type, sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02003531 mgmt_pending_remove(cmd);
3532
3533 return err;
3534}
3535
Andre Guedese6d465c2011-11-09 17:14:26 -03003536int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
3537{
3538 struct pending_cmd *cmd;
3539 int err;
3540
3541 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
3542 if (!cmd)
3543 return -ENOENT;
3544
Johan Hedbergd9306502012-02-20 23:25:18 +02003545 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
3546 &hdev->discovery.type,
3547 sizeof(hdev->discovery.type));
Johan Hedberg03811012010-12-08 00:21:06 +02003548 mgmt_pending_remove(cmd);
3549
3550 return err;
3551}
Johan Hedberg314b2382011-04-27 10:29:57 -04003552
Johan Hedberg744cf192011-11-08 20:40:14 +02003553int mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04003554{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02003555 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02003556 struct pending_cmd *cmd;
3557
Andre Guedes343fb142011-11-22 17:14:19 -03003558 BT_DBG("%s discovering %u", hdev->name, discovering);
3559
Johan Hedberg164a6e72011-11-01 17:06:44 +02003560 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003561 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003562 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003563 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003564
3565 if (cmd != NULL) {
Johan Hedbergf808e162012-02-19 12:52:07 +02003566 u8 type = hdev->discovery.type;
3567
Johan Hedbergd9306502012-02-20 23:25:18 +02003568 cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0,
Johan Hedbergf808e162012-02-19 12:52:07 +02003569 &type, sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02003570 mgmt_pending_remove(cmd);
3571 }
3572
Johan Hedbergf963e8e2012-02-20 23:30:44 +02003573 memset(&ev, 0, sizeof(ev));
3574 ev.type = hdev->discovery.type;
3575 ev.discovering = discovering;
3576
3577 return mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04003578}
Antti Julku5e762442011-08-25 16:48:02 +03003579
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003580int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003581{
3582 struct pending_cmd *cmd;
3583 struct mgmt_ev_device_blocked ev;
3584
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003585 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003586
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003587 bacpy(&ev.addr.bdaddr, bdaddr);
3588 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003589
Johan Hedberg744cf192011-11-08 20:40:14 +02003590 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
3591 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003592}
3593
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003594int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003595{
3596 struct pending_cmd *cmd;
3597 struct mgmt_ev_device_unblocked ev;
3598
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003599 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003600
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003601 bacpy(&ev.addr.bdaddr, bdaddr);
3602 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003603
Johan Hedberg744cf192011-11-08 20:40:14 +02003604 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
3605 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003606}
Marcel Holtmannd7b7e792012-02-20 21:47:49 +01003607
3608module_param(enable_hs, bool, 0644);
3609MODULE_PARM_DESC(enable_hs, "Enable High Speed support");
3610
3611module_param(enable_le, bool, 0644);
3612MODULE_PARM_DESC(enable_le, "Enable Low Energy support");