blob: 86e63a707f5a7269e5d065697a2415b88d9b4031 [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
Johan Hedbergf1f0eb02012-02-21 17:15:41 +0200395 if (hdev_is_powered(hdev))
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100396 settings |= MGMT_SETTING_POWERED;
397
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200398 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200399 settings |= MGMT_SETTING_CONNECTABLE;
400
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200401 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200402 settings |= MGMT_SETTING_DISCOVERABLE;
403
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200404 if (test_bit(HCI_PAIRABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200405 settings |= MGMT_SETTING_PAIRABLE;
406
407 if (!(hdev->features[4] & LMP_NO_BREDR))
408 settings |= MGMT_SETTING_BREDR;
409
Andre Guedes59e29402011-12-30 10:34:03 -0300410 if (hdev->host_features[0] & LMP_HOST_LE)
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200411 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200412
413 if (test_bit(HCI_AUTH, &hdev->flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200414 settings |= MGMT_SETTING_LINK_SECURITY;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200415
Johan Hedberg84bde9d6c2012-01-25 14:21:06 +0200416 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200417 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200418
Johan Hedberg6d80dfd2012-02-20 23:50:38 +0200419 if (test_bit(HCI_HS_ENABLED, &hdev->dev_flags))
420 settings |= MGMT_SETTING_HS;
421
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200422 return settings;
Johan Hedbergc542a062011-01-26 13:11:03 +0200423}
424
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300425#define PNP_INFO_SVCLASS_ID 0x1200
426
427static u8 bluetooth_base_uuid[] = {
428 0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80,
429 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
430};
431
432static u16 get_uuid16(u8 *uuid128)
433{
434 u32 val;
435 int i;
436
437 for (i = 0; i < 12; i++) {
438 if (bluetooth_base_uuid[i] != uuid128[i])
439 return 0;
440 }
441
442 memcpy(&val, &uuid128[12], 4);
443
444 val = le32_to_cpu(val);
445 if (val > 0xffff)
446 return 0;
447
448 return (u16) val;
449}
450
451static void create_eir(struct hci_dev *hdev, u8 *data)
452{
453 u8 *ptr = data;
454 u16 eir_len = 0;
455 u16 uuid16_list[HCI_MAX_EIR_LENGTH / sizeof(u16)];
456 int i, truncated = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200457 struct bt_uuid *uuid;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300458 size_t name_len;
459
460 name_len = strlen(hdev->dev_name);
461
462 if (name_len > 0) {
463 /* EIR Data type */
464 if (name_len > 48) {
465 name_len = 48;
466 ptr[1] = EIR_NAME_SHORT;
467 } else
468 ptr[1] = EIR_NAME_COMPLETE;
469
470 /* EIR Data length */
471 ptr[0] = name_len + 1;
472
473 memcpy(ptr + 2, hdev->dev_name, name_len);
474
475 eir_len += (name_len + 2);
476 ptr += (name_len + 2);
477 }
478
479 memset(uuid16_list, 0, sizeof(uuid16_list));
480
481 /* Group all UUID16 types */
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200482 list_for_each_entry(uuid, &hdev->uuids, list) {
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300483 u16 uuid16;
484
485 uuid16 = get_uuid16(uuid->uuid);
486 if (uuid16 == 0)
487 return;
488
489 if (uuid16 < 0x1100)
490 continue;
491
492 if (uuid16 == PNP_INFO_SVCLASS_ID)
493 continue;
494
495 /* Stop if not enough space to put next UUID */
496 if (eir_len + 2 + sizeof(u16) > HCI_MAX_EIR_LENGTH) {
497 truncated = 1;
498 break;
499 }
500
501 /* Check for duplicates */
502 for (i = 0; uuid16_list[i] != 0; i++)
503 if (uuid16_list[i] == uuid16)
504 break;
505
506 if (uuid16_list[i] == 0) {
507 uuid16_list[i] = uuid16;
508 eir_len += sizeof(u16);
509 }
510 }
511
512 if (uuid16_list[0] != 0) {
513 u8 *length = ptr;
514
515 /* EIR Data type */
516 ptr[1] = truncated ? EIR_UUID16_SOME : EIR_UUID16_ALL;
517
518 ptr += 2;
519 eir_len += 2;
520
521 for (i = 0; uuid16_list[i] != 0; i++) {
522 *ptr++ = (uuid16_list[i] & 0x00ff);
523 *ptr++ = (uuid16_list[i] & 0xff00) >> 8;
524 }
525
526 /* EIR Data length */
527 *length = (i * sizeof(u16)) + 1;
528 }
529}
530
531static int update_eir(struct hci_dev *hdev)
532{
533 struct hci_cp_write_eir cp;
534
535 if (!(hdev->features[6] & LMP_EXT_INQ))
536 return 0;
537
Johan Hedberg84bde9d6c2012-01-25 14:21:06 +0200538 if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300539 return 0;
540
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200541 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300542 return 0;
543
544 memset(&cp, 0, sizeof(cp));
545
546 create_eir(hdev, cp.data);
547
548 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
549 return 0;
550
551 memcpy(hdev->eir, cp.data, sizeof(cp.data));
552
553 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
554}
555
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200556static u8 get_service_classes(struct hci_dev *hdev)
557{
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300558 struct bt_uuid *uuid;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200559 u8 val = 0;
560
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300561 list_for_each_entry(uuid, &hdev->uuids, list)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200562 val |= uuid->svc_hint;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200563
564 return val;
565}
566
567static int update_class(struct hci_dev *hdev)
568{
569 u8 cod[3];
570
571 BT_DBG("%s", hdev->name);
572
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200573 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200574 return 0;
575
576 cod[0] = hdev->minor_class;
577 cod[1] = hdev->major_class;
578 cod[2] = get_service_classes(hdev);
579
580 if (memcmp(cod, hdev->dev_class, 3) == 0)
581 return 0;
582
583 return hci_send_cmd(hdev, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
584}
585
Johan Hedberg7d785252011-12-15 00:47:39 +0200586static void service_cache_off(struct work_struct *work)
587{
588 struct hci_dev *hdev = container_of(work, struct hci_dev,
589 service_cache.work);
590
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200591 if (!test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200592 return;
593
594 hci_dev_lock(hdev);
595
596 update_eir(hdev);
597 update_class(hdev);
598
599 hci_dev_unlock(hdev);
600}
601
602static void mgmt_init_hdev(struct hci_dev *hdev)
603{
Johan Hedberg0cbf4ed2012-02-21 17:25:22 +0200604 if (!test_and_set_bit(HCI_MGMT, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +0200605 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
606
Johan Hedberg0cbf4ed2012-02-21 17:25:22 +0200607 /* Non-mgmt controlled devices get this bit set
608 * implicitly so that pairing works for them, however
609 * for mgmt we require user-space to explicitly enable
610 * it
611 */
612 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
613 }
614
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200615 if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200616 schedule_delayed_work(&hdev->service_cache,
617 msecs_to_jiffies(SERVICE_CACHE_TIMEOUT));
618}
619
Johan Hedberg03811012010-12-08 00:21:06 +0200620static int read_controller_info(struct sock *sk, u16 index)
621{
622 struct mgmt_rp_read_info rp;
623 struct hci_dev *hdev;
624
625 BT_DBG("sock %p hci%u", sk, index);
626
627 hdev = hci_dev_get(index);
628 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200629 return cmd_status(sk, index, MGMT_OP_READ_INFO,
630 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200631
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300632 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200633
Johan Hedberg7d785252011-12-15 00:47:39 +0200634 if (test_and_clear_bit(HCI_PI_MGMT_INIT, &hci_pi(sk)->flags))
635 mgmt_init_hdev(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200636
637 memset(&rp, 0, sizeof(rp));
638
Johan Hedberg03811012010-12-08 00:21:06 +0200639 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200640
641 rp.version = hdev->hci_ver;
642
Johan Hedberg03811012010-12-08 00:21:06 +0200643 put_unaligned_le16(hdev->manufacturer, &rp.manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200644
645 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
646 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
647
648 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedberg03811012010-12-08 00:21:06 +0200649
650 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
651
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300652 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200653 hci_dev_put(hdev);
654
Johan Hedbergaee9b212012-02-18 15:07:59 +0200655 return cmd_complete(sk, index, MGMT_OP_READ_INFO, 0, &rp, sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +0200656}
657
658static void mgmt_pending_free(struct pending_cmd *cmd)
659{
660 sock_put(cmd->sk);
661 kfree(cmd->param);
662 kfree(cmd);
663}
664
665static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
666 struct hci_dev *hdev,
667 void *data, u16 len)
668{
669 struct pending_cmd *cmd;
670
671 cmd = kmalloc(sizeof(*cmd), GFP_ATOMIC);
672 if (!cmd)
673 return NULL;
674
675 cmd->opcode = opcode;
676 cmd->index = hdev->id;
677
678 cmd->param = kmalloc(len, GFP_ATOMIC);
679 if (!cmd->param) {
680 kfree(cmd);
681 return NULL;
682 }
683
684 if (data)
685 memcpy(cmd->param, data, len);
686
687 cmd->sk = sk;
688 sock_hold(sk);
689
690 list_add(&cmd->list, &hdev->mgmt_pending);
691
692 return cmd;
693}
694
695static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
696 void (*cb)(struct pending_cmd *cmd, void *data),
697 void *data)
698{
699 struct list_head *p, *n;
700
701 list_for_each_safe(p, n, &hdev->mgmt_pending) {
702 struct pending_cmd *cmd;
703
704 cmd = list_entry(p, struct pending_cmd, list);
705
706 if (opcode > 0 && cmd->opcode != opcode)
707 continue;
708
709 cb(cmd, data);
710 }
711}
712
713static struct pending_cmd *mgmt_pending_find(u16 opcode, struct hci_dev *hdev)
714{
715 struct pending_cmd *cmd;
716
717 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
718 if (cmd->opcode == opcode)
719 return cmd;
720 }
721
722 return NULL;
723}
724
725static void mgmt_pending_remove(struct pending_cmd *cmd)
726{
727 list_del(&cmd->list);
728 mgmt_pending_free(cmd);
729}
730
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200731static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +0200732{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200733 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +0200734
Johan Hedbergaee9b212012-02-18 15:07:59 +0200735 return cmd_complete(sk, hdev->id, opcode, 0, &settings,
736 sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +0200737}
738
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300739static int set_powered(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200740{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300741 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200742 struct hci_dev *hdev;
743 struct pending_cmd *cmd;
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200744 int err;
Johan Hedberg03811012010-12-08 00:21:06 +0200745
Johan Hedberg03811012010-12-08 00:21:06 +0200746 BT_DBG("request for hci%u", index);
747
748 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200749 return cmd_status(sk, index, MGMT_OP_SET_POWERED,
750 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200751
752 hdev = hci_dev_get(index);
753 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200754 return cmd_status(sk, index, MGMT_OP_SET_POWERED,
755 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200756
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300757 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200758
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100759 if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) {
760 cancel_delayed_work(&hdev->power_off);
761
762 if (cp->val) {
763 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
764 mgmt_powered(hdev, 1);
765 goto failed;
766 }
767 }
768
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200769 if (!!cp->val == hdev_is_powered(hdev)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200770 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200771 goto failed;
772 }
773
774 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200775 err = cmd_status(sk, index, MGMT_OP_SET_POWERED,
776 MGMT_STATUS_BUSY);
Johan Hedberg03811012010-12-08 00:21:06 +0200777 goto failed;
778 }
779
780 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
781 if (!cmd) {
782 err = -ENOMEM;
783 goto failed;
784 }
785
786 if (cp->val)
Gustavo F. Padovan7f971042011-12-18 12:40:32 -0200787 schedule_work(&hdev->power_on);
Johan Hedberg03811012010-12-08 00:21:06 +0200788 else
Gustavo F. Padovan80b7ab32011-12-17 14:52:27 -0200789 schedule_work(&hdev->power_off.work);
Johan Hedberg03811012010-12-08 00:21:06 +0200790
791 err = 0;
792
793failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300794 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200795 hci_dev_put(hdev);
796 return err;
797}
798
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300799static int set_discoverable(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200800{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300801 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberge41d8b42010-12-13 21:07:03 +0200802 struct hci_dev *hdev;
Johan Hedberg03811012010-12-08 00:21:06 +0200803 struct pending_cmd *cmd;
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200804 u16 timeout;
Johan Hedberg03811012010-12-08 00:21:06 +0200805 u8 scan;
806 int err;
807
Johan Hedberg03811012010-12-08 00:21:06 +0200808 BT_DBG("request for hci%u", index);
809
810 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200811 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
812 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200813
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200814 hdev = hci_dev_get(index);
815 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200816 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
817 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200818
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200819 timeout = get_unaligned_le16(&cp->timeout);
820
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300821 hci_dev_lock(hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200822
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200823 if (!hdev_is_powered(hdev) && timeout > 0) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200824 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
825 MGMT_STATUS_NOT_POWERED);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200826 goto failed;
827 }
828
829 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
830 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200831 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
832 MGMT_STATUS_BUSY);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200833 goto failed;
834 }
835
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200836 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) {
837 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
838 MGMT_STATUS_REJECTED);
839 goto failed;
840 }
841
842 if (!hdev_is_powered(hdev)) {
843 if (cp->val)
844 set_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
845 else
846 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
847 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
848 goto failed;
849 }
850
851 if (!!cp->val == test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200852 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200853 goto failed;
854 }
855
856 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
857 if (!cmd) {
858 err = -ENOMEM;
859 goto failed;
860 }
861
862 scan = SCAN_PAGE;
863
864 if (cp->val)
865 scan |= SCAN_INQUIRY;
866 else
867 cancel_delayed_work(&hdev->discov_off);
868
869 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
870 if (err < 0)
871 mgmt_pending_remove(cmd);
872
Johan Hedberg03811012010-12-08 00:21:06 +0200873 if (cp->val)
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200874 hdev->discov_timeout = timeout;
Johan Hedberg03811012010-12-08 00:21:06 +0200875
876failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300877 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200878 hci_dev_put(hdev);
879
880 return err;
881}
882
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300883static int set_connectable(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200884{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300885 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200886 struct hci_dev *hdev;
887 struct pending_cmd *cmd;
888 u8 scan;
889 int err;
890
Johan Hedberge41d8b42010-12-13 21:07:03 +0200891 BT_DBG("request for hci%u", index);
892
Johan Hedberg03811012010-12-08 00:21:06 +0200893 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200894 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
895 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200896
897 hdev = hci_dev_get(index);
898 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200899 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
900 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200901
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300902 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200903
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200904 if (!hdev_is_powered(hdev)) {
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200905 if (cp->val)
906 set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
907 else {
908 clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
909 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
910 }
911 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200912 goto failed;
913 }
914
915 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
916 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200917 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
918 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200919 goto failed;
920 }
921
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200922 if (!!cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200923 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200924 goto failed;
925 }
926
927 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
928 if (!cmd) {
929 err = -ENOMEM;
930 goto failed;
931 }
932
933 if (cp->val)
934 scan = SCAN_PAGE;
Johan Hedbergdf2c6c52012-02-21 19:15:49 +0200935 else {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200936 scan = 0;
937
Johan Hedbergdf2c6c52012-02-21 19:15:49 +0200938 if (test_bit(HCI_ISCAN, &hdev->flags) &&
939 hdev->discov_timeout > 0)
940 cancel_delayed_work(&hdev->discov_off);
941 }
942
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200943 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
944 if (err < 0)
945 mgmt_pending_remove(cmd);
946
947failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300948 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200949 hci_dev_put(hdev);
950
951 return err;
952}
953
954static int mgmt_event(u16 event, struct hci_dev *hdev, void *data,
955 u16 data_len, struct sock *skip_sk)
956{
957 struct sk_buff *skb;
958 struct mgmt_hdr *hdr;
959
960 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_ATOMIC);
961 if (!skb)
962 return -ENOMEM;
963
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200964 hdr = (void *) skb_put(skb, sizeof(*hdr));
965 hdr->opcode = cpu_to_le16(event);
966 if (hdev)
967 hdr->index = cpu_to_le16(hdev->id);
968 else
969 hdr->index = cpu_to_le16(MGMT_INDEX_NONE);
970 hdr->len = cpu_to_le16(data_len);
971
972 if (data)
973 memcpy(skb_put(skb, data_len), data, data_len);
974
Marcel Holtmann470fe1b2012-02-20 14:50:30 +0100975 hci_send_to_control(skb, skip_sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200976 kfree_skb(skb);
977
978 return 0;
979}
980
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300981static int set_pairable(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +0200982{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300983 struct mgmt_mode *cp = data;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200984 struct hci_dev *hdev;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200985 __le32 ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200986 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200987
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200988 BT_DBG("request for hci%u", index);
989
990 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200991 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE,
992 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200993
994 hdev = hci_dev_get(index);
995 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200996 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE,
997 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200998
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300999 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001000
1001 if (cp->val)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001002 set_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001003 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001004 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001005
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001006 err = send_settings_rsp(sk, MGMT_OP_SET_PAIRABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001007 if (err < 0)
1008 goto failed;
1009
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001010 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001011
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001012 err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001013
1014failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001015 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001016 hci_dev_put(hdev);
1017
1018 return err;
1019}
Johan Hedberg72a734e2010-12-30 00:38:22 +02001020
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001021static int set_link_security(struct sock *sk, u16 index, void *data, u16 len)
1022{
1023 struct mgmt_mode *cp = data;
1024 struct pending_cmd *cmd;
1025 struct hci_dev *hdev;
1026 uint8_t val;
1027 int err;
1028
1029 BT_DBG("request for hci%u", index);
1030
1031 if (len != sizeof(*cp))
1032 return cmd_status(sk, index, MGMT_OP_SET_LINK_SECURITY,
1033 MGMT_STATUS_INVALID_PARAMS);
1034
1035 hdev = hci_dev_get(index);
1036 if (!hdev)
1037 return cmd_status(sk, index, MGMT_OP_SET_LINK_SECURITY,
1038 MGMT_STATUS_INVALID_PARAMS);
1039
1040 hci_dev_lock(hdev);
1041
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001042 if (!hdev_is_powered(hdev)) {
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001043 err = cmd_status(sk, index, MGMT_OP_SET_LINK_SECURITY,
1044 MGMT_STATUS_NOT_POWERED);
1045 goto failed;
1046 }
1047
1048 if (mgmt_pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
1049 err = cmd_status(sk, index, MGMT_OP_SET_LINK_SECURITY,
1050 MGMT_STATUS_BUSY);
1051 goto failed;
1052 }
1053
1054 val = !!cp->val;
1055
1056 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1057 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1058 goto failed;
1059 }
1060
1061 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1062 if (!cmd) {
1063 err = -ENOMEM;
1064 goto failed;
1065 }
1066
1067 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1068 if (err < 0) {
1069 mgmt_pending_remove(cmd);
1070 goto failed;
1071 }
1072
1073failed:
1074 hci_dev_unlock(hdev);
1075 hci_dev_put(hdev);
1076
1077 return err;
1078}
1079
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001080static int set_ssp(struct sock *sk, u16 index, void *data, u16 len)
1081{
1082 struct mgmt_mode *cp = data;
1083 struct pending_cmd *cmd;
1084 struct hci_dev *hdev;
1085 uint8_t val;
1086 int err;
1087
1088 BT_DBG("request for hci%u", index);
1089
1090 if (len != sizeof(*cp))
1091 return cmd_status(sk, index, MGMT_OP_SET_SSP,
1092 MGMT_STATUS_INVALID_PARAMS);
1093
1094 hdev = hci_dev_get(index);
1095 if (!hdev)
1096 return cmd_status(sk, index, MGMT_OP_SET_SSP,
1097 MGMT_STATUS_INVALID_PARAMS);
1098
1099 hci_dev_lock(hdev);
1100
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001101 if (!hdev_is_powered(hdev)) {
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001102 err = cmd_status(sk, index, MGMT_OP_SET_SSP,
1103 MGMT_STATUS_NOT_POWERED);
1104 goto failed;
1105 }
1106
Johan Hedberg1e163572012-02-20 23:53:46 +02001107 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
1108 err = cmd_status(sk, index, MGMT_OP_SET_SSP,
1109 MGMT_STATUS_NOT_SUPPORTED);
1110 goto failed;
1111 }
1112
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001113 if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev)) {
1114 err = cmd_status(sk, index, MGMT_OP_SET_SSP, MGMT_STATUS_BUSY);
1115 goto failed;
1116 }
1117
1118 val = !!cp->val;
1119
1120 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) == val) {
1121 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1122 goto failed;
1123 }
1124
1125 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1126 if (!cmd) {
1127 err = -ENOMEM;
1128 goto failed;
1129 }
1130
1131 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, sizeof(val), &val);
1132 if (err < 0) {
1133 mgmt_pending_remove(cmd);
1134 goto failed;
1135 }
1136
1137failed:
1138 hci_dev_unlock(hdev);
1139 hci_dev_put(hdev);
1140
1141 return err;
1142}
1143
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001144static int set_hs(struct sock *sk, u16 index, void *data, u16 len)
1145{
1146 struct mgmt_mode *cp = data;
1147 struct hci_dev *hdev;
1148 int err;
1149
1150 BT_DBG("request for hci%u", index);
1151
1152 if (len != sizeof(*cp))
1153 return cmd_status(sk, index, MGMT_OP_SET_HS,
1154 MGMT_STATUS_INVALID_PARAMS);
1155
1156 hdev = hci_dev_get(index);
1157 if (!hdev)
1158 return cmd_status(sk, index, MGMT_OP_SET_HS,
1159 MGMT_STATUS_INVALID_PARAMS);
1160
1161 if (!enable_hs) {
1162 err = cmd_status(sk, index, MGMT_OP_SET_HS,
1163 MGMT_STATUS_NOT_SUPPORTED);
1164 goto failed;
1165 }
1166
1167 if (cp->val)
1168 set_bit(HCI_HS_ENABLED, &hdev->dev_flags);
1169 else
1170 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
1171
1172 err = send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
1173
1174failed:
1175 hci_dev_put(hdev);
1176 return err;
1177}
1178
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001179static int add_uuid(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001180{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001181 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001182 struct hci_dev *hdev;
1183 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001184 int err;
1185
Szymon Janc4e51eae2011-02-25 19:05:48 +01001186 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001187
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001188 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001189 return cmd_status(sk, index, MGMT_OP_ADD_UUID,
1190 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001191
Szymon Janc4e51eae2011-02-25 19:05:48 +01001192 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001193 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001194 return cmd_status(sk, index, MGMT_OP_ADD_UUID,
1195 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001196
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001197 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001198
1199 uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC);
1200 if (!uuid) {
1201 err = -ENOMEM;
1202 goto failed;
1203 }
1204
1205 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001206 uuid->svc_hint = cp->svc_hint;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001207
1208 list_add(&uuid->list, &hdev->uuids);
1209
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001210 err = update_class(hdev);
1211 if (err < 0)
1212 goto failed;
1213
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001214 err = update_eir(hdev);
1215 if (err < 0)
1216 goto failed;
1217
Johan Hedbergaee9b212012-02-18 15:07:59 +02001218 err = cmd_complete(sk, index, MGMT_OP_ADD_UUID, 0, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001219
1220failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001221 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001222 hci_dev_put(hdev);
1223
1224 return err;
1225}
1226
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001227static int remove_uuid(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001228{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001229 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001230 struct list_head *p, *n;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001231 struct hci_dev *hdev;
1232 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 +02001233 int err, found;
1234
Szymon Janc4e51eae2011-02-25 19:05:48 +01001235 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001236
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001237 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001238 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
1239 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001240
Szymon Janc4e51eae2011-02-25 19:05:48 +01001241 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001242 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001243 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
1244 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001245
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001246 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001247
1248 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
1249 err = hci_uuids_clear(hdev);
1250 goto unlock;
1251 }
1252
1253 found = 0;
1254
1255 list_for_each_safe(p, n, &hdev->uuids) {
1256 struct bt_uuid *match = list_entry(p, struct bt_uuid, list);
1257
1258 if (memcmp(match->uuid, cp->uuid, 16) != 0)
1259 continue;
1260
1261 list_del(&match->list);
1262 found++;
1263 }
1264
1265 if (found == 0) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001266 err = cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
1267 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001268 goto unlock;
1269 }
1270
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001271 err = update_class(hdev);
1272 if (err < 0)
1273 goto unlock;
1274
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001275 err = update_eir(hdev);
1276 if (err < 0)
1277 goto unlock;
1278
Johan Hedbergaee9b212012-02-18 15:07:59 +02001279 err = cmd_complete(sk, index, MGMT_OP_REMOVE_UUID, 0, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001280
1281unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001282 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001283 hci_dev_put(hdev);
1284
1285 return err;
1286}
1287
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001288static int set_dev_class(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001289{
1290 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001291 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001292 int err;
1293
Szymon Janc4e51eae2011-02-25 19:05:48 +01001294 BT_DBG("request for hci%u", index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001295
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001296 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001297 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS,
1298 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001299
Szymon Janc4e51eae2011-02-25 19:05:48 +01001300 hdev = hci_dev_get(index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001301 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001302 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS,
1303 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001304
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001305 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001306
Johan Hedbergb5235a62012-02-21 14:32:24 +02001307 if (!hdev_is_powered(hdev)) {
1308 err = cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS,
1309 MGMT_STATUS_NOT_POWERED);
1310 goto unlock;
1311 }
1312
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001313 hdev->major_class = cp->major;
1314 hdev->minor_class = cp->minor;
1315
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001316 if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02001317 hci_dev_unlock(hdev);
1318 cancel_delayed_work_sync(&hdev->service_cache);
1319 hci_dev_lock(hdev);
Johan Hedberg14c0b602011-12-15 00:47:37 +02001320 update_eir(hdev);
Johan Hedberg7d785252011-12-15 00:47:39 +02001321 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02001322
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001323 err = update_class(hdev);
1324
1325 if (err == 0)
Johan Hedbergaee9b212012-02-18 15:07:59 +02001326 err = cmd_complete(sk, index, MGMT_OP_SET_DEV_CLASS, 0,
1327 NULL, 0);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001328
Johan Hedbergb5235a62012-02-21 14:32:24 +02001329unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001330 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001331 hci_dev_put(hdev);
1332
1333 return err;
1334}
1335
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001336static int load_link_keys(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001337{
1338 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001339 struct mgmt_cp_load_link_keys *cp = data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001340 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001341 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001342
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001343 if (len < sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001344 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1345 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001346
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001347 key_count = get_unaligned_le16(&cp->key_count);
1348
Johan Hedberg86742e12011-11-07 23:13:38 +02001349 expected_len = sizeof(*cp) + key_count *
1350 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001351 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001352 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001353 len, expected_len);
Johan Hedbergca69b792011-11-11 18:10:00 +02001354 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1355 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001356 }
1357
Szymon Janc4e51eae2011-02-25 19:05:48 +01001358 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001359 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001360 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1361 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001362
Szymon Janc4e51eae2011-02-25 19:05:48 +01001363 BT_DBG("hci%u debug_keys %u key_count %u", index, cp->debug_keys,
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001364 key_count);
1365
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001366 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001367
1368 hci_link_keys_clear(hdev);
1369
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001370 set_bit(HCI_LINK_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001371
1372 if (cp->debug_keys)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001373 set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001374 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001375 clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001376
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001377 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001378 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001379
Johan Hedbergd753fdc2012-02-17 14:06:34 +02001380 hci_add_link_key(hdev, NULL, 0, &key->addr.bdaddr, key->val,
1381 key->type, key->pin_len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001382 }
1383
Johan Hedbergaee9b212012-02-18 15:07:59 +02001384 cmd_complete(sk, index, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02001385
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001386 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001387 hci_dev_put(hdev);
1388
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001389 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001390}
1391
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001392static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
1393 u8 addr_type, struct sock *skip_sk)
1394{
1395 struct mgmt_ev_device_unpaired ev;
1396
1397 bacpy(&ev.addr.bdaddr, bdaddr);
1398 ev.addr.type = addr_type;
1399
1400 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
1401 skip_sk);
1402}
1403
Johan Hedberg124f6e32012-02-09 13:50:12 +02001404static int unpair_device(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001405{
1406 struct hci_dev *hdev;
Johan Hedberg124f6e32012-02-09 13:50:12 +02001407 struct mgmt_cp_unpair_device *cp = data;
1408 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001409 struct hci_cp_disconnect dc;
1410 struct pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001411 struct hci_conn *conn;
Johan Hedbergaee9b212012-02-18 15:07:59 +02001412 u8 status = 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001413 int err;
1414
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001415 if (len != sizeof(*cp))
Johan Hedberg124f6e32012-02-09 13:50:12 +02001416 return cmd_status(sk, index, MGMT_OP_UNPAIR_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02001417 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001418
Szymon Janc4e51eae2011-02-25 19:05:48 +01001419 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001420 if (!hdev)
Johan Hedberg124f6e32012-02-09 13:50:12 +02001421 return cmd_status(sk, index, MGMT_OP_UNPAIR_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02001422 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001423
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001424 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001425
Johan Hedberga8a1d192011-11-10 15:54:38 +02001426 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02001427 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1428 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001429
Johan Hedberg124f6e32012-02-09 13:50:12 +02001430 if (cp->addr.type == MGMT_ADDR_BREDR)
1431 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
1432 else
1433 err = hci_remove_ltk(hdev, &cp->addr.bdaddr);
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03001434
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001435 if (err < 0) {
Johan Hedbergaee9b212012-02-18 15:07:59 +02001436 status = MGMT_STATUS_NOT_PAIRED;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001437 goto unlock;
1438 }
1439
Johan Hedberga8a1d192011-11-10 15:54:38 +02001440 if (!test_bit(HCI_UP, &hdev->flags) || !cp->disconnect) {
Johan Hedbergaee9b212012-02-18 15:07:59 +02001441 err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE, status,
1442 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001443 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001444 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001445 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001446
Johan Hedberg124f6e32012-02-09 13:50:12 +02001447 if (cp->addr.type == MGMT_ADDR_BREDR)
1448 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
1449 &cp->addr.bdaddr);
1450 else
1451 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
1452 &cp->addr.bdaddr);
1453
Johan Hedberga8a1d192011-11-10 15:54:38 +02001454 if (!conn) {
Johan Hedbergaee9b212012-02-18 15:07:59 +02001455 err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE, status,
1456 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001457 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001458 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001459 }
1460
Johan Hedberg124f6e32012-02-09 13:50:12 +02001461 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
1462 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02001463 if (!cmd) {
1464 err = -ENOMEM;
1465 goto unlock;
1466 }
1467
1468 put_unaligned_le16(conn->handle, &dc.handle);
1469 dc.reason = 0x13; /* Remote User Terminated Connection */
1470 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1471 if (err < 0)
1472 mgmt_pending_remove(cmd);
1473
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001474unlock:
Johan Hedbergca69b792011-11-11 18:10:00 +02001475 if (err < 0)
Johan Hedbergaee9b212012-02-18 15:07:59 +02001476 err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE, status,
1477 &rp, sizeof(rp));
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001478 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001479 hci_dev_put(hdev);
1480
1481 return err;
1482}
1483
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001484static int disconnect(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02001485{
1486 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001487 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001488 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03001489 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001490 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001491 int err;
1492
1493 BT_DBG("");
1494
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001495 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001496 return cmd_status(sk, index, MGMT_OP_DISCONNECT,
1497 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001498
Szymon Janc4e51eae2011-02-25 19:05:48 +01001499 hdev = hci_dev_get(index);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001500 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001501 return cmd_status(sk, index, MGMT_OP_DISCONNECT,
1502 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001503
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001504 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001505
1506 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001507 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1508 MGMT_STATUS_NOT_POWERED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001509 goto failed;
1510 }
1511
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001512 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001513 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1514 MGMT_STATUS_BUSY);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001515 goto failed;
1516 }
1517
Johan Hedberg88c3df12012-02-09 14:27:38 +02001518 if (cp->addr.type == MGMT_ADDR_BREDR)
1519 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
1520 else
1521 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03001522
Johan Hedberg8962ee72011-01-20 12:40:27 +02001523 if (!conn) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001524 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1525 MGMT_STATUS_NOT_CONNECTED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001526 goto failed;
1527 }
1528
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001529 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001530 if (!cmd) {
1531 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001532 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001533 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001534
1535 put_unaligned_le16(conn->handle, &dc.handle);
1536 dc.reason = 0x13; /* Remote User Terminated Connection */
1537
1538 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1539 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001540 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001541
1542failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001543 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001544 hci_dev_put(hdev);
1545
1546 return err;
1547}
1548
Johan Hedberg48264f02011-11-09 13:58:58 +02001549static u8 link_to_mgmt(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02001550{
1551 switch (link_type) {
1552 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02001553 switch (addr_type) {
1554 case ADDR_LE_DEV_PUBLIC:
1555 return MGMT_ADDR_LE_PUBLIC;
1556 case ADDR_LE_DEV_RANDOM:
1557 return MGMT_ADDR_LE_RANDOM;
1558 default:
1559 return MGMT_ADDR_INVALID;
1560 }
Johan Hedberg4c659c32011-11-07 23:13:39 +02001561 case ACL_LINK:
1562 return MGMT_ADDR_BREDR;
1563 default:
1564 return MGMT_ADDR_INVALID;
1565 }
1566}
1567
Szymon Janc8ce62842011-03-01 16:55:32 +01001568static int get_connections(struct sock *sk, u16 index)
Johan Hedberg2784eb42011-01-21 13:56:35 +02001569{
Johan Hedberg2784eb42011-01-21 13:56:35 +02001570 struct mgmt_rp_get_connections *rp;
1571 struct hci_dev *hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001572 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02001573 size_t rp_len;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001574 u16 count;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001575 int i, err;
1576
1577 BT_DBG("");
1578
Szymon Janc4e51eae2011-02-25 19:05:48 +01001579 hdev = hci_dev_get(index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001580 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001581 return cmd_status(sk, index, MGMT_OP_GET_CONNECTIONS,
1582 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001583
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001584 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001585
1586 count = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02001587 list_for_each_entry(c, &hdev->conn_hash.list, list) {
1588 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
1589 count++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001590 }
1591
Johan Hedberg4c659c32011-11-07 23:13:39 +02001592 rp_len = sizeof(*rp) + (count * sizeof(struct mgmt_addr_info));
Johan Hedberga38528f2011-01-22 06:46:43 +02001593 rp = kmalloc(rp_len, GFP_ATOMIC);
1594 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02001595 err = -ENOMEM;
1596 goto unlock;
1597 }
1598
Johan Hedberg2784eb42011-01-21 13:56:35 +02001599 put_unaligned_le16(count, &rp->conn_count);
1600
Johan Hedberg2784eb42011-01-21 13:56:35 +02001601 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001602 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02001603 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
1604 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001605 bacpy(&rp->addr[i].bdaddr, &c->dst);
Johan Hedberg48264f02011-11-09 13:58:58 +02001606 rp->addr[i].type = link_to_mgmt(c->type, c->dst_type);
Johan Hedberg4c659c32011-11-07 23:13:39 +02001607 if (rp->addr[i].type == MGMT_ADDR_INVALID)
1608 continue;
1609 i++;
1610 }
1611
1612 /* Recalculate length in case of filtered SCO connections, etc */
1613 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02001614
Johan Hedbergaee9b212012-02-18 15:07:59 +02001615 err = cmd_complete(sk, index, MGMT_OP_GET_CONNECTIONS, 0, rp, rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001616
1617unlock:
Johan Hedberga38528f2011-01-22 06:46:43 +02001618 kfree(rp);
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001619 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001620 hci_dev_put(hdev);
1621 return err;
1622}
1623
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001624static int send_pin_code_neg_reply(struct sock *sk, u16 index,
1625 struct hci_dev *hdev, struct mgmt_cp_pin_code_neg_reply *cp)
1626{
1627 struct pending_cmd *cmd;
1628 int err;
1629
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001630 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001631 sizeof(*cp));
1632 if (!cmd)
1633 return -ENOMEM;
1634
Johan Hedbergd8457692012-02-17 14:24:57 +02001635 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
1636 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001637 if (err < 0)
1638 mgmt_pending_remove(cmd);
1639
1640 return err;
1641}
1642
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001643static int pin_code_reply(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001644{
1645 struct hci_dev *hdev;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001646 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001647 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001648 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03001649 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001650 int err;
1651
1652 BT_DBG("");
1653
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001654 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001655 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1656 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001657
Szymon Janc4e51eae2011-02-25 19:05:48 +01001658 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001659 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001660 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1661 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001662
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001663 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001664
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001665 if (!hdev_is_powered(hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001666 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1667 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001668 goto failed;
1669 }
1670
Johan Hedbergd8457692012-02-17 14:24:57 +02001671 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001672 if (!conn) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001673 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1674 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001675 goto failed;
1676 }
1677
1678 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02001679 struct mgmt_cp_pin_code_neg_reply ncp;
1680
1681 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001682
1683 BT_ERR("PIN code is not 16 bytes long");
1684
1685 err = send_pin_code_neg_reply(sk, index, hdev, &ncp);
1686 if (err >= 0)
1687 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001688 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001689
1690 goto failed;
1691 }
1692
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001693 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data,
1694 len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001695 if (!cmd) {
1696 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001697 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001698 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02001699
Johan Hedbergd8457692012-02-17 14:24:57 +02001700 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001701 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02001702 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02001703
1704 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
1705 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001706 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001707
1708failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001709 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001710 hci_dev_put(hdev);
1711
1712 return err;
1713}
1714
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001715static int pin_code_neg_reply(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001716{
1717 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001718 struct mgmt_cp_pin_code_neg_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001719 int err;
1720
1721 BT_DBG("");
1722
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001723 if (len != sizeof(*cp))
1724 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001725 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001726
Szymon Janc4e51eae2011-02-25 19:05:48 +01001727 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001728 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001729 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001730 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001731
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001732 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001733
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001734 if (!hdev_is_powered(hdev)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001735 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001736 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001737 goto failed;
1738 }
1739
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001740 err = send_pin_code_neg_reply(sk, index, hdev, cp);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001741
1742failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001743 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001744 hci_dev_put(hdev);
1745
1746 return err;
1747}
1748
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001749static int set_io_capability(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001750{
1751 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001752 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001753
1754 BT_DBG("");
1755
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001756 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001757 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY,
1758 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001759
Szymon Janc4e51eae2011-02-25 19:05:48 +01001760 hdev = hci_dev_get(index);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001761 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001762 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY,
1763 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001764
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001765 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001766
1767 hdev->io_capability = cp->io_capability;
1768
1769 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Szymon Jancb8534e02011-03-01 16:55:34 +01001770 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001771
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001772 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001773 hci_dev_put(hdev);
1774
Johan Hedbergaee9b212012-02-18 15:07:59 +02001775 return cmd_complete(sk, index, MGMT_OP_SET_IO_CAPABILITY, 0, NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001776}
1777
Johan Hedberge9a416b2011-02-19 12:05:56 -03001778static inline struct pending_cmd *find_pairing(struct hci_conn *conn)
1779{
1780 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001781 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001782
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001783 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03001784 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
1785 continue;
1786
Johan Hedberge9a416b2011-02-19 12:05:56 -03001787 if (cmd->user_data != conn)
1788 continue;
1789
1790 return cmd;
1791 }
1792
1793 return NULL;
1794}
1795
1796static void pairing_complete(struct pending_cmd *cmd, u8 status)
1797{
1798 struct mgmt_rp_pair_device rp;
1799 struct hci_conn *conn = cmd->user_data;
1800
Johan Hedbergba4e5642011-11-11 00:07:34 +02001801 bacpy(&rp.addr.bdaddr, &conn->dst);
1802 rp.addr.type = link_to_mgmt(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001803
Johan Hedbergaee9b212012-02-18 15:07:59 +02001804 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, status,
1805 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001806
1807 /* So we don't get further callbacks for this connection */
1808 conn->connect_cfm_cb = NULL;
1809 conn->security_cfm_cb = NULL;
1810 conn->disconn_cfm_cb = NULL;
1811
1812 hci_conn_put(conn);
1813
Johan Hedberga664b5b2011-02-19 12:06:02 -03001814 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001815}
1816
1817static void pairing_complete_cb(struct hci_conn *conn, u8 status)
1818{
1819 struct pending_cmd *cmd;
1820
1821 BT_DBG("status %u", status);
1822
Johan Hedberg56e5cb82011-11-08 20:40:16 +02001823 cmd = find_pairing(conn);
1824 if (!cmd)
1825 BT_DBG("Unable to find a pending command");
1826 else
Johan Hedberge2113262012-02-18 15:20:03 +02001827 pairing_complete(cmd, mgmt_status(status));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001828}
1829
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001830static int pair_device(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001831{
1832 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001833 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02001834 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001835 struct pending_cmd *cmd;
1836 u8 sec_level, auth_type;
1837 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001838 int err;
1839
1840 BT_DBG("");
1841
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001842 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001843 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE,
1844 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001845
Szymon Janc4e51eae2011-02-25 19:05:48 +01001846 hdev = hci_dev_get(index);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001847 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001848 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE,
1849 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001850
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001851 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001852
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001853 sec_level = BT_SECURITY_MEDIUM;
1854 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001855 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001856 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03001857 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001858
Johan Hedbergba4e5642011-11-11 00:07:34 +02001859 if (cp->addr.type == MGMT_ADDR_BREDR)
1860 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr, sec_level,
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001861 auth_type);
1862 else
Johan Hedbergba4e5642011-11-11 00:07:34 +02001863 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr, sec_level,
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001864 auth_type);
1865
Johan Hedberg1425acb2011-11-11 00:07:35 +02001866 memset(&rp, 0, sizeof(rp));
1867 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1868 rp.addr.type = cp->addr.type;
1869
Ville Tervo30e76272011-02-22 16:10:53 -03001870 if (IS_ERR(conn)) {
Johan Hedberge2113262012-02-18 15:20:03 +02001871 err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE,
1872 MGMT_STATUS_CONNECT_FAILED,
1873 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001874 goto unlock;
1875 }
1876
1877 if (conn->connect_cfm_cb) {
1878 hci_conn_put(conn);
Johan Hedberge2113262012-02-18 15:20:03 +02001879 err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE,
1880 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001881 goto unlock;
1882 }
1883
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001884 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001885 if (!cmd) {
1886 err = -ENOMEM;
1887 hci_conn_put(conn);
1888 goto unlock;
1889 }
1890
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001891 /* For LE, just connecting isn't a proof that the pairing finished */
Johan Hedbergba4e5642011-11-11 00:07:34 +02001892 if (cp->addr.type == MGMT_ADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001893 conn->connect_cfm_cb = pairing_complete_cb;
1894
Johan Hedberge9a416b2011-02-19 12:05:56 -03001895 conn->security_cfm_cb = pairing_complete_cb;
1896 conn->disconn_cfm_cb = pairing_complete_cb;
1897 conn->io_capability = cp->io_cap;
1898 cmd->user_data = conn;
1899
1900 if (conn->state == BT_CONNECTED &&
1901 hci_conn_security(conn, sec_level, auth_type))
1902 pairing_complete(cmd, 0);
1903
1904 err = 0;
1905
1906unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001907 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001908 hci_dev_put(hdev);
1909
1910 return err;
1911}
1912
Johan Hedberg28424702012-02-02 04:02:29 +02001913static int cancel_pair_device(struct sock *sk, u16 index,
1914 unsigned char *data, u16 len)
1915{
1916 struct mgmt_addr_info *addr = (void *) data;
1917 struct hci_dev *hdev;
1918 struct pending_cmd *cmd;
1919 struct hci_conn *conn;
1920 int err;
1921
1922 BT_DBG("");
1923
1924 if (len != sizeof(*addr))
1925 return cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
1926 MGMT_STATUS_INVALID_PARAMS);
1927
1928 hdev = hci_dev_get(index);
1929 if (!hdev)
1930 return cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
1931 MGMT_STATUS_INVALID_PARAMS);
1932
1933 hci_dev_lock(hdev);
1934
1935 cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
1936 if (!cmd) {
1937 err = cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
1938 MGMT_STATUS_INVALID_PARAMS);
1939 goto unlock;
1940 }
1941
1942 conn = cmd->user_data;
1943
1944 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
1945 err = cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
1946 MGMT_STATUS_INVALID_PARAMS);
1947 goto unlock;
1948 }
1949
1950 pairing_complete(cmd, MGMT_STATUS_CANCELLED);
1951
Johan Hedbergaee9b212012-02-18 15:07:59 +02001952 err = cmd_complete(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE, 0, addr,
Johan Hedberg28424702012-02-02 04:02:29 +02001953 sizeof(*addr));
1954unlock:
1955 hci_dev_unlock(hdev);
1956 hci_dev_put(hdev);
1957
1958 return err;
1959}
1960
Brian Gix0df4c182011-11-16 13:53:13 -08001961static int user_pairing_resp(struct sock *sk, u16 index, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02001962 u8 type, u16 mgmt_op, u16 hci_op,
1963 __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03001964{
Johan Hedberga5c29682011-02-19 12:05:57 -03001965 struct pending_cmd *cmd;
1966 struct hci_dev *hdev;
Brian Gix0df4c182011-11-16 13:53:13 -08001967 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03001968 int err;
1969
Szymon Janc4e51eae2011-02-25 19:05:48 +01001970 hdev = hci_dev_get(index);
Johan Hedberga5c29682011-02-19 12:05:57 -03001971 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001972 return cmd_status(sk, index, mgmt_op,
1973 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga5c29682011-02-19 12:05:57 -03001974
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001975 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02001976
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001977 if (!hdev_is_powered(hdev)) {
Brian Gix0df4c182011-11-16 13:53:13 -08001978 err = cmd_status(sk, index, mgmt_op, MGMT_STATUS_NOT_POWERED);
1979 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03001980 }
1981
Johan Hedberg272d90d2012-02-09 15:26:12 +02001982 if (type == MGMT_ADDR_BREDR)
1983 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, bdaddr);
1984 else
Brian Gix47c15e22011-11-16 13:53:14 -08001985 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, bdaddr);
Brian Gix47c15e22011-11-16 13:53:14 -08001986
Johan Hedberg272d90d2012-02-09 15:26:12 +02001987 if (!conn) {
1988 err = cmd_status(sk, index, mgmt_op,
1989 MGMT_STATUS_NOT_CONNECTED);
1990 goto done;
1991 }
1992
1993 if (type == MGMT_ADDR_LE_PUBLIC || type == MGMT_ADDR_LE_RANDOM) {
Brian Gix47c15e22011-11-16 13:53:14 -08001994 /* Continue with pairing via SMP */
Brian Gix5fe57d92011-12-21 16:12:13 -08001995 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix47c15e22011-11-16 13:53:14 -08001996
Brian Gix5fe57d92011-12-21 16:12:13 -08001997 if (!err)
1998 err = cmd_status(sk, index, mgmt_op,
1999 MGMT_STATUS_SUCCESS);
2000 else
2001 err = cmd_status(sk, index, mgmt_op,
2002 MGMT_STATUS_FAILED);
2003
Brian Gix47c15e22011-11-16 13:53:14 -08002004 goto done;
2005 }
2006
Brian Gix0df4c182011-11-16 13:53:13 -08002007 cmd = mgmt_pending_add(sk, mgmt_op, hdev, bdaddr, sizeof(*bdaddr));
Johan Hedberga5c29682011-02-19 12:05:57 -03002008 if (!cmd) {
2009 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08002010 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002011 }
2012
Brian Gix0df4c182011-11-16 13:53:13 -08002013 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08002014 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
2015 struct hci_cp_user_passkey_reply cp;
2016
2017 bacpy(&cp.bdaddr, bdaddr);
2018 cp.passkey = passkey;
2019 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
2020 } else
2021 err = hci_send_cmd(hdev, hci_op, sizeof(*bdaddr), bdaddr);
2022
Johan Hedberga664b5b2011-02-19 12:06:02 -03002023 if (err < 0)
2024 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002025
Brian Gix0df4c182011-11-16 13:53:13 -08002026done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002027 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002028 hci_dev_put(hdev);
2029
2030 return err;
2031}
2032
Brian Gix0df4c182011-11-16 13:53:13 -08002033static int user_confirm_reply(struct sock *sk, u16 index, void *data, u16 len)
2034{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002035 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002036
2037 BT_DBG("");
2038
2039 if (len != sizeof(*cp))
2040 return cmd_status(sk, index, MGMT_OP_USER_CONFIRM_REPLY,
2041 MGMT_STATUS_INVALID_PARAMS);
2042
Johan Hedberg272d90d2012-02-09 15:26:12 +02002043 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
2044 MGMT_OP_USER_CONFIRM_REPLY,
2045 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002046}
2047
2048static int user_confirm_neg_reply(struct sock *sk, u16 index, void *data,
2049 u16 len)
2050{
Johan Hedbergc9c26592011-12-15 00:47:41 +02002051 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002052
2053 BT_DBG("");
2054
2055 if (len != sizeof(*cp))
2056 return cmd_status(sk, index, MGMT_OP_USER_CONFIRM_NEG_REPLY,
2057 MGMT_STATUS_INVALID_PARAMS);
2058
Johan Hedberg272d90d2012-02-09 15:26:12 +02002059 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
2060 MGMT_OP_USER_CONFIRM_NEG_REPLY,
2061 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002062}
2063
Brian Gix604086b2011-11-23 08:28:33 -08002064static int user_passkey_reply(struct sock *sk, u16 index, void *data, u16 len)
2065{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002066 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002067
2068 BT_DBG("");
2069
2070 if (len != sizeof(*cp))
2071 return cmd_status(sk, index, MGMT_OP_USER_PASSKEY_REPLY,
2072 EINVAL);
2073
Johan Hedberg272d90d2012-02-09 15:26:12 +02002074 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
2075 MGMT_OP_USER_PASSKEY_REPLY,
2076 HCI_OP_USER_PASSKEY_REPLY,
2077 cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08002078}
2079
2080static int user_passkey_neg_reply(struct sock *sk, u16 index, void *data,
2081 u16 len)
2082{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002083 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002084
2085 BT_DBG("");
2086
2087 if (len != sizeof(*cp))
2088 return cmd_status(sk, index, MGMT_OP_USER_PASSKEY_NEG_REPLY,
2089 EINVAL);
2090
Johan Hedberg272d90d2012-02-09 15:26:12 +02002091 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
2092 MGMT_OP_USER_PASSKEY_NEG_REPLY,
2093 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08002094}
2095
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002096static int set_local_name(struct sock *sk, u16 index, void *data,
Johan Hedbergb312b1612011-03-16 14:29:37 +02002097 u16 len)
2098{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002099 struct mgmt_cp_set_local_name *mgmt_cp = data;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002100 struct hci_cp_write_local_name hci_cp;
2101 struct hci_dev *hdev;
2102 struct pending_cmd *cmd;
2103 int err;
2104
2105 BT_DBG("");
2106
2107 if (len != sizeof(*mgmt_cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02002108 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME,
2109 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002110
2111 hdev = hci_dev_get(index);
2112 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002113 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME,
2114 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002115
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002116 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002117
Johan Hedbergb5235a62012-02-21 14:32:24 +02002118 if (!hdev_is_powered(hdev)) {
2119 err = cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME,
2120 MGMT_STATUS_NOT_POWERED);
2121 goto failed;
2122 }
2123
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002124 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data,
2125 len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002126 if (!cmd) {
2127 err = -ENOMEM;
2128 goto failed;
2129 }
2130
2131 memcpy(hci_cp.name, mgmt_cp->name, sizeof(hci_cp.name));
2132 err = hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(hci_cp),
2133 &hci_cp);
2134 if (err < 0)
2135 mgmt_pending_remove(cmd);
2136
2137failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002138 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002139 hci_dev_put(hdev);
2140
2141 return err;
2142}
2143
Szymon Jancc35938b2011-03-22 13:12:21 +01002144static int read_local_oob_data(struct sock *sk, u16 index)
2145{
2146 struct hci_dev *hdev;
2147 struct pending_cmd *cmd;
2148 int err;
2149
2150 BT_DBG("hci%u", index);
2151
2152 hdev = hci_dev_get(index);
2153 if (!hdev)
2154 return cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002155 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancc35938b2011-03-22 13:12:21 +01002156
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002157 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002158
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002159 if (!hdev_is_powered(hdev)) {
Szymon Jancc35938b2011-03-22 13:12:21 +01002160 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002161 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002162 goto unlock;
2163 }
2164
2165 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
2166 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002167 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002168 goto unlock;
2169 }
2170
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002171 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02002172 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2173 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01002174 goto unlock;
2175 }
2176
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002177 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01002178 if (!cmd) {
2179 err = -ENOMEM;
2180 goto unlock;
2181 }
2182
2183 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
2184 if (err < 0)
2185 mgmt_pending_remove(cmd);
2186
2187unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002188 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002189 hci_dev_put(hdev);
2190
2191 return err;
2192}
2193
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002194static int add_remote_oob_data(struct sock *sk, u16 index, void *data,
2195 u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002196{
2197 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002198 struct mgmt_cp_add_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002199 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002200 int err;
2201
2202 BT_DBG("hci%u ", index);
2203
2204 if (len != sizeof(*cp))
2205 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002206 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01002207
2208 hdev = hci_dev_get(index);
2209 if (!hdev)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002210 return cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
2211 MGMT_STATUS_INVALID_PARAMS,
2212 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002213
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002214 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002215
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002216 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, cp->hash,
Szymon Janc2763eda2011-03-22 13:12:22 +01002217 cp->randomizer);
2218 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002219 status = MGMT_STATUS_FAILED;
Szymon Janc2763eda2011-03-22 13:12:22 +01002220 else
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002221 status = 0;
2222
2223 err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, status,
2224 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002225
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002226 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002227 hci_dev_put(hdev);
2228
2229 return err;
2230}
2231
2232static int remove_remote_oob_data(struct sock *sk, u16 index,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002233 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002234{
2235 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002236 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002237 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002238 int err;
2239
2240 BT_DBG("hci%u ", index);
2241
2242 if (len != sizeof(*cp))
2243 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002244 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01002245
2246 hdev = hci_dev_get(index);
2247 if (!hdev)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002248 return cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2249 MGMT_STATUS_INVALID_PARAMS,
2250 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002251
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002252 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002253
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002254 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr);
Szymon Janc2763eda2011-03-22 13:12:22 +01002255 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002256 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01002257 else
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002258 status = 0;
2259
2260 err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA, status,
2261 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002262
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002263 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002264 hci_dev_put(hdev);
2265
2266 return err;
2267}
2268
Andre Guedes5e0452c2012-02-17 20:39:38 -03002269static int discovery(struct hci_dev *hdev)
2270{
2271 int err;
2272
2273 if (lmp_host_le_capable(hdev)) {
2274 if (lmp_bredr_capable(hdev)) {
2275 err = hci_le_scan(hdev, LE_SCAN_TYPE,
2276 LE_SCAN_INT, LE_SCAN_WIN,
2277 LE_SCAN_TIMEOUT_BREDR_LE);
2278 } else {
2279 hdev->discovery.type = DISCOV_TYPE_LE;
2280 err = hci_le_scan(hdev, LE_SCAN_TYPE,
2281 LE_SCAN_INT, LE_SCAN_WIN,
2282 LE_SCAN_TIMEOUT_LE_ONLY);
2283 }
2284 } else {
2285 hdev->discovery.type = DISCOV_TYPE_BREDR;
2286 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
2287 }
2288
2289 return err;
2290}
2291
2292int mgmt_interleaved_discovery(struct hci_dev *hdev)
2293{
2294 int err;
2295
2296 BT_DBG("%s", hdev->name);
2297
2298 hci_dev_lock(hdev);
2299
2300 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR_LE);
2301 if (err < 0)
2302 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2303
2304 hci_dev_unlock(hdev);
2305
2306 return err;
2307}
2308
Johan Hedberg450dfda2011-11-12 11:58:22 +02002309static int start_discovery(struct sock *sk, u16 index,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002310 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002311{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002312 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002313 struct pending_cmd *cmd;
2314 struct hci_dev *hdev;
2315 int err;
2316
2317 BT_DBG("hci%u", index);
2318
Johan Hedberg450dfda2011-11-12 11:58:22 +02002319 if (len != sizeof(*cp))
2320 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2321 MGMT_STATUS_INVALID_PARAMS);
2322
Johan Hedberg14a53662011-04-27 10:29:56 -04002323 hdev = hci_dev_get(index);
2324 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002325 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2326 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg14a53662011-04-27 10:29:56 -04002327
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002328 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002329
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002330 if (!hdev_is_powered(hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02002331 err = cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2332 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02002333 goto failed;
2334 }
2335
Johan Hedbergff9ef572012-01-04 14:23:45 +02002336 if (hdev->discovery.state != DISCOVERY_STOPPED) {
2337 err = cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2338 MGMT_STATUS_BUSY);
2339 goto failed;
2340 }
2341
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002342 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002343 if (!cmd) {
2344 err = -ENOMEM;
2345 goto failed;
2346 }
2347
Andre Guedes4aab14e2012-02-17 20:39:36 -03002348 hdev->discovery.type = cp->type;
2349
2350 switch (hdev->discovery.type) {
Andre Guedesf39799f2012-02-17 20:39:35 -03002351 case DISCOV_TYPE_BREDR:
Andre Guedes3fd24152012-02-03 17:48:01 -03002352 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
Andre Guedesf39799f2012-02-17 20:39:35 -03002353 break;
2354
2355 case DISCOV_TYPE_LE:
Andre Guedes3fd24152012-02-03 17:48:01 -03002356 err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT,
2357 LE_SCAN_WIN, LE_SCAN_TIMEOUT_LE_ONLY);
Andre Guedesf39799f2012-02-17 20:39:35 -03002358 break;
2359
Andre Guedes5e0452c2012-02-17 20:39:38 -03002360 case DISCOV_TYPE_INTERLEAVED:
2361 err = discovery(hdev);
2362 break;
2363
Andre Guedesf39799f2012-02-17 20:39:35 -03002364 default:
Andre Guedes3fd24152012-02-03 17:48:01 -03002365 err = -EINVAL;
Andre Guedesf39799f2012-02-17 20:39:35 -03002366 }
Andre Guedes3fd24152012-02-03 17:48:01 -03002367
Johan Hedberg14a53662011-04-27 10:29:56 -04002368 if (err < 0)
2369 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002370 else
2371 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002372
2373failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002374 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002375 hci_dev_put(hdev);
2376
2377 return err;
2378}
2379
Johan Hedbergd9306502012-02-20 23:25:18 +02002380static int stop_discovery(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002381{
Johan Hedbergd9306502012-02-20 23:25:18 +02002382 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002383 struct hci_dev *hdev;
2384 struct pending_cmd *cmd;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002385 struct hci_cp_remote_name_req_cancel cp;
2386 struct inquiry_entry *e;
Johan Hedberg14a53662011-04-27 10:29:56 -04002387 int err;
2388
2389 BT_DBG("hci%u", index);
2390
Johan Hedbergd9306502012-02-20 23:25:18 +02002391 if (len != sizeof(*mgmt_cp))
2392 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY,
2393 MGMT_STATUS_INVALID_PARAMS);
2394
Johan Hedberg14a53662011-04-27 10:29:56 -04002395 hdev = hci_dev_get(index);
2396 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002397 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY,
2398 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg14a53662011-04-27 10:29:56 -04002399
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002400 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002401
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002402 if (!hci_discovery_active(hdev)) {
Johan Hedbergd9306502012-02-20 23:25:18 +02002403 err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY,
2404 MGMT_STATUS_REJECTED,
2405 &mgmt_cp->type, sizeof(mgmt_cp->type));
2406 goto unlock;
2407 }
2408
2409 if (hdev->discovery.type != mgmt_cp->type) {
2410 err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY,
2411 MGMT_STATUS_INVALID_PARAMS,
2412 &mgmt_cp->type, sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002413 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02002414 }
2415
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002416 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002417 if (!cmd) {
2418 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002419 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04002420 }
2421
Andre Guedes343f9352012-02-17 20:39:37 -03002422 if (hdev->discovery.state == DISCOVERY_FINDING) {
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002423 err = hci_cancel_inquiry(hdev);
2424 if (err < 0)
2425 mgmt_pending_remove(cmd);
2426 else
2427 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
2428 goto unlock;
2429 }
2430
2431 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY, NAME_PENDING);
2432 if (!e) {
2433 mgmt_pending_remove(cmd);
Johan Hedbergaee9b212012-02-18 15:07:59 +02002434 err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY, 0,
Johan Hedbergd9306502012-02-20 23:25:18 +02002435 &mgmt_cp->type, sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002436 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2437 goto unlock;
2438 }
2439
2440 bacpy(&cp.bdaddr, &e->data.bdaddr);
2441 err = hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ_CANCEL,
2442 sizeof(cp), &cp);
Johan Hedberg14a53662011-04-27 10:29:56 -04002443 if (err < 0)
2444 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002445 else
2446 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002447
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002448unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002449 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002450 hci_dev_put(hdev);
2451
2452 return err;
2453}
2454
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002455static int confirm_name(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02002456{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002457 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002458 struct inquiry_entry *e;
2459 struct hci_dev *hdev;
2460 int err;
2461
2462 BT_DBG("hci%u", index);
2463
2464 if (len != sizeof(*cp))
2465 return cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2466 MGMT_STATUS_INVALID_PARAMS);
2467
2468 hdev = hci_dev_get(index);
2469 if (!hdev)
2470 return cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2471 MGMT_STATUS_INVALID_PARAMS);
2472
2473 hci_dev_lock(hdev);
2474
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002475 if (!hci_discovery_active(hdev)) {
2476 err = cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2477 MGMT_STATUS_FAILED);
2478 goto failed;
2479 }
2480
Johan Hedberga198e7b2012-02-17 14:27:06 +02002481 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002482 if (!e) {
2483 err = cmd_status (sk, index, MGMT_OP_CONFIRM_NAME,
2484 MGMT_STATUS_INVALID_PARAMS);
2485 goto failed;
2486 }
2487
2488 if (cp->name_known) {
2489 e->name_state = NAME_KNOWN;
2490 list_del(&e->list);
2491 } else {
2492 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e202012-01-09 00:53:02 +02002493 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002494 }
2495
2496 err = 0;
2497
2498failed:
2499 hci_dev_unlock(hdev);
2500
2501 return err;
2502}
2503
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002504static int block_device(struct sock *sk, u16 index, void *data, u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002505{
2506 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002507 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002508 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03002509 int err;
2510
2511 BT_DBG("hci%u", index);
2512
Antti Julku7fbec222011-06-15 12:01:15 +03002513 if (len != sizeof(*cp))
2514 return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002515 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002516
2517 hdev = hci_dev_get(index);
2518 if (!hdev)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002519 return cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE,
2520 MGMT_STATUS_INVALID_PARAMS,
2521 &cp->addr, sizeof(cp->addr));
Antti Julku7fbec222011-06-15 12:01:15 +03002522
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002523 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002524
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002525 err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002526 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002527 status = MGMT_STATUS_FAILED;
Antti Julku7fbec222011-06-15 12:01:15 +03002528 else
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002529 status = 0;
2530
2531 err = cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE, status,
2532 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03002533
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002534 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002535 hci_dev_put(hdev);
2536
2537 return err;
2538}
2539
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002540static int unblock_device(struct sock *sk, u16 index, void *data, u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002541{
2542 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002543 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002544 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03002545 int err;
2546
2547 BT_DBG("hci%u", index);
2548
Antti Julku7fbec222011-06-15 12:01:15 +03002549 if (len != sizeof(*cp))
2550 return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002551 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002552
2553 hdev = hci_dev_get(index);
2554 if (!hdev)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002555 return cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE,
2556 MGMT_STATUS_INVALID_PARAMS,
2557 &cp->addr, sizeof(cp->addr));
Antti Julku7fbec222011-06-15 12:01:15 +03002558
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002559 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002560
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002561 err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002562 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002563 status = MGMT_STATUS_INVALID_PARAMS;
Antti Julku7fbec222011-06-15 12:01:15 +03002564 else
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002565 status = 0;
2566
2567 err = cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE, status,
2568 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03002569
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002570 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002571 hci_dev_put(hdev);
2572
2573 return err;
2574}
2575
Antti Julkuf6422ec2011-06-22 13:11:56 +03002576static int set_fast_connectable(struct sock *sk, u16 index,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002577 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03002578{
2579 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002580 struct mgmt_mode *cp = data;
Antti Julkuf6422ec2011-06-22 13:11:56 +03002581 struct hci_cp_write_page_scan_activity acp;
2582 u8 type;
2583 int err;
2584
2585 BT_DBG("hci%u", index);
2586
2587 if (len != sizeof(*cp))
2588 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002589 MGMT_STATUS_INVALID_PARAMS);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002590
2591 hdev = hci_dev_get(index);
2592 if (!hdev)
2593 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002594 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg5400c042012-02-21 16:40:33 +02002595 if (!hdev_is_powered(hdev))
2596 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
2597 MGMT_STATUS_NOT_POWERED);
2598
2599 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
2600 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
2601 MGMT_STATUS_REJECTED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002602
2603 hci_dev_lock(hdev);
2604
Johan Hedbergf7c6869ce2011-12-15 00:47:36 +02002605 if (cp->val) {
Antti Julkuf6422ec2011-06-22 13:11:56 +03002606 type = PAGE_SCAN_TYPE_INTERLACED;
2607 acp.interval = 0x0024; /* 22.5 msec page scan interval */
2608 } else {
2609 type = PAGE_SCAN_TYPE_STANDARD; /* default */
2610 acp.interval = 0x0800; /* default 1.28 sec page scan */
2611 }
2612
2613 acp.window = 0x0012; /* default 11.25 msec page scan window */
2614
2615 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
2616 sizeof(acp), &acp);
2617 if (err < 0) {
2618 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002619 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002620 goto done;
2621 }
2622
2623 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
2624 if (err < 0) {
2625 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002626 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002627 goto done;
2628 }
2629
Johan Hedbergaee9b212012-02-18 15:07:59 +02002630 err = cmd_complete(sk, index, MGMT_OP_SET_FAST_CONNECTABLE, 0,
2631 NULL, 0);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002632done:
2633 hci_dev_unlock(hdev);
2634 hci_dev_put(hdev);
2635
2636 return err;
2637}
2638
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002639static int load_long_term_keys(struct sock *sk, u16 index,
2640 void *cp_data, u16 len)
2641{
2642 struct hci_dev *hdev;
2643 struct mgmt_cp_load_long_term_keys *cp = cp_data;
2644 u16 key_count, expected_len;
2645 int i;
2646
2647 if (len < sizeof(*cp))
2648 return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS,
2649 EINVAL);
2650
2651 key_count = get_unaligned_le16(&cp->key_count);
2652
2653 expected_len = sizeof(*cp) + key_count *
2654 sizeof(struct mgmt_ltk_info);
2655 if (expected_len != len) {
2656 BT_ERR("load_keys: expected %u bytes, got %u bytes",
2657 len, expected_len);
2658 return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS,
2659 EINVAL);
2660 }
2661
2662 hdev = hci_dev_get(index);
2663 if (!hdev)
2664 return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS,
2665 ENODEV);
2666
2667 BT_DBG("hci%u key_count %u", index, key_count);
2668
2669 hci_dev_lock(hdev);
2670
2671 hci_smp_ltks_clear(hdev);
2672
2673 for (i = 0; i < key_count; i++) {
2674 struct mgmt_ltk_info *key = &cp->keys[i];
2675 u8 type;
2676
2677 if (key->master)
2678 type = HCI_SMP_LTK;
2679 else
2680 type = HCI_SMP_LTK_SLAVE;
2681
2682 hci_add_ltk(hdev, &key->addr.bdaddr, key->addr.type,
2683 type, 0, key->authenticated, key->val,
2684 key->enc_size, key->ediv, key->rand);
2685 }
2686
2687 hci_dev_unlock(hdev);
2688 hci_dev_put(hdev);
2689
2690 return 0;
2691}
2692
Johan Hedberg03811012010-12-08 00:21:06 +02002693int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
2694{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002695 void *buf;
2696 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02002697 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002698 u16 opcode, index, len;
Johan Hedberg03811012010-12-08 00:21:06 +02002699 int err;
2700
2701 BT_DBG("got %zu bytes", msglen);
2702
2703 if (msglen < sizeof(*hdr))
2704 return -EINVAL;
2705
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03002706 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02002707 if (!buf)
2708 return -ENOMEM;
2709
2710 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
2711 err = -EFAULT;
2712 goto done;
2713 }
2714
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002715 hdr = buf;
Johan Hedberg03811012010-12-08 00:21:06 +02002716 opcode = get_unaligned_le16(&hdr->opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002717 index = get_unaligned_le16(&hdr->index);
Johan Hedberg03811012010-12-08 00:21:06 +02002718 len = get_unaligned_le16(&hdr->len);
2719
2720 if (len != msglen - sizeof(*hdr)) {
2721 err = -EINVAL;
2722 goto done;
2723 }
2724
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002725 cp = buf + sizeof(*hdr);
2726
Johan Hedberg03811012010-12-08 00:21:06 +02002727 switch (opcode) {
Johan Hedberg02d98122010-12-13 21:07:04 +02002728 case MGMT_OP_READ_VERSION:
2729 err = read_version(sk);
2730 break;
Johan Hedberge70bb2e2012-02-13 16:59:33 +02002731 case MGMT_OP_READ_COMMANDS:
2732 err = read_commands(sk);
2733 break;
Johan Hedbergfaba42e2010-12-13 21:07:05 +02002734 case MGMT_OP_READ_INDEX_LIST:
2735 err = read_index_list(sk);
2736 break;
Johan Hedbergf7b64e692010-12-13 21:07:06 +02002737 case MGMT_OP_READ_INFO:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002738 err = read_controller_info(sk, index);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02002739 break;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002740 case MGMT_OP_SET_POWERED:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002741 err = set_powered(sk, index, cp, len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002742 break;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002743 case MGMT_OP_SET_DISCOVERABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002744 err = set_discoverable(sk, index, cp, len);
Johan Hedberg73f22f62010-12-29 16:00:25 +02002745 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002746 case MGMT_OP_SET_CONNECTABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002747 err = set_connectable(sk, index, cp, len);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002748 break;
Johan Hedbergf7c6869ce2011-12-15 00:47:36 +02002749 case MGMT_OP_SET_FAST_CONNECTABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002750 err = set_fast_connectable(sk, index, cp, len);
Johan Hedbergf7c6869ce2011-12-15 00:47:36 +02002751 break;
Johan Hedbergc542a062011-01-26 13:11:03 +02002752 case MGMT_OP_SET_PAIRABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002753 err = set_pairable(sk, index, cp, len);
Johan Hedbergc542a062011-01-26 13:11:03 +02002754 break;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02002755 case MGMT_OP_SET_LINK_SECURITY:
2756 err = set_link_security(sk, index, cp, len);
2757 break;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02002758 case MGMT_OP_SET_SSP:
2759 err = set_ssp(sk, index, cp, len);
2760 break;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02002761 case MGMT_OP_SET_HS:
2762 err = set_hs(sk, index, cp, len);
2763 break;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002764 case MGMT_OP_ADD_UUID:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002765 err = add_uuid(sk, index, cp, len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002766 break;
2767 case MGMT_OP_REMOVE_UUID:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002768 err = remove_uuid(sk, index, cp, len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002769 break;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002770 case MGMT_OP_SET_DEV_CLASS:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002771 err = set_dev_class(sk, index, cp, len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002772 break;
Johan Hedberg86742e12011-11-07 23:13:38 +02002773 case MGMT_OP_LOAD_LINK_KEYS:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002774 err = load_link_keys(sk, index, cp, len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002775 break;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002776 case MGMT_OP_DISCONNECT:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002777 err = disconnect(sk, index, cp, len);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002778 break;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002779 case MGMT_OP_GET_CONNECTIONS:
Szymon Janc8ce62842011-03-01 16:55:32 +01002780 err = get_connections(sk, index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002781 break;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002782 case MGMT_OP_PIN_CODE_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002783 err = pin_code_reply(sk, index, cp, len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002784 break;
2785 case MGMT_OP_PIN_CODE_NEG_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002786 err = pin_code_neg_reply(sk, index, cp, len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002787 break;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002788 case MGMT_OP_SET_IO_CAPABILITY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002789 err = set_io_capability(sk, index, cp, len);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002790 break;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002791 case MGMT_OP_PAIR_DEVICE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002792 err = pair_device(sk, index, cp, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002793 break;
Johan Hedberg28424702012-02-02 04:02:29 +02002794 case MGMT_OP_CANCEL_PAIR_DEVICE:
2795 err = cancel_pair_device(sk, index, buf + sizeof(*hdr), len);
2796 break;
Johan Hedberg124f6e32012-02-09 13:50:12 +02002797 case MGMT_OP_UNPAIR_DEVICE:
2798 err = unpair_device(sk, index, cp, len);
2799 break;
Johan Hedberga5c29682011-02-19 12:05:57 -03002800 case MGMT_OP_USER_CONFIRM_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002801 err = user_confirm_reply(sk, index, cp, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03002802 break;
2803 case MGMT_OP_USER_CONFIRM_NEG_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002804 err = user_confirm_neg_reply(sk, index, cp, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03002805 break;
Brian Gix604086b2011-11-23 08:28:33 -08002806 case MGMT_OP_USER_PASSKEY_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002807 err = user_passkey_reply(sk, index, cp, len);
Brian Gix604086b2011-11-23 08:28:33 -08002808 break;
2809 case MGMT_OP_USER_PASSKEY_NEG_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002810 err = user_passkey_neg_reply(sk, index, cp, len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002811 break;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002812 case MGMT_OP_SET_LOCAL_NAME:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002813 err = set_local_name(sk, index, cp, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002814 break;
Szymon Jancc35938b2011-03-22 13:12:21 +01002815 case MGMT_OP_READ_LOCAL_OOB_DATA:
2816 err = read_local_oob_data(sk, index);
2817 break;
Szymon Janc2763eda2011-03-22 13:12:22 +01002818 case MGMT_OP_ADD_REMOTE_OOB_DATA:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002819 err = add_remote_oob_data(sk, index, cp, len);
Szymon Janc2763eda2011-03-22 13:12:22 +01002820 break;
2821 case MGMT_OP_REMOVE_REMOTE_OOB_DATA:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002822 err = remove_remote_oob_data(sk, index, cp, len);
Szymon Janc2763eda2011-03-22 13:12:22 +01002823 break;
Johan Hedberg14a53662011-04-27 10:29:56 -04002824 case MGMT_OP_START_DISCOVERY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002825 err = start_discovery(sk, index, cp, len);
Johan Hedberg14a53662011-04-27 10:29:56 -04002826 break;
2827 case MGMT_OP_STOP_DISCOVERY:
Johan Hedbergd9306502012-02-20 23:25:18 +02002828 err = stop_discovery(sk, index, cp, len);
Johan Hedberg14a53662011-04-27 10:29:56 -04002829 break;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002830 case MGMT_OP_CONFIRM_NAME:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002831 err = confirm_name(sk, index, cp, len);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002832 break;
Antti Julku7fbec222011-06-15 12:01:15 +03002833 case MGMT_OP_BLOCK_DEVICE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002834 err = block_device(sk, index, cp, len);
Antti Julku7fbec222011-06-15 12:01:15 +03002835 break;
2836 case MGMT_OP_UNBLOCK_DEVICE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002837 err = unblock_device(sk, index, cp, len);
Antti Julku7fbec222011-06-15 12:01:15 +03002838 break;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002839 case MGMT_OP_LOAD_LONG_TERM_KEYS:
2840 err = load_long_term_keys(sk, index, cp, len);
2841 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002842 default:
Johan Hedberg72a734e2010-12-30 00:38:22 +02002843 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02002844 err = cmd_status(sk, index, opcode,
2845 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002846 break;
2847 }
Johan Hedberg72a734e2010-12-30 00:38:22 +02002848
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002849 if (err < 0)
Johan Hedberg72a734e2010-12-30 00:38:22 +02002850 goto done;
2851
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002852 err = msglen;
2853
2854done:
2855 kfree(buf);
2856 return err;
2857}
2858
Johan Hedbergb24752f2011-11-03 14:40:33 +02002859static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
2860{
2861 u8 *status = data;
2862
2863 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
2864 mgmt_pending_remove(cmd);
2865}
2866
Johan Hedberg744cf192011-11-08 20:40:14 +02002867int mgmt_index_added(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +02002868{
Johan Hedberg744cf192011-11-08 20:40:14 +02002869 return mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02002870}
2871
Johan Hedberg744cf192011-11-08 20:40:14 +02002872int mgmt_index_removed(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +02002873{
Johan Hedbergb24752f2011-11-03 14:40:33 +02002874 u8 status = ENODEV;
2875
Johan Hedberg744cf192011-11-08 20:40:14 +02002876 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002877
Johan Hedberg744cf192011-11-08 20:40:14 +02002878 return mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02002879}
2880
2881struct cmd_lookup {
Johan Hedberg03811012010-12-08 00:21:06 +02002882 struct sock *sk;
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002883 struct hci_dev *hdev;
Johan Hedberg03811012010-12-08 00:21:06 +02002884};
2885
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002886static void settings_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberg03811012010-12-08 00:21:06 +02002887{
Johan Hedberg03811012010-12-08 00:21:06 +02002888 struct cmd_lookup *match = data;
2889
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002890 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02002891
2892 list_del(&cmd->list);
2893
2894 if (match->sk == NULL) {
2895 match->sk = cmd->sk;
2896 sock_hold(match->sk);
2897 }
2898
2899 mgmt_pending_free(cmd);
2900}
2901
Johan Hedberg744cf192011-11-08 20:40:14 +02002902int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg03811012010-12-08 00:21:06 +02002903{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002904 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002905 __le32 ev;
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002906 int err;
Johan Hedberg03811012010-12-08 00:21:06 +02002907
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002908 if (!test_bit(HCI_MGMT, &hdev->dev_flags))
2909 return 0;
2910
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002911 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
Johan Hedberg03811012010-12-08 00:21:06 +02002912
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002913 if (powered) {
2914 u8 scan = 0;
2915
2916 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
2917 scan |= SCAN_PAGE;
2918 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
2919 scan |= SCAN_INQUIRY;
2920
2921 if (scan)
2922 hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
2923 } else {
Johan Hedbergb24752f2011-11-03 14:40:33 +02002924 u8 status = ENETDOWN;
Johan Hedberg744cf192011-11-08 20:40:14 +02002925 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002926 }
2927
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002928 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg03811012010-12-08 00:21:06 +02002929
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002930 err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev),
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002931 match.sk);
Johan Hedberg03811012010-12-08 00:21:06 +02002932
2933 if (match.sk)
2934 sock_put(match.sk);
2935
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002936 return err;
Johan Hedberg03811012010-12-08 00:21:06 +02002937}
2938
Johan Hedberg744cf192011-11-08 20:40:14 +02002939int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg03811012010-12-08 00:21:06 +02002940{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002941 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002942 bool changed = false;
2943 int err = 0;
Johan Hedberg03811012010-12-08 00:21:06 +02002944
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002945 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp, &match);
Johan Hedberg03811012010-12-08 00:21:06 +02002946
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002947 if (discoverable) {
2948 if (!test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
2949 changed = true;
2950 } else {
2951 if (test_and_clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
2952 changed = true;
2953 }
Johan Hedberg03811012010-12-08 00:21:06 +02002954
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002955 if (changed) {
2956 __le32 ev = cpu_to_le32(get_current_settings(hdev));
2957 err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01002958 match.sk);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002959 }
2960
Johan Hedberg03811012010-12-08 00:21:06 +02002961 if (match.sk)
2962 sock_put(match.sk);
2963
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002964 return err;
Johan Hedberg03811012010-12-08 00:21:06 +02002965}
2966
Johan Hedberg744cf192011-11-08 20:40:14 +02002967int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg03811012010-12-08 00:21:06 +02002968{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002969 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002970 bool changed = false;
2971 int err = 0;
Johan Hedberg03811012010-12-08 00:21:06 +02002972
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002973 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev, settings_rsp,
2974 &match);
Johan Hedberg03811012010-12-08 00:21:06 +02002975
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002976 if (connectable) {
2977 if (!test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags))
2978 changed = true;
2979 } else {
2980 if (test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags))
2981 changed = true;
2982 }
Johan Hedberg03811012010-12-08 00:21:06 +02002983
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002984 if (changed) {
2985 __le32 ev = cpu_to_le32(get_current_settings(hdev));
2986 err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev),
2987 match.sk);
2988 }
Johan Hedberg03811012010-12-08 00:21:06 +02002989
2990 if (match.sk)
2991 sock_put(match.sk);
2992
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002993 return err;
Johan Hedberg03811012010-12-08 00:21:06 +02002994}
2995
Johan Hedberg744cf192011-11-08 20:40:14 +02002996int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002997{
Johan Hedbergca69b792011-11-11 18:10:00 +02002998 u8 mgmt_err = mgmt_status(status);
2999
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003000 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02003001 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Johan Hedbergca69b792011-11-11 18:10:00 +02003002 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003003
3004 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02003005 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Johan Hedbergca69b792011-11-11 18:10:00 +02003006 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003007
3008 return 0;
3009}
3010
Johan Hedberg744cf192011-11-08 20:40:14 +02003011int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
3012 u8 persistent)
Johan Hedberg03811012010-12-08 00:21:06 +02003013{
Johan Hedberg86742e12011-11-07 23:13:38 +02003014 struct mgmt_ev_new_link_key ev;
Johan Hedberg03811012010-12-08 00:21:06 +02003015
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003016 memset(&ev, 0, sizeof(ev));
Johan Hedberg03811012010-12-08 00:21:06 +02003017
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003018 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02003019 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
3020 ev.key.addr.type = MGMT_ADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003021 ev.key.type = key->type;
3022 memcpy(ev.key.val, key->val, 16);
3023 ev.key.pin_len = key->pin_len;
Johan Hedberg03811012010-12-08 00:21:06 +02003024
Johan Hedberg744cf192011-11-08 20:40:14 +02003025 return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02003026}
Johan Hedbergf7520542011-01-20 12:34:39 +02003027
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003028int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
3029{
3030 struct mgmt_ev_new_long_term_key ev;
3031
3032 memset(&ev, 0, sizeof(ev));
3033
3034 ev.store_hint = persistent;
3035 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
3036 ev.key.addr.type = key->bdaddr_type;
3037 ev.key.authenticated = key->authenticated;
3038 ev.key.enc_size = key->enc_size;
3039 ev.key.ediv = key->ediv;
3040
3041 if (key->type == HCI_SMP_LTK)
3042 ev.key.master = 1;
3043
3044 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
3045 memcpy(ev.key.val, key->val, sizeof(key->val));
3046
3047 return mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev,
3048 &ev, sizeof(ev), NULL);
3049}
3050
Johan Hedbergafc747a2012-01-15 18:11:07 +02003051int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Johan Hedbergb644ba32012-01-17 21:48:47 +02003052 u8 addr_type, u8 *name, u8 name_len,
3053 u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02003054{
Johan Hedbergb644ba32012-01-17 21:48:47 +02003055 char buf[512];
3056 struct mgmt_ev_device_connected *ev = (void *) buf;
3057 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02003058
Johan Hedbergb644ba32012-01-17 21:48:47 +02003059 bacpy(&ev->addr.bdaddr, bdaddr);
3060 ev->addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02003061
Johan Hedbergb644ba32012-01-17 21:48:47 +02003062 if (name_len > 0)
3063 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
3064 name, name_len);
3065
3066 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
3067 eir_len = eir_append_data(&ev->eir[eir_len], eir_len,
3068 EIR_CLASS_OF_DEV, dev_class, 3);
3069
3070 put_unaligned_le16(eir_len, &ev->eir_len);
3071
3072 return mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
3073 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02003074}
3075
Johan Hedberg8962ee72011-01-20 12:40:27 +02003076static void disconnect_rsp(struct pending_cmd *cmd, void *data)
3077{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01003078 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003079 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02003080 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003081
Johan Hedberg88c3df12012-02-09 14:27:38 +02003082 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3083 rp.addr.type = cp->addr.type;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003084
Johan Hedbergaee9b212012-02-18 15:07:59 +02003085 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, 0, &rp,
3086 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003087
3088 *sk = cmd->sk;
3089 sock_hold(*sk);
3090
Johan Hedberga664b5b2011-02-19 12:06:02 -03003091 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003092}
3093
Johan Hedberg124f6e32012-02-09 13:50:12 +02003094static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02003095{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003096 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02003097 struct mgmt_cp_unpair_device *cp = cmd->param;
3098 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02003099
3100 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02003101 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3102 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02003103
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003104 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
3105
Johan Hedbergaee9b212012-02-18 15:07:59 +02003106 cmd_complete(cmd->sk, cmd->index, cmd->opcode, 0, &rp, sizeof(rp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02003107
3108 mgmt_pending_remove(cmd);
3109}
3110
Johan Hedbergafc747a2012-01-15 18:11:07 +02003111int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
3112 u8 link_type, u8 addr_type)
Johan Hedbergf7520542011-01-20 12:34:39 +02003113{
Johan Hedberg4c659c32011-11-07 23:13:39 +02003114 struct mgmt_addr_info ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003115 struct sock *sk = NULL;
3116 int err;
3117
Johan Hedberg744cf192011-11-08 20:40:14 +02003118 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02003119
Johan Hedbergf7520542011-01-20 12:34:39 +02003120 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02003121 ev.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02003122
Johan Hedbergafc747a2012-01-15 18:11:07 +02003123 err = mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev),
3124 sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003125
3126 if (sk)
3127 sock_put(sk);
3128
Johan Hedberg124f6e32012-02-09 13:50:12 +02003129 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003130 hdev);
Johan Hedberga8a1d192011-11-10 15:54:38 +02003131
Johan Hedberg8962ee72011-01-20 12:40:27 +02003132 return err;
3133}
3134
Johan Hedberg88c3df12012-02-09 14:27:38 +02003135int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
3136 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02003137{
Johan Hedberg88c3df12012-02-09 14:27:38 +02003138 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003139 struct pending_cmd *cmd;
3140 int err;
3141
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003142 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003143 if (!cmd)
3144 return -ENOENT;
3145
Johan Hedberg88c3df12012-02-09 14:27:38 +02003146 bacpy(&rp.addr.bdaddr, bdaddr);
3147 rp.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02003148
Johan Hedberg88c3df12012-02-09 14:27:38 +02003149 err = cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
Johan Hedbergaee9b212012-02-18 15:07:59 +02003150 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003151
Johan Hedberga664b5b2011-02-19 12:06:02 -03003152 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003153
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003154 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
3155 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003156 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02003157}
Johan Hedberg17d5c042011-01-22 06:09:08 +02003158
Johan Hedberg48264f02011-11-09 13:58:58 +02003159int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
3160 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02003161{
3162 struct mgmt_ev_connect_failed ev;
3163
Johan Hedberg4c659c32011-11-07 23:13:39 +02003164 bacpy(&ev.addr.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02003165 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003166 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003167
Johan Hedberg744cf192011-11-08 20:40:14 +02003168 return mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003169}
Johan Hedberg980e1a52011-01-22 06:10:07 +02003170
Johan Hedberg744cf192011-11-08 20:40:14 +02003171int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003172{
3173 struct mgmt_ev_pin_code_request ev;
3174
Johan Hedbergd8457692012-02-17 14:24:57 +02003175 bacpy(&ev.addr.bdaddr, bdaddr);
3176 ev.addr.type = MGMT_ADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02003177 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003178
Johan Hedberg744cf192011-11-08 20:40:14 +02003179 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01003180 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003181}
3182
Johan Hedberg744cf192011-11-08 20:40:14 +02003183int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3184 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003185{
3186 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003187 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003188 int err;
3189
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003190 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003191 if (!cmd)
3192 return -ENOENT;
3193
Johan Hedbergd8457692012-02-17 14:24:57 +02003194 bacpy(&rp.addr.bdaddr, bdaddr);
3195 rp.addr.type = MGMT_ADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003196
Johan Hedbergaee9b212012-02-18 15:07:59 +02003197 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
3198 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003199
Johan Hedberga664b5b2011-02-19 12:06:02 -03003200 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003201
3202 return err;
3203}
3204
Johan Hedberg744cf192011-11-08 20:40:14 +02003205int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3206 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003207{
3208 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003209 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003210 int err;
3211
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003212 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003213 if (!cmd)
3214 return -ENOENT;
3215
Johan Hedbergd8457692012-02-17 14:24:57 +02003216 bacpy(&rp.addr.bdaddr, bdaddr);
3217 rp.addr.type = MGMT_ADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003218
Johan Hedbergaee9b212012-02-18 15:07:59 +02003219 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
3220 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003221
Johan Hedberga664b5b2011-02-19 12:06:02 -03003222 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003223
3224 return err;
3225}
Johan Hedberga5c29682011-02-19 12:05:57 -03003226
Johan Hedberg744cf192011-11-08 20:40:14 +02003227int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003228 u8 link_type, u8 addr_type, __le32 value,
3229 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03003230{
3231 struct mgmt_ev_user_confirm_request ev;
3232
Johan Hedberg744cf192011-11-08 20:40:14 +02003233 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03003234
Johan Hedberg272d90d2012-02-09 15:26:12 +02003235 bacpy(&ev.addr.bdaddr, bdaddr);
3236 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07003237 ev.confirm_hint = confirm_hint;
Johan Hedberga5c29682011-02-19 12:05:57 -03003238 put_unaligned_le32(value, &ev.value);
3239
Johan Hedberg744cf192011-11-08 20:40:14 +02003240 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01003241 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03003242}
3243
Johan Hedberg272d90d2012-02-09 15:26:12 +02003244int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
3245 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08003246{
3247 struct mgmt_ev_user_passkey_request ev;
3248
3249 BT_DBG("%s", hdev->name);
3250
Johan Hedberg272d90d2012-02-09 15:26:12 +02003251 bacpy(&ev.addr.bdaddr, bdaddr);
3252 ev.addr.type = link_to_mgmt(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08003253
3254 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
3255 NULL);
3256}
3257
Brian Gix0df4c182011-11-16 13:53:13 -08003258static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003259 u8 link_type, u8 addr_type, u8 status,
3260 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03003261{
3262 struct pending_cmd *cmd;
3263 struct mgmt_rp_user_confirm_reply rp;
3264 int err;
3265
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003266 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03003267 if (!cmd)
3268 return -ENOENT;
3269
Johan Hedberg272d90d2012-02-09 15:26:12 +02003270 bacpy(&rp.addr.bdaddr, bdaddr);
3271 rp.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergaee9b212012-02-18 15:07:59 +02003272 err = cmd_complete(cmd->sk, hdev->id, opcode, mgmt_status(status),
3273 &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03003274
Johan Hedberga664b5b2011-02-19 12:06:02 -03003275 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03003276
3277 return err;
3278}
3279
Johan Hedberg744cf192011-11-08 20:40:14 +02003280int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003281 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003282{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003283 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3284 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003285}
3286
Johan Hedberg272d90d2012-02-09 15:26:12 +02003287int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3288 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003289{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003290 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3291 status, MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003292}
Johan Hedberg2a611692011-02-19 12:06:00 -03003293
Brian Gix604086b2011-11-23 08:28:33 -08003294int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003295 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003296{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003297 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3298 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003299}
3300
Johan Hedberg272d90d2012-02-09 15:26:12 +02003301int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3302 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003303{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003304 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3305 status, MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003306}
3307
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003308int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
3309 u8 addr_type, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03003310{
3311 struct mgmt_ev_auth_failed ev;
3312
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003313 bacpy(&ev.addr.bdaddr, bdaddr);
3314 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003315 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03003316
Johan Hedberg744cf192011-11-08 20:40:14 +02003317 return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03003318}
Johan Hedbergb312b1612011-03-16 14:29:37 +02003319
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003320int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
3321{
3322 struct cmd_lookup match = { NULL, hdev };
3323 __le32 ev;
3324 int err;
3325
3326 if (status) {
3327 u8 mgmt_err = mgmt_status(status);
3328 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
3329 cmd_status_rsp, &mgmt_err);
3330 return 0;
3331 }
3332
3333 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
3334 &match);
3335
3336 ev = cpu_to_le32(get_current_settings(hdev));
3337 err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), match.sk);
3338
3339 if (match.sk)
3340 sock_put(match.sk);
3341
3342 return err;
3343}
3344
Johan Hedbergcacaf522012-02-21 00:52:42 +02003345static int clear_eir(struct hci_dev *hdev)
3346{
3347 struct hci_cp_write_eir cp;
3348
3349 if (!(hdev->features[6] & LMP_EXT_INQ))
3350 return 0;
3351
3352 memset(&cp, 0, sizeof(cp));
3353
3354 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
3355}
3356
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003357int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 status)
3358{
3359 struct cmd_lookup match = { NULL, hdev };
3360 __le32 ev;
3361 int err;
3362
3363 if (status) {
3364 u8 mgmt_err = mgmt_status(status);
3365 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev,
3366 cmd_status_rsp, &mgmt_err);
3367 return 0;
3368 }
3369
3370 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
3371
3372 ev = cpu_to_le32(get_current_settings(hdev));
3373 err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), match.sk);
3374
Johan Hedbergcacaf522012-02-21 00:52:42 +02003375 if (match.sk) {
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003376 sock_put(match.sk);
3377
Johan Hedbergcacaf522012-02-21 00:52:42 +02003378 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3379 update_eir(hdev);
3380 else
3381 clear_eir(hdev);
3382 }
3383
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003384 return err;
3385}
3386
Johan Hedberg744cf192011-11-08 20:40:14 +02003387int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02003388{
3389 struct pending_cmd *cmd;
3390 struct mgmt_cp_set_local_name ev;
3391 int err;
3392
3393 memset(&ev, 0, sizeof(ev));
3394 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
3395
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003396 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003397 if (!cmd)
3398 goto send_event;
3399
3400 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02003401 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
Johan Hedbergca69b792011-11-11 18:10:00 +02003402 mgmt_status(status));
Johan Hedbergb312b1612011-03-16 14:29:37 +02003403 goto failed;
3404 }
3405
Johan Hedberg744cf192011-11-08 20:40:14 +02003406 update_eir(hdev);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03003407
Johan Hedbergaee9b212012-02-18 15:07:59 +02003408 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0, &ev,
Johan Hedbergb312b1612011-03-16 14:29:37 +02003409 sizeof(ev));
3410 if (err < 0)
3411 goto failed;
3412
3413send_event:
Johan Hedberg744cf192011-11-08 20:40:14 +02003414 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
Johan Hedbergb312b1612011-03-16 14:29:37 +02003415 cmd ? cmd->sk : NULL);
3416
3417failed:
3418 if (cmd)
3419 mgmt_pending_remove(cmd);
3420 return err;
3421}
Szymon Jancc35938b2011-03-22 13:12:21 +01003422
Johan Hedberg744cf192011-11-08 20:40:14 +02003423int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
3424 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01003425{
3426 struct pending_cmd *cmd;
3427 int err;
3428
Johan Hedberg744cf192011-11-08 20:40:14 +02003429 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01003430
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003431 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003432 if (!cmd)
3433 return -ENOENT;
3434
3435 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02003436 err = cmd_status(cmd->sk, hdev->id,
Johan Hedbergca69b792011-11-11 18:10:00 +02003437 MGMT_OP_READ_LOCAL_OOB_DATA,
3438 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01003439 } else {
3440 struct mgmt_rp_read_local_oob_data rp;
3441
3442 memcpy(rp.hash, hash, sizeof(rp.hash));
3443 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
3444
Johan Hedberg744cf192011-11-08 20:40:14 +02003445 err = cmd_complete(cmd->sk, hdev->id,
3446 MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergaee9b212012-02-18 15:07:59 +02003447 0, &rp, sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01003448 }
3449
3450 mgmt_pending_remove(cmd);
3451
3452 return err;
3453}
Johan Hedberge17acd42011-03-30 23:57:16 +03003454
Johan Hedberg48264f02011-11-09 13:58:58 +02003455int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Johan Hedberg561aafb2012-01-04 13:31:59 +02003456 u8 addr_type, u8 *dev_class, s8 rssi,
Johan Hedberge319d2e2012-01-15 19:51:59 +02003457 u8 cfm_name, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03003458{
Johan Hedberge319d2e2012-01-15 19:51:59 +02003459 char buf[512];
3460 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02003461 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03003462
Johan Hedberg1dc06092012-01-15 21:01:23 +02003463 /* Leave 5 bytes for a potential CoD field */
3464 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Andre Guedes7d262f82012-01-10 18:20:49 -03003465 return -EINVAL;
3466
Johan Hedberg1dc06092012-01-15 21:01:23 +02003467 memset(buf, 0, sizeof(buf));
3468
Johan Hedberge319d2e2012-01-15 19:51:59 +02003469 bacpy(&ev->addr.bdaddr, bdaddr);
3470 ev->addr.type = link_to_mgmt(link_type, addr_type);
3471 ev->rssi = rssi;
3472 ev->confirm_name = cfm_name;
Johan Hedberge17acd42011-03-30 23:57:16 +03003473
Johan Hedberg1dc06092012-01-15 21:01:23 +02003474 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02003475 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03003476
Johan Hedberg1dc06092012-01-15 21:01:23 +02003477 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
3478 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
3479 dev_class, 3);
3480
3481 put_unaligned_le16(eir_len, &ev->eir_len);
3482
3483 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03003484
Johan Hedberge319d2e2012-01-15 19:51:59 +02003485 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03003486}
Johan Hedberga88a9652011-03-30 13:18:12 +03003487
Johan Hedbergb644ba32012-01-17 21:48:47 +02003488int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
3489 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03003490{
Johan Hedbergb644ba32012-01-17 21:48:47 +02003491 struct mgmt_ev_device_found *ev;
3492 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
3493 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03003494
Johan Hedbergb644ba32012-01-17 21:48:47 +02003495 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03003496
Johan Hedbergb644ba32012-01-17 21:48:47 +02003497 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03003498
Johan Hedbergb644ba32012-01-17 21:48:47 +02003499 bacpy(&ev->addr.bdaddr, bdaddr);
3500 ev->addr.type = link_to_mgmt(link_type, addr_type);
3501 ev->rssi = rssi;
3502
3503 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
3504 name_len);
3505
3506 put_unaligned_le16(eir_len, &ev->eir_len);
3507
Johan Hedberg053c7e02012-02-04 00:06:00 +02003508 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev,
3509 sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03003510}
Johan Hedberg314b2382011-04-27 10:29:57 -04003511
Andre Guedes7a135102011-11-09 17:14:25 -03003512int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
Johan Hedberg164a6e72011-11-01 17:06:44 +02003513{
3514 struct pending_cmd *cmd;
Johan Hedbergf808e162012-02-19 12:52:07 +02003515 u8 type;
Johan Hedberg164a6e72011-11-01 17:06:44 +02003516 int err;
3517
Andre Guedes203159d2012-02-13 15:41:01 -03003518 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3519
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003520 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003521 if (!cmd)
3522 return -ENOENT;
3523
Johan Hedbergf808e162012-02-19 12:52:07 +02003524 type = hdev->discovery.type;
3525
3526 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
3527 &type, sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02003528 mgmt_pending_remove(cmd);
3529
3530 return err;
3531}
3532
Andre Guedese6d465c2011-11-09 17:14:26 -03003533int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
3534{
3535 struct pending_cmd *cmd;
3536 int err;
3537
3538 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
3539 if (!cmd)
3540 return -ENOENT;
3541
Johan Hedbergd9306502012-02-20 23:25:18 +02003542 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
3543 &hdev->discovery.type,
3544 sizeof(hdev->discovery.type));
Johan Hedberg03811012010-12-08 00:21:06 +02003545 mgmt_pending_remove(cmd);
3546
3547 return err;
3548}
Johan Hedberg314b2382011-04-27 10:29:57 -04003549
Johan Hedberg744cf192011-11-08 20:40:14 +02003550int mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04003551{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02003552 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02003553 struct pending_cmd *cmd;
3554
Andre Guedes343fb142011-11-22 17:14:19 -03003555 BT_DBG("%s discovering %u", hdev->name, discovering);
3556
Johan Hedberg164a6e72011-11-01 17:06:44 +02003557 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003558 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003559 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003560 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003561
3562 if (cmd != NULL) {
Johan Hedbergf808e162012-02-19 12:52:07 +02003563 u8 type = hdev->discovery.type;
3564
Johan Hedbergd9306502012-02-20 23:25:18 +02003565 cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0,
Johan Hedbergf808e162012-02-19 12:52:07 +02003566 &type, sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02003567 mgmt_pending_remove(cmd);
3568 }
3569
Johan Hedbergf963e8e2012-02-20 23:30:44 +02003570 memset(&ev, 0, sizeof(ev));
3571 ev.type = hdev->discovery.type;
3572 ev.discovering = discovering;
3573
3574 return mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04003575}
Antti Julku5e762442011-08-25 16:48:02 +03003576
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003577int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003578{
3579 struct pending_cmd *cmd;
3580 struct mgmt_ev_device_blocked ev;
3581
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003582 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003583
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003584 bacpy(&ev.addr.bdaddr, bdaddr);
3585 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003586
Johan Hedberg744cf192011-11-08 20:40:14 +02003587 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
3588 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003589}
3590
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003591int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003592{
3593 struct pending_cmd *cmd;
3594 struct mgmt_ev_device_unblocked ev;
3595
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003596 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003597
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003598 bacpy(&ev.addr.bdaddr, bdaddr);
3599 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003600
Johan Hedberg744cf192011-11-08 20:40:14 +02003601 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
3602 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003603}
Marcel Holtmannd7b7e792012-02-20 21:47:49 +01003604
3605module_param(enable_hs, bool, 0644);
3606MODULE_PARM_DESC(enable_hs, "Enable High Speed support");
3607
3608module_param(enable_le, bool, 0644);
3609MODULE_PARM_DESC(enable_le, "Enable Low Energy support");