blob: 439ec786ff8c44f6dbeceffd22499c950bdf7011 [file] [log] [blame]
Johan Hedberg03811012010-12-08 00:21:06 +02001/*
2 BlueZ - Bluetooth protocol stack for Linux
Johan Hedbergea585ab2012-02-17 14:50:39 +02003
Johan Hedberg03811012010-12-08 00:21:06 +02004 Copyright (C) 2010 Nokia Corporation
Johan Hedbergea585ab2012-02-17 14:50:39 +02005 Copyright (C) 2011-2012 Intel Corporation
Johan Hedberg03811012010-12-08 00:21:06 +02006
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License version 2 as
9 published by the Free Software Foundation;
10
11 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
12 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
13 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
14 IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
15 CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
16 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19
20 ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
21 COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
22 SOFTWARE IS DISCLAIMED.
23*/
24
25/* Bluetooth HCI Management interface */
26
Johan Hedbergca69b792011-11-11 18:10:00 +020027#include <linux/kernel.h>
Szymon Janc72359752011-02-17 14:16:32 +010028#include <linux/uaccess.h>
Paul Gortmaker3a9a2312011-05-27 09:12:25 -040029#include <linux/module.h>
Johan Hedberg03811012010-12-08 00:21:06 +020030#include <asm/unaligned.h>
31
32#include <net/bluetooth/bluetooth.h>
33#include <net/bluetooth/hci_core.h>
34#include <net/bluetooth/mgmt.h>
Brian Gix5fe57d92011-12-21 16:12:13 -080035#include <net/bluetooth/smp.h>
Johan Hedberg03811012010-12-08 00:21:06 +020036
Marcel Holtmannd7b7e792012-02-20 21:47:49 +010037bool enable_hs;
38bool enable_le;
39
Johan Hedberg2da9c552012-02-17 14:39:28 +020040#define MGMT_VERSION 1
41#define MGMT_REVISION 0
Johan Hedberg02d98122010-12-13 21:07:04 +020042
Johan Hedberge70bb2e2012-02-13 16:59:33 +020043static const u16 mgmt_commands[] = {
44 MGMT_OP_READ_INDEX_LIST,
45 MGMT_OP_READ_INFO,
46 MGMT_OP_SET_POWERED,
47 MGMT_OP_SET_DISCOVERABLE,
48 MGMT_OP_SET_CONNECTABLE,
49 MGMT_OP_SET_FAST_CONNECTABLE,
50 MGMT_OP_SET_PAIRABLE,
51 MGMT_OP_SET_LINK_SECURITY,
52 MGMT_OP_SET_SSP,
53 MGMT_OP_SET_HS,
54 MGMT_OP_SET_LE,
55 MGMT_OP_SET_DEV_CLASS,
56 MGMT_OP_SET_LOCAL_NAME,
57 MGMT_OP_ADD_UUID,
58 MGMT_OP_REMOVE_UUID,
59 MGMT_OP_LOAD_LINK_KEYS,
60 MGMT_OP_LOAD_LONG_TERM_KEYS,
61 MGMT_OP_DISCONNECT,
62 MGMT_OP_GET_CONNECTIONS,
63 MGMT_OP_PIN_CODE_REPLY,
64 MGMT_OP_PIN_CODE_NEG_REPLY,
65 MGMT_OP_SET_IO_CAPABILITY,
66 MGMT_OP_PAIR_DEVICE,
67 MGMT_OP_CANCEL_PAIR_DEVICE,
68 MGMT_OP_UNPAIR_DEVICE,
69 MGMT_OP_USER_CONFIRM_REPLY,
70 MGMT_OP_USER_CONFIRM_NEG_REPLY,
71 MGMT_OP_USER_PASSKEY_REPLY,
72 MGMT_OP_USER_PASSKEY_NEG_REPLY,
73 MGMT_OP_READ_LOCAL_OOB_DATA,
74 MGMT_OP_ADD_REMOTE_OOB_DATA,
75 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
76 MGMT_OP_START_DISCOVERY,
77 MGMT_OP_STOP_DISCOVERY,
78 MGMT_OP_CONFIRM_NAME,
79 MGMT_OP_BLOCK_DEVICE,
80 MGMT_OP_UNBLOCK_DEVICE,
81};
82
83static const u16 mgmt_events[] = {
84 MGMT_EV_CONTROLLER_ERROR,
85 MGMT_EV_INDEX_ADDED,
86 MGMT_EV_INDEX_REMOVED,
87 MGMT_EV_NEW_SETTINGS,
88 MGMT_EV_CLASS_OF_DEV_CHANGED,
89 MGMT_EV_LOCAL_NAME_CHANGED,
90 MGMT_EV_NEW_LINK_KEY,
91 MGMT_EV_NEW_LONG_TERM_KEY,
92 MGMT_EV_DEVICE_CONNECTED,
93 MGMT_EV_DEVICE_DISCONNECTED,
94 MGMT_EV_CONNECT_FAILED,
95 MGMT_EV_PIN_CODE_REQUEST,
96 MGMT_EV_USER_CONFIRM_REQUEST,
97 MGMT_EV_USER_PASSKEY_REQUEST,
98 MGMT_EV_AUTH_FAILED,
99 MGMT_EV_DEVICE_FOUND,
100 MGMT_EV_DISCOVERING,
101 MGMT_EV_DEVICE_BLOCKED,
102 MGMT_EV_DEVICE_UNBLOCKED,
103 MGMT_EV_DEVICE_UNPAIRED,
104};
105
Andre Guedes3fd24152012-02-03 17:48:01 -0300106/*
107 * These LE scan and inquiry parameters were chosen according to LE General
108 * Discovery Procedure specification.
109 */
110#define LE_SCAN_TYPE 0x01
111#define LE_SCAN_WIN 0x12
112#define LE_SCAN_INT 0x12
113#define LE_SCAN_TIMEOUT_LE_ONLY 10240 /* TGAP(gen_disc_scan_min) */
Andre Guedes5e0452c2012-02-17 20:39:38 -0300114#define LE_SCAN_TIMEOUT_BREDR_LE 5120 /* TGAP(100)/2 */
Andre Guedes3fd24152012-02-03 17:48:01 -0300115
Andre Guedese8777522012-02-03 17:48:02 -0300116#define INQUIRY_LEN_BREDR 0x08 /* TGAP(100) */
Andre Guedes5e0452c2012-02-17 20:39:38 -0300117#define INQUIRY_LEN_BREDR_LE 0x04 /* TGAP(100)/2 */
Andre Guedes2519a1f2011-11-07 11:45:24 -0300118
Johan Hedberg7d785252011-12-15 00:47:39 +0200119#define SERVICE_CACHE_TIMEOUT (5 * 1000)
120
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200121#define hdev_is_powered(hdev) (test_bit(HCI_UP, &hdev->flags) && \
122 !test_bit(HCI_AUTO_OFF, &hdev->dev_flags))
123
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200124struct pending_cmd {
125 struct list_head list;
Johan Hedbergfc2f4b12011-11-09 13:58:56 +0200126 u16 opcode;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200127 int index;
Szymon Jancc68fb7f2011-03-22 13:12:19 +0100128 void *param;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200129 struct sock *sk;
Johan Hedberge9a416b2011-02-19 12:05:56 -0300130 void *user_data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200131};
132
Johan Hedbergca69b792011-11-11 18:10:00 +0200133/* HCI to MGMT error code conversion table */
134static u8 mgmt_status_table[] = {
135 MGMT_STATUS_SUCCESS,
136 MGMT_STATUS_UNKNOWN_COMMAND, /* Unknown Command */
137 MGMT_STATUS_NOT_CONNECTED, /* No Connection */
138 MGMT_STATUS_FAILED, /* Hardware Failure */
139 MGMT_STATUS_CONNECT_FAILED, /* Page Timeout */
140 MGMT_STATUS_AUTH_FAILED, /* Authentication Failed */
141 MGMT_STATUS_NOT_PAIRED, /* PIN or Key Missing */
142 MGMT_STATUS_NO_RESOURCES, /* Memory Full */
143 MGMT_STATUS_TIMEOUT, /* Connection Timeout */
144 MGMT_STATUS_NO_RESOURCES, /* Max Number of Connections */
145 MGMT_STATUS_NO_RESOURCES, /* Max Number of SCO Connections */
146 MGMT_STATUS_ALREADY_CONNECTED, /* ACL Connection Exists */
147 MGMT_STATUS_BUSY, /* Command Disallowed */
148 MGMT_STATUS_NO_RESOURCES, /* Rejected Limited Resources */
149 MGMT_STATUS_REJECTED, /* Rejected Security */
150 MGMT_STATUS_REJECTED, /* Rejected Personal */
151 MGMT_STATUS_TIMEOUT, /* Host Timeout */
152 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Feature */
153 MGMT_STATUS_INVALID_PARAMS, /* Invalid Parameters */
154 MGMT_STATUS_DISCONNECTED, /* OE User Ended Connection */
155 MGMT_STATUS_NO_RESOURCES, /* OE Low Resources */
156 MGMT_STATUS_DISCONNECTED, /* OE Power Off */
157 MGMT_STATUS_DISCONNECTED, /* Connection Terminated */
158 MGMT_STATUS_BUSY, /* Repeated Attempts */
159 MGMT_STATUS_REJECTED, /* Pairing Not Allowed */
160 MGMT_STATUS_FAILED, /* Unknown LMP PDU */
161 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Remote Feature */
162 MGMT_STATUS_REJECTED, /* SCO Offset Rejected */
163 MGMT_STATUS_REJECTED, /* SCO Interval Rejected */
164 MGMT_STATUS_REJECTED, /* Air Mode Rejected */
165 MGMT_STATUS_INVALID_PARAMS, /* Invalid LMP Parameters */
166 MGMT_STATUS_FAILED, /* Unspecified Error */
167 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported LMP Parameter Value */
168 MGMT_STATUS_FAILED, /* Role Change Not Allowed */
169 MGMT_STATUS_TIMEOUT, /* LMP Response Timeout */
170 MGMT_STATUS_FAILED, /* LMP Error Transaction Collision */
171 MGMT_STATUS_FAILED, /* LMP PDU Not Allowed */
172 MGMT_STATUS_REJECTED, /* Encryption Mode Not Accepted */
173 MGMT_STATUS_FAILED, /* Unit Link Key Used */
174 MGMT_STATUS_NOT_SUPPORTED, /* QoS Not Supported */
175 MGMT_STATUS_TIMEOUT, /* Instant Passed */
176 MGMT_STATUS_NOT_SUPPORTED, /* Pairing Not Supported */
177 MGMT_STATUS_FAILED, /* Transaction Collision */
178 MGMT_STATUS_INVALID_PARAMS, /* Unacceptable Parameter */
179 MGMT_STATUS_REJECTED, /* QoS Rejected */
180 MGMT_STATUS_NOT_SUPPORTED, /* Classification Not Supported */
181 MGMT_STATUS_REJECTED, /* Insufficient Security */
182 MGMT_STATUS_INVALID_PARAMS, /* Parameter Out Of Range */
183 MGMT_STATUS_BUSY, /* Role Switch Pending */
184 MGMT_STATUS_FAILED, /* Slot Violation */
185 MGMT_STATUS_FAILED, /* Role Switch Failed */
186 MGMT_STATUS_INVALID_PARAMS, /* EIR Too Large */
187 MGMT_STATUS_NOT_SUPPORTED, /* Simple Pairing Not Supported */
188 MGMT_STATUS_BUSY, /* Host Busy Pairing */
189 MGMT_STATUS_REJECTED, /* Rejected, No Suitable Channel */
190 MGMT_STATUS_BUSY, /* Controller Busy */
191 MGMT_STATUS_INVALID_PARAMS, /* Unsuitable Connection Interval */
192 MGMT_STATUS_TIMEOUT, /* Directed Advertising Timeout */
193 MGMT_STATUS_AUTH_FAILED, /* Terminated Due to MIC Failure */
194 MGMT_STATUS_CONNECT_FAILED, /* Connection Establishment Failed */
195 MGMT_STATUS_CONNECT_FAILED, /* MAC Connection Failed */
196};
197
198static u8 mgmt_status(u8 hci_status)
199{
200 if (hci_status < ARRAY_SIZE(mgmt_status_table))
201 return mgmt_status_table[hci_status];
202
203 return MGMT_STATUS_FAILED;
204}
205
Szymon Janc4e51eae2011-02-25 19:05:48 +0100206static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200207{
208 struct sk_buff *skb;
209 struct mgmt_hdr *hdr;
210 struct mgmt_ev_cmd_status *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300211 int err;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200212
Szymon Janc34eb5252011-02-28 14:10:08 +0100213 BT_DBG("sock %p, index %u, cmd %u, status %u", sk, index, cmd, status);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200214
215 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_ATOMIC);
216 if (!skb)
217 return -ENOMEM;
218
219 hdr = (void *) skb_put(skb, sizeof(*hdr));
220
221 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_STATUS);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100222 hdr->index = cpu_to_le16(index);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200223 hdr->len = cpu_to_le16(sizeof(*ev));
224
225 ev = (void *) skb_put(skb, sizeof(*ev));
226 ev->status = status;
227 put_unaligned_le16(cmd, &ev->opcode);
228
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300229 err = sock_queue_rcv_skb(sk, skb);
230 if (err < 0)
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200231 kfree_skb(skb);
232
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300233 return err;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200234}
235
Johan Hedbergaee9b212012-02-18 15:07:59 +0200236static int cmd_complete(struct sock *sk, u16 index, u16 cmd, u8 status,
237 void *rp, size_t rp_len)
Johan Hedberg02d98122010-12-13 21:07:04 +0200238{
239 struct sk_buff *skb;
240 struct mgmt_hdr *hdr;
241 struct mgmt_ev_cmd_complete *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300242 int err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200243
244 BT_DBG("sock %p", sk);
245
Johan Hedberga38528f2011-01-22 06:46:43 +0200246 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + rp_len, GFP_ATOMIC);
Johan Hedberg02d98122010-12-13 21:07:04 +0200247 if (!skb)
248 return -ENOMEM;
249
250 hdr = (void *) skb_put(skb, sizeof(*hdr));
Johan Hedberga38528f2011-01-22 06:46:43 +0200251
Johan Hedberg02d98122010-12-13 21:07:04 +0200252 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100253 hdr->index = cpu_to_le16(index);
Johan Hedberga38528f2011-01-22 06:46:43 +0200254 hdr->len = cpu_to_le16(sizeof(*ev) + rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200255
Johan Hedberga38528f2011-01-22 06:46:43 +0200256 ev = (void *) skb_put(skb, sizeof(*ev) + rp_len);
257 put_unaligned_le16(cmd, &ev->opcode);
Johan Hedbergaee9b212012-02-18 15:07:59 +0200258 ev->status = status;
Szymon Janc8020c162011-02-28 14:09:50 +0100259
260 if (rp)
261 memcpy(ev->data, rp, rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200262
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300263 err = sock_queue_rcv_skb(sk, skb);
264 if (err < 0)
Johan Hedberg02d98122010-12-13 21:07:04 +0200265 kfree_skb(skb);
266
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300267 return err;;
Johan Hedberg02d98122010-12-13 21:07:04 +0200268}
269
Johan Hedberga38528f2011-01-22 06:46:43 +0200270static int read_version(struct sock *sk)
271{
272 struct mgmt_rp_read_version rp;
273
274 BT_DBG("sock %p", sk);
275
276 rp.version = MGMT_VERSION;
277 put_unaligned_le16(MGMT_REVISION, &rp.revision);
278
Johan Hedbergaee9b212012-02-18 15:07:59 +0200279 return cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, 0, &rp,
Szymon Janc4e51eae2011-02-25 19:05:48 +0100280 sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200281}
282
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200283static int read_commands(struct sock *sk)
284{
285 struct mgmt_rp_read_commands *rp;
286 u16 num_commands = ARRAY_SIZE(mgmt_commands);
287 u16 num_events = ARRAY_SIZE(mgmt_events);
288 u16 *opcode;
289 size_t rp_size;
290 int i, err;
291
292 BT_DBG("sock %p", sk);
293
294 rp_size = sizeof(*rp) + ((num_commands + num_events) * sizeof(u16));
295
296 rp = kmalloc(rp_size, GFP_KERNEL);
297 if (!rp)
298 return -ENOMEM;
299
300 put_unaligned_le16(num_commands, &rp->num_commands);
301 put_unaligned_le16(num_events, &rp->num_events);
302
303 for (i = 0, opcode = rp->opcodes; i < num_commands; i++, opcode++)
304 put_unaligned_le16(mgmt_commands[i], opcode);
305
306 for (i = 0; i < num_events; i++, opcode++)
307 put_unaligned_le16(mgmt_events[i], opcode);
308
Johan Hedbergaee9b212012-02-18 15:07:59 +0200309 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_COMMANDS, 0, rp,
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200310 rp_size);
311 kfree(rp);
312
313 return err;
314}
315
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200316static int read_index_list(struct sock *sk)
317{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200318 struct mgmt_rp_read_index_list *rp;
319 struct list_head *p;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200320 struct hci_dev *d;
Johan Hedberga38528f2011-01-22 06:46:43 +0200321 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200322 u16 count;
Johan Hedberga38528f2011-01-22 06:46:43 +0200323 int i, err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200324
325 BT_DBG("sock %p", sk);
326
327 read_lock(&hci_dev_list_lock);
328
329 count = 0;
330 list_for_each(p, &hci_dev_list) {
331 count++;
332 }
333
Johan Hedberga38528f2011-01-22 06:46:43 +0200334 rp_len = sizeof(*rp) + (2 * count);
335 rp = kmalloc(rp_len, GFP_ATOMIC);
336 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100337 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200338 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100339 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200340
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200341 put_unaligned_le16(count, &rp->num_controllers);
342
343 i = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200344 list_for_each_entry(d, &hci_dev_list, list) {
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200345 if (test_bit(HCI_SETUP, &d->dev_flags))
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200346 continue;
347
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200348 put_unaligned_le16(d->id, &rp->index[i++]);
349 BT_DBG("Added hci%u", d->id);
350 }
351
352 read_unlock(&hci_dev_list_lock);
353
Johan Hedbergaee9b212012-02-18 15:07:59 +0200354 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST, 0, rp,
Szymon Janc4e51eae2011-02-25 19:05:48 +0100355 rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200356
Johan Hedberga38528f2011-01-22 06:46:43 +0200357 kfree(rp);
358
359 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200360}
361
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200362static u32 get_supported_settings(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +0200363{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200364 u32 settings = 0;
Johan Hedberg03811012010-12-08 00:21:06 +0200365
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200366 settings |= MGMT_SETTING_POWERED;
367 settings |= MGMT_SETTING_CONNECTABLE;
368 settings |= MGMT_SETTING_FAST_CONNECTABLE;
369 settings |= MGMT_SETTING_DISCOVERABLE;
370 settings |= MGMT_SETTING_PAIRABLE;
Johan Hedberg03811012010-12-08 00:21:06 +0200371
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200372 if (hdev->features[6] & LMP_SIMPLE_PAIR)
373 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200374
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200375 if (!(hdev->features[4] & LMP_NO_BREDR)) {
376 settings |= MGMT_SETTING_BREDR;
377 settings |= MGMT_SETTING_LINK_SECURITY;
378 }
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200379
Marcel Holtmannd7b7e792012-02-20 21:47:49 +0100380 if (enable_hs)
381 settings |= MGMT_SETTING_HS;
382
383 if (enable_le) {
384 if (hdev->features[4] & LMP_LE)
385 settings |= MGMT_SETTING_LE;
386 }
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200387
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200388 return settings;
389}
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200390
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200391static u32 get_current_settings(struct hci_dev *hdev)
392{
393 u32 settings = 0;
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200394
Johan Hedbergf1f0eb02012-02-21 17:15:41 +0200395 if (hdev_is_powered(hdev))
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100396 settings |= MGMT_SETTING_POWERED;
397
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200398 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200399 settings |= MGMT_SETTING_CONNECTABLE;
400
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200401 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200402 settings |= MGMT_SETTING_DISCOVERABLE;
403
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200404 if (test_bit(HCI_PAIRABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200405 settings |= MGMT_SETTING_PAIRABLE;
406
407 if (!(hdev->features[4] & LMP_NO_BREDR))
408 settings |= MGMT_SETTING_BREDR;
409
Andre Guedes59e29402011-12-30 10:34:03 -0300410 if (hdev->host_features[0] & LMP_HOST_LE)
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200411 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200412
413 if (test_bit(HCI_AUTH, &hdev->flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200414 settings |= MGMT_SETTING_LINK_SECURITY;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200415
Johan Hedberg84bde9d2012-01-25 14:21:06 +0200416 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200417 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200418
Johan Hedberg6d80dfd2012-02-20 23:50:38 +0200419 if (test_bit(HCI_HS_ENABLED, &hdev->dev_flags))
420 settings |= MGMT_SETTING_HS;
421
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200422 return settings;
Johan Hedbergc542a062011-01-26 13:11:03 +0200423}
424
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300425#define PNP_INFO_SVCLASS_ID 0x1200
426
427static u8 bluetooth_base_uuid[] = {
428 0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80,
429 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
430};
431
432static u16 get_uuid16(u8 *uuid128)
433{
434 u32 val;
435 int i;
436
437 for (i = 0; i < 12; i++) {
438 if (bluetooth_base_uuid[i] != uuid128[i])
439 return 0;
440 }
441
442 memcpy(&val, &uuid128[12], 4);
443
444 val = le32_to_cpu(val);
445 if (val > 0xffff)
446 return 0;
447
448 return (u16) val;
449}
450
451static void create_eir(struct hci_dev *hdev, u8 *data)
452{
453 u8 *ptr = data;
454 u16 eir_len = 0;
455 u16 uuid16_list[HCI_MAX_EIR_LENGTH / sizeof(u16)];
456 int i, truncated = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200457 struct bt_uuid *uuid;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300458 size_t name_len;
459
460 name_len = strlen(hdev->dev_name);
461
462 if (name_len > 0) {
463 /* EIR Data type */
464 if (name_len > 48) {
465 name_len = 48;
466 ptr[1] = EIR_NAME_SHORT;
467 } else
468 ptr[1] = EIR_NAME_COMPLETE;
469
470 /* EIR Data length */
471 ptr[0] = name_len + 1;
472
473 memcpy(ptr + 2, hdev->dev_name, name_len);
474
475 eir_len += (name_len + 2);
476 ptr += (name_len + 2);
477 }
478
479 memset(uuid16_list, 0, sizeof(uuid16_list));
480
481 /* Group all UUID16 types */
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200482 list_for_each_entry(uuid, &hdev->uuids, list) {
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300483 u16 uuid16;
484
485 uuid16 = get_uuid16(uuid->uuid);
486 if (uuid16 == 0)
487 return;
488
489 if (uuid16 < 0x1100)
490 continue;
491
492 if (uuid16 == PNP_INFO_SVCLASS_ID)
493 continue;
494
495 /* Stop if not enough space to put next UUID */
496 if (eir_len + 2 + sizeof(u16) > HCI_MAX_EIR_LENGTH) {
497 truncated = 1;
498 break;
499 }
500
501 /* Check for duplicates */
502 for (i = 0; uuid16_list[i] != 0; i++)
503 if (uuid16_list[i] == uuid16)
504 break;
505
506 if (uuid16_list[i] == 0) {
507 uuid16_list[i] = uuid16;
508 eir_len += sizeof(u16);
509 }
510 }
511
512 if (uuid16_list[0] != 0) {
513 u8 *length = ptr;
514
515 /* EIR Data type */
516 ptr[1] = truncated ? EIR_UUID16_SOME : EIR_UUID16_ALL;
517
518 ptr += 2;
519 eir_len += 2;
520
521 for (i = 0; uuid16_list[i] != 0; i++) {
522 *ptr++ = (uuid16_list[i] & 0x00ff);
523 *ptr++ = (uuid16_list[i] & 0xff00) >> 8;
524 }
525
526 /* EIR Data length */
527 *length = (i * sizeof(u16)) + 1;
528 }
529}
530
531static int update_eir(struct hci_dev *hdev)
532{
533 struct hci_cp_write_eir cp;
534
535 if (!(hdev->features[6] & LMP_EXT_INQ))
536 return 0;
537
Johan Hedberg84bde9d2012-01-25 14:21:06 +0200538 if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300539 return 0;
540
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200541 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300542 return 0;
543
544 memset(&cp, 0, sizeof(cp));
545
546 create_eir(hdev, cp.data);
547
548 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
549 return 0;
550
551 memcpy(hdev->eir, cp.data, sizeof(cp.data));
552
553 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
554}
555
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200556static u8 get_service_classes(struct hci_dev *hdev)
557{
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300558 struct bt_uuid *uuid;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200559 u8 val = 0;
560
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300561 list_for_each_entry(uuid, &hdev->uuids, list)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200562 val |= uuid->svc_hint;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200563
564 return val;
565}
566
567static int update_class(struct hci_dev *hdev)
568{
569 u8 cod[3];
570
571 BT_DBG("%s", hdev->name);
572
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200573 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200574 return 0;
575
576 cod[0] = hdev->minor_class;
577 cod[1] = hdev->major_class;
578 cod[2] = get_service_classes(hdev);
579
580 if (memcmp(cod, hdev->dev_class, 3) == 0)
581 return 0;
582
583 return hci_send_cmd(hdev, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
584}
585
Johan Hedberg7d785252011-12-15 00:47:39 +0200586static void service_cache_off(struct work_struct *work)
587{
588 struct hci_dev *hdev = container_of(work, struct hci_dev,
589 service_cache.work);
590
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200591 if (!test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200592 return;
593
594 hci_dev_lock(hdev);
595
596 update_eir(hdev);
597 update_class(hdev);
598
599 hci_dev_unlock(hdev);
600}
601
602static void mgmt_init_hdev(struct hci_dev *hdev)
603{
Johan Hedberg0cbf4ed2012-02-21 17:25:22 +0200604 if (!test_and_set_bit(HCI_MGMT, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +0200605 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
606
Johan Hedberg0cbf4ed2012-02-21 17:25:22 +0200607 /* Non-mgmt controlled devices get this bit set
608 * implicitly so that pairing works for them, however
609 * for mgmt we require user-space to explicitly enable
610 * it
611 */
612 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
613 }
614
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200615 if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200616 schedule_delayed_work(&hdev->service_cache,
617 msecs_to_jiffies(SERVICE_CACHE_TIMEOUT));
618}
619
Johan Hedberg03811012010-12-08 00:21:06 +0200620static int read_controller_info(struct sock *sk, u16 index)
621{
622 struct mgmt_rp_read_info rp;
623 struct hci_dev *hdev;
624
625 BT_DBG("sock %p hci%u", sk, index);
626
627 hdev = hci_dev_get(index);
628 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200629 return cmd_status(sk, index, MGMT_OP_READ_INFO,
630 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200631
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300632 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200633
Johan Hedberg7d785252011-12-15 00:47:39 +0200634 if (test_and_clear_bit(HCI_PI_MGMT_INIT, &hci_pi(sk)->flags))
635 mgmt_init_hdev(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200636
637 memset(&rp, 0, sizeof(rp));
638
Johan Hedberg03811012010-12-08 00:21:06 +0200639 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200640
641 rp.version = hdev->hci_ver;
642
Johan Hedberg03811012010-12-08 00:21:06 +0200643 put_unaligned_le16(hdev->manufacturer, &rp.manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200644
645 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
646 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
647
648 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedberg03811012010-12-08 00:21:06 +0200649
650 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
651
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300652 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200653 hci_dev_put(hdev);
654
Johan Hedbergaee9b212012-02-18 15:07:59 +0200655 return cmd_complete(sk, index, MGMT_OP_READ_INFO, 0, &rp, sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +0200656}
657
658static void mgmt_pending_free(struct pending_cmd *cmd)
659{
660 sock_put(cmd->sk);
661 kfree(cmd->param);
662 kfree(cmd);
663}
664
665static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
666 struct hci_dev *hdev,
667 void *data, u16 len)
668{
669 struct pending_cmd *cmd;
670
671 cmd = kmalloc(sizeof(*cmd), GFP_ATOMIC);
672 if (!cmd)
673 return NULL;
674
675 cmd->opcode = opcode;
676 cmd->index = hdev->id;
677
678 cmd->param = kmalloc(len, GFP_ATOMIC);
679 if (!cmd->param) {
680 kfree(cmd);
681 return NULL;
682 }
683
684 if (data)
685 memcpy(cmd->param, data, len);
686
687 cmd->sk = sk;
688 sock_hold(sk);
689
690 list_add(&cmd->list, &hdev->mgmt_pending);
691
692 return cmd;
693}
694
695static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
696 void (*cb)(struct pending_cmd *cmd, void *data),
697 void *data)
698{
699 struct list_head *p, *n;
700
701 list_for_each_safe(p, n, &hdev->mgmt_pending) {
702 struct pending_cmd *cmd;
703
704 cmd = list_entry(p, struct pending_cmd, list);
705
706 if (opcode > 0 && cmd->opcode != opcode)
707 continue;
708
709 cb(cmd, data);
710 }
711}
712
713static struct pending_cmd *mgmt_pending_find(u16 opcode, struct hci_dev *hdev)
714{
715 struct pending_cmd *cmd;
716
717 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
718 if (cmd->opcode == opcode)
719 return cmd;
720 }
721
722 return NULL;
723}
724
725static void mgmt_pending_remove(struct pending_cmd *cmd)
726{
727 list_del(&cmd->list);
728 mgmt_pending_free(cmd);
729}
730
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200731static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +0200732{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200733 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +0200734
Johan Hedbergaee9b212012-02-18 15:07:59 +0200735 return cmd_complete(sk, hdev->id, opcode, 0, &settings,
736 sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +0200737}
738
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300739static int set_powered(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200740{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300741 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200742 struct hci_dev *hdev;
743 struct pending_cmd *cmd;
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200744 int err;
Johan Hedberg03811012010-12-08 00:21:06 +0200745
Johan Hedberg03811012010-12-08 00:21:06 +0200746 BT_DBG("request for hci%u", index);
747
748 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200749 return cmd_status(sk, index, MGMT_OP_SET_POWERED,
750 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200751
752 hdev = hci_dev_get(index);
753 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200754 return cmd_status(sk, index, MGMT_OP_SET_POWERED,
755 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200756
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300757 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200758
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100759 if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) {
760 cancel_delayed_work(&hdev->power_off);
761
762 if (cp->val) {
763 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
764 mgmt_powered(hdev, 1);
765 goto failed;
766 }
767 }
768
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200769 if (!!cp->val == hdev_is_powered(hdev)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200770 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200771 goto failed;
772 }
773
774 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200775 err = cmd_status(sk, index, MGMT_OP_SET_POWERED,
776 MGMT_STATUS_BUSY);
Johan Hedberg03811012010-12-08 00:21:06 +0200777 goto failed;
778 }
779
780 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
781 if (!cmd) {
782 err = -ENOMEM;
783 goto failed;
784 }
785
786 if (cp->val)
Gustavo F. Padovan7f971042011-12-18 12:40:32 -0200787 schedule_work(&hdev->power_on);
Johan Hedberg03811012010-12-08 00:21:06 +0200788 else
Gustavo F. Padovan80b7ab32011-12-17 14:52:27 -0200789 schedule_work(&hdev->power_off.work);
Johan Hedberg03811012010-12-08 00:21:06 +0200790
791 err = 0;
792
793failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300794 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200795 hci_dev_put(hdev);
796 return err;
797}
798
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200799static int mgmt_event(u16 event, struct hci_dev *hdev, void *data,
800 u16 data_len, struct sock *skip_sk)
801{
802 struct sk_buff *skb;
803 struct mgmt_hdr *hdr;
804
805 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_ATOMIC);
806 if (!skb)
807 return -ENOMEM;
808
809 hdr = (void *) skb_put(skb, sizeof(*hdr));
810 hdr->opcode = cpu_to_le16(event);
811 if (hdev)
812 hdr->index = cpu_to_le16(hdev->id);
813 else
814 hdr->index = cpu_to_le16(MGMT_INDEX_NONE);
815 hdr->len = cpu_to_le16(data_len);
816
817 if (data)
818 memcpy(skb_put(skb, data_len), data, data_len);
819
820 hci_send_to_control(skb, skip_sk);
821 kfree_skb(skb);
822
823 return 0;
824}
825
826static int new_settings(struct hci_dev *hdev, struct sock *skip)
827{
828 __le32 ev;
829
830 ev = cpu_to_le32(get_current_settings(hdev));
831
832 return mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), skip);
833}
834
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300835static int set_discoverable(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200836{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300837 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberge41d8b42010-12-13 21:07:03 +0200838 struct hci_dev *hdev;
Johan Hedberg03811012010-12-08 00:21:06 +0200839 struct pending_cmd *cmd;
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200840 u16 timeout;
Johan Hedberg03811012010-12-08 00:21:06 +0200841 u8 scan;
842 int err;
843
Johan Hedberg03811012010-12-08 00:21:06 +0200844 BT_DBG("request for hci%u", index);
845
846 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200847 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
848 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200849
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200850 hdev = hci_dev_get(index);
851 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200852 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
853 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200854
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200855 timeout = get_unaligned_le16(&cp->timeout);
856
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300857 hci_dev_lock(hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200858
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200859 if (!hdev_is_powered(hdev) && timeout > 0) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200860 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
861 MGMT_STATUS_NOT_POWERED);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200862 goto failed;
863 }
864
865 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
866 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200867 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
868 MGMT_STATUS_BUSY);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200869 goto failed;
870 }
871
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200872 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) {
873 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
874 MGMT_STATUS_REJECTED);
875 goto failed;
876 }
877
878 if (!hdev_is_powered(hdev)) {
879 if (cp->val)
880 set_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
881 else
882 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
883 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
884 goto failed;
885 }
886
887 if (!!cp->val == test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200888 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200889 goto failed;
890 }
891
892 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
893 if (!cmd) {
894 err = -ENOMEM;
895 goto failed;
896 }
897
898 scan = SCAN_PAGE;
899
900 if (cp->val)
901 scan |= SCAN_INQUIRY;
902 else
903 cancel_delayed_work(&hdev->discov_off);
904
905 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
906 if (err < 0)
907 mgmt_pending_remove(cmd);
908
Johan Hedberg03811012010-12-08 00:21:06 +0200909 if (cp->val)
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200910 hdev->discov_timeout = timeout;
Johan Hedberg03811012010-12-08 00:21:06 +0200911
912failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300913 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200914 hci_dev_put(hdev);
915
916 return err;
917}
918
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300919static int set_connectable(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200920{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300921 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200922 struct hci_dev *hdev;
923 struct pending_cmd *cmd;
924 u8 scan;
925 int err;
926
Johan Hedberge41d8b42010-12-13 21:07:03 +0200927 BT_DBG("request for hci%u", index);
928
Johan Hedberg03811012010-12-08 00:21:06 +0200929 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200930 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
931 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200932
933 hdev = hci_dev_get(index);
934 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200935 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
936 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200937
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300938 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200939
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200940 if (!hdev_is_powered(hdev)) {
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200941 if (cp->val)
942 set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
943 else {
944 clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
945 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
946 }
947 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200948 goto failed;
949 }
950
951 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
952 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200953 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
954 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200955 goto failed;
956 }
957
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200958 if (!!cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200959 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200960 goto failed;
961 }
962
963 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
964 if (!cmd) {
965 err = -ENOMEM;
966 goto failed;
967 }
968
969 if (cp->val)
970 scan = SCAN_PAGE;
Johan Hedbergdf2c6c52012-02-21 19:15:49 +0200971 else {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200972 scan = 0;
973
Johan Hedbergdf2c6c52012-02-21 19:15:49 +0200974 if (test_bit(HCI_ISCAN, &hdev->flags) &&
975 hdev->discov_timeout > 0)
976 cancel_delayed_work(&hdev->discov_off);
977 }
978
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200979 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
980 if (err < 0)
981 mgmt_pending_remove(cmd);
982
983failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300984 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200985 hci_dev_put(hdev);
986
987 return err;
988}
989
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300990static int set_pairable(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +0200991{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300992 struct mgmt_mode *cp = data;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200993 struct hci_dev *hdev;
994 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200995
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200996 BT_DBG("request for hci%u", index);
997
998 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200999 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE,
1000 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001001
1002 hdev = hci_dev_get(index);
1003 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001004 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE,
1005 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001006
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001007 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001008
1009 if (cp->val)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001010 set_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001011 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001012 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001013
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001014 err = send_settings_rsp(sk, MGMT_OP_SET_PAIRABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001015 if (err < 0)
1016 goto failed;
1017
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001018 err = new_settings(hdev, sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001019
1020failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001021 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001022 hci_dev_put(hdev);
1023
1024 return err;
1025}
Johan Hedberg72a734e2010-12-30 00:38:22 +02001026
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001027static int set_link_security(struct sock *sk, u16 index, void *data, u16 len)
1028{
1029 struct mgmt_mode *cp = data;
1030 struct pending_cmd *cmd;
1031 struct hci_dev *hdev;
1032 uint8_t val;
1033 int err;
1034
1035 BT_DBG("request for hci%u", index);
1036
1037 if (len != sizeof(*cp))
1038 return cmd_status(sk, index, MGMT_OP_SET_LINK_SECURITY,
1039 MGMT_STATUS_INVALID_PARAMS);
1040
1041 hdev = hci_dev_get(index);
1042 if (!hdev)
1043 return cmd_status(sk, index, MGMT_OP_SET_LINK_SECURITY,
1044 MGMT_STATUS_INVALID_PARAMS);
1045
1046 hci_dev_lock(hdev);
1047
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001048 if (!hdev_is_powered(hdev)) {
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001049 err = cmd_status(sk, index, MGMT_OP_SET_LINK_SECURITY,
1050 MGMT_STATUS_NOT_POWERED);
1051 goto failed;
1052 }
1053
1054 if (mgmt_pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
1055 err = cmd_status(sk, index, MGMT_OP_SET_LINK_SECURITY,
1056 MGMT_STATUS_BUSY);
1057 goto failed;
1058 }
1059
1060 val = !!cp->val;
1061
1062 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1063 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1064 goto failed;
1065 }
1066
1067 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1068 if (!cmd) {
1069 err = -ENOMEM;
1070 goto failed;
1071 }
1072
1073 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1074 if (err < 0) {
1075 mgmt_pending_remove(cmd);
1076 goto failed;
1077 }
1078
1079failed:
1080 hci_dev_unlock(hdev);
1081 hci_dev_put(hdev);
1082
1083 return err;
1084}
1085
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001086static int set_ssp(struct sock *sk, u16 index, void *data, u16 len)
1087{
1088 struct mgmt_mode *cp = data;
1089 struct pending_cmd *cmd;
1090 struct hci_dev *hdev;
1091 uint8_t val;
1092 int err;
1093
1094 BT_DBG("request for hci%u", index);
1095
1096 if (len != sizeof(*cp))
1097 return cmd_status(sk, index, MGMT_OP_SET_SSP,
1098 MGMT_STATUS_INVALID_PARAMS);
1099
1100 hdev = hci_dev_get(index);
1101 if (!hdev)
1102 return cmd_status(sk, index, MGMT_OP_SET_SSP,
1103 MGMT_STATUS_INVALID_PARAMS);
1104
1105 hci_dev_lock(hdev);
1106
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001107 if (!hdev_is_powered(hdev)) {
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001108 err = cmd_status(sk, index, MGMT_OP_SET_SSP,
1109 MGMT_STATUS_NOT_POWERED);
1110 goto failed;
1111 }
1112
Johan Hedberg1e163572012-02-20 23:53:46 +02001113 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
1114 err = cmd_status(sk, index, MGMT_OP_SET_SSP,
1115 MGMT_STATUS_NOT_SUPPORTED);
1116 goto failed;
1117 }
1118
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001119 if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev)) {
1120 err = cmd_status(sk, index, MGMT_OP_SET_SSP, MGMT_STATUS_BUSY);
1121 goto failed;
1122 }
1123
1124 val = !!cp->val;
1125
1126 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) == val) {
1127 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1128 goto failed;
1129 }
1130
1131 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1132 if (!cmd) {
1133 err = -ENOMEM;
1134 goto failed;
1135 }
1136
1137 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, sizeof(val), &val);
1138 if (err < 0) {
1139 mgmt_pending_remove(cmd);
1140 goto failed;
1141 }
1142
1143failed:
1144 hci_dev_unlock(hdev);
1145 hci_dev_put(hdev);
1146
1147 return err;
1148}
1149
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001150static int set_hs(struct sock *sk, u16 index, void *data, u16 len)
1151{
1152 struct mgmt_mode *cp = data;
1153 struct hci_dev *hdev;
1154 int err;
1155
1156 BT_DBG("request for hci%u", index);
1157
1158 if (len != sizeof(*cp))
1159 return cmd_status(sk, index, MGMT_OP_SET_HS,
1160 MGMT_STATUS_INVALID_PARAMS);
1161
1162 hdev = hci_dev_get(index);
1163 if (!hdev)
1164 return cmd_status(sk, index, MGMT_OP_SET_HS,
1165 MGMT_STATUS_INVALID_PARAMS);
1166
1167 if (!enable_hs) {
1168 err = cmd_status(sk, index, MGMT_OP_SET_HS,
1169 MGMT_STATUS_NOT_SUPPORTED);
1170 goto failed;
1171 }
1172
1173 if (cp->val)
1174 set_bit(HCI_HS_ENABLED, &hdev->dev_flags);
1175 else
1176 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
1177
1178 err = send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
1179
1180failed:
1181 hci_dev_put(hdev);
1182 return err;
1183}
1184
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001185static int add_uuid(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001186{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001187 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001188 struct hci_dev *hdev;
1189 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001190 int err;
1191
Szymon Janc4e51eae2011-02-25 19:05:48 +01001192 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001193
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001194 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001195 return cmd_status(sk, index, MGMT_OP_ADD_UUID,
1196 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001197
Szymon Janc4e51eae2011-02-25 19:05:48 +01001198 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001199 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001200 return cmd_status(sk, index, MGMT_OP_ADD_UUID,
1201 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001202
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001203 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001204
1205 uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC);
1206 if (!uuid) {
1207 err = -ENOMEM;
1208 goto failed;
1209 }
1210
1211 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001212 uuid->svc_hint = cp->svc_hint;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001213
1214 list_add(&uuid->list, &hdev->uuids);
1215
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001216 err = update_class(hdev);
1217 if (err < 0)
1218 goto failed;
1219
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001220 err = update_eir(hdev);
1221 if (err < 0)
1222 goto failed;
1223
Johan Hedbergaee9b212012-02-18 15:07:59 +02001224 err = cmd_complete(sk, index, MGMT_OP_ADD_UUID, 0, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001225
1226failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001227 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001228 hci_dev_put(hdev);
1229
1230 return err;
1231}
1232
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001233static int remove_uuid(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001234{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001235 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001236 struct list_head *p, *n;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001237 struct hci_dev *hdev;
1238 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 +02001239 int err, found;
1240
Szymon Janc4e51eae2011-02-25 19:05:48 +01001241 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001242
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001243 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001244 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
1245 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001246
Szymon Janc4e51eae2011-02-25 19:05:48 +01001247 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001248 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001249 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
1250 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001251
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001252 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001253
1254 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
1255 err = hci_uuids_clear(hdev);
1256 goto unlock;
1257 }
1258
1259 found = 0;
1260
1261 list_for_each_safe(p, n, &hdev->uuids) {
1262 struct bt_uuid *match = list_entry(p, struct bt_uuid, list);
1263
1264 if (memcmp(match->uuid, cp->uuid, 16) != 0)
1265 continue;
1266
1267 list_del(&match->list);
1268 found++;
1269 }
1270
1271 if (found == 0) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001272 err = cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
1273 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001274 goto unlock;
1275 }
1276
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001277 err = update_class(hdev);
1278 if (err < 0)
1279 goto unlock;
1280
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001281 err = update_eir(hdev);
1282 if (err < 0)
1283 goto unlock;
1284
Johan Hedbergaee9b212012-02-18 15:07:59 +02001285 err = cmd_complete(sk, index, MGMT_OP_REMOVE_UUID, 0, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001286
1287unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001288 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001289 hci_dev_put(hdev);
1290
1291 return err;
1292}
1293
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001294static int set_dev_class(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001295{
1296 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001297 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001298 int err;
1299
Szymon Janc4e51eae2011-02-25 19:05:48 +01001300 BT_DBG("request for hci%u", index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001301
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001302 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001303 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS,
1304 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001305
Szymon Janc4e51eae2011-02-25 19:05:48 +01001306 hdev = hci_dev_get(index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001307 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001308 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS,
1309 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001310
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001311 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001312
Johan Hedbergb5235a62012-02-21 14:32:24 +02001313 if (!hdev_is_powered(hdev)) {
1314 err = cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS,
1315 MGMT_STATUS_NOT_POWERED);
1316 goto unlock;
1317 }
1318
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001319 hdev->major_class = cp->major;
1320 hdev->minor_class = cp->minor;
1321
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001322 if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02001323 hci_dev_unlock(hdev);
1324 cancel_delayed_work_sync(&hdev->service_cache);
1325 hci_dev_lock(hdev);
Johan Hedberg14c0b602011-12-15 00:47:37 +02001326 update_eir(hdev);
Johan Hedberg7d785252011-12-15 00:47:39 +02001327 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02001328
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001329 err = update_class(hdev);
1330
1331 if (err == 0)
Johan Hedbergaee9b212012-02-18 15:07:59 +02001332 err = cmd_complete(sk, index, MGMT_OP_SET_DEV_CLASS, 0,
1333 NULL, 0);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001334
Johan Hedbergb5235a62012-02-21 14:32:24 +02001335unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001336 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001337 hci_dev_put(hdev);
1338
1339 return err;
1340}
1341
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001342static int load_link_keys(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001343{
1344 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001345 struct mgmt_cp_load_link_keys *cp = data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001346 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001347 int i;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001348
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001349 if (len < sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001350 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1351 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001352
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001353 key_count = get_unaligned_le16(&cp->key_count);
1354
Johan Hedberg86742e12011-11-07 23:13:38 +02001355 expected_len = sizeof(*cp) + key_count *
1356 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001357 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001358 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001359 len, expected_len);
Johan Hedbergca69b792011-11-11 18:10:00 +02001360 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1361 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001362 }
1363
Szymon Janc4e51eae2011-02-25 19:05:48 +01001364 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001365 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001366 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1367 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001368
Szymon Janc4e51eae2011-02-25 19:05:48 +01001369 BT_DBG("hci%u debug_keys %u key_count %u", index, cp->debug_keys,
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001370 key_count);
1371
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001372 hci_dev_lock(hdev);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001373
1374 hci_link_keys_clear(hdev);
1375
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001376 set_bit(HCI_LINK_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001377
1378 if (cp->debug_keys)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001379 set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001380 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001381 clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001382
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001383 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001384 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001385
Johan Hedbergd753fdc2012-02-17 14:06:34 +02001386 hci_add_link_key(hdev, NULL, 0, &key->addr.bdaddr, key->val,
1387 key->type, key->pin_len);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001388 }
1389
Johan Hedbergaee9b212012-02-18 15:07:59 +02001390 cmd_complete(sk, index, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02001391
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001392 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001393 hci_dev_put(hdev);
1394
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001395 return 0;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001396}
1397
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001398static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
1399 u8 addr_type, struct sock *skip_sk)
1400{
1401 struct mgmt_ev_device_unpaired ev;
1402
1403 bacpy(&ev.addr.bdaddr, bdaddr);
1404 ev.addr.type = addr_type;
1405
1406 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
1407 skip_sk);
1408}
1409
Johan Hedberg124f6e32012-02-09 13:50:12 +02001410static int unpair_device(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001411{
1412 struct hci_dev *hdev;
Johan Hedberg124f6e32012-02-09 13:50:12 +02001413 struct mgmt_cp_unpair_device *cp = data;
1414 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001415 struct hci_cp_disconnect dc;
1416 struct pending_cmd *cmd;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001417 struct hci_conn *conn;
Johan Hedbergaee9b212012-02-18 15:07:59 +02001418 u8 status = 0;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001419 int err;
1420
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001421 if (len != sizeof(*cp))
Johan Hedberg124f6e32012-02-09 13:50:12 +02001422 return cmd_status(sk, index, MGMT_OP_UNPAIR_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02001423 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001424
Szymon Janc4e51eae2011-02-25 19:05:48 +01001425 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001426 if (!hdev)
Johan Hedberg124f6e32012-02-09 13:50:12 +02001427 return cmd_status(sk, index, MGMT_OP_UNPAIR_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02001428 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001429
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001430 hci_dev_lock(hdev);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001431
Johan Hedberga8a1d192011-11-10 15:54:38 +02001432 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02001433 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1434 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001435
Johan Hedberg124f6e32012-02-09 13:50:12 +02001436 if (cp->addr.type == MGMT_ADDR_BREDR)
1437 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
1438 else
1439 err = hci_remove_ltk(hdev, &cp->addr.bdaddr);
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03001440
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001441 if (err < 0) {
Johan Hedbergaee9b212012-02-18 15:07:59 +02001442 status = MGMT_STATUS_NOT_PAIRED;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001443 goto unlock;
1444 }
1445
Johan Hedberga8a1d192011-11-10 15:54:38 +02001446 if (!test_bit(HCI_UP, &hdev->flags) || !cp->disconnect) {
Johan Hedbergaee9b212012-02-18 15:07:59 +02001447 err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE, status,
1448 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001449 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001450 goto unlock;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001451 }
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001452
Johan Hedberg124f6e32012-02-09 13:50:12 +02001453 if (cp->addr.type == MGMT_ADDR_BREDR)
1454 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
1455 &cp->addr.bdaddr);
1456 else
1457 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
1458 &cp->addr.bdaddr);
1459
Johan Hedberga8a1d192011-11-10 15:54:38 +02001460 if (!conn) {
Johan Hedbergaee9b212012-02-18 15:07:59 +02001461 err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE, status,
1462 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001463 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001464 goto unlock;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001465 }
1466
Johan Hedberg124f6e32012-02-09 13:50:12 +02001467 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
1468 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02001469 if (!cmd) {
1470 err = -ENOMEM;
1471 goto unlock;
1472 }
1473
1474 put_unaligned_le16(conn->handle, &dc.handle);
1475 dc.reason = 0x13; /* Remote User Terminated Connection */
1476 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1477 if (err < 0)
1478 mgmt_pending_remove(cmd);
1479
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001480unlock:
Johan Hedbergca69b792011-11-11 18:10:00 +02001481 if (err < 0)
Johan Hedbergaee9b212012-02-18 15:07:59 +02001482 err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE, status,
1483 &rp, sizeof(rp));
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001484 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001485 hci_dev_put(hdev);
1486
1487 return err;
1488}
1489
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001490static int disconnect(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02001491{
1492 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001493 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001494 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03001495 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001496 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001497 int err;
1498
1499 BT_DBG("");
1500
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001501 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001502 return cmd_status(sk, index, MGMT_OP_DISCONNECT,
1503 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001504
Szymon Janc4e51eae2011-02-25 19:05:48 +01001505 hdev = hci_dev_get(index);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001506 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001507 return cmd_status(sk, index, MGMT_OP_DISCONNECT,
1508 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001509
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001510 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001511
1512 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001513 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1514 MGMT_STATUS_NOT_POWERED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001515 goto failed;
1516 }
1517
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001518 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001519 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1520 MGMT_STATUS_BUSY);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001521 goto failed;
1522 }
1523
Johan Hedberg88c3df12012-02-09 14:27:38 +02001524 if (cp->addr.type == MGMT_ADDR_BREDR)
1525 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
1526 else
1527 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03001528
Johan Hedberg8962ee72011-01-20 12:40:27 +02001529 if (!conn) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001530 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1531 MGMT_STATUS_NOT_CONNECTED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001532 goto failed;
1533 }
1534
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001535 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001536 if (!cmd) {
1537 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001538 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001539 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001540
1541 put_unaligned_le16(conn->handle, &dc.handle);
1542 dc.reason = 0x13; /* Remote User Terminated Connection */
1543
1544 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1545 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001546 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001547
1548failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001549 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001550 hci_dev_put(hdev);
1551
1552 return err;
1553}
1554
Johan Hedberg48264f02011-11-09 13:58:58 +02001555static u8 link_to_mgmt(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02001556{
1557 switch (link_type) {
1558 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02001559 switch (addr_type) {
1560 case ADDR_LE_DEV_PUBLIC:
1561 return MGMT_ADDR_LE_PUBLIC;
1562 case ADDR_LE_DEV_RANDOM:
1563 return MGMT_ADDR_LE_RANDOM;
1564 default:
1565 return MGMT_ADDR_INVALID;
1566 }
Johan Hedberg4c659c32011-11-07 23:13:39 +02001567 case ACL_LINK:
1568 return MGMT_ADDR_BREDR;
1569 default:
1570 return MGMT_ADDR_INVALID;
1571 }
1572}
1573
Szymon Janc8ce62842011-03-01 16:55:32 +01001574static int get_connections(struct sock *sk, u16 index)
Johan Hedberg2784eb42011-01-21 13:56:35 +02001575{
Johan Hedberg2784eb42011-01-21 13:56:35 +02001576 struct mgmt_rp_get_connections *rp;
1577 struct hci_dev *hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001578 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02001579 size_t rp_len;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001580 u16 count;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001581 int i, err;
1582
1583 BT_DBG("");
1584
Szymon Janc4e51eae2011-02-25 19:05:48 +01001585 hdev = hci_dev_get(index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001586 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001587 return cmd_status(sk, index, MGMT_OP_GET_CONNECTIONS,
1588 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001589
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001590 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001591
1592 count = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02001593 list_for_each_entry(c, &hdev->conn_hash.list, list) {
1594 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
1595 count++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001596 }
1597
Johan Hedberg4c659c32011-11-07 23:13:39 +02001598 rp_len = sizeof(*rp) + (count * sizeof(struct mgmt_addr_info));
Johan Hedberga38528f2011-01-22 06:46:43 +02001599 rp = kmalloc(rp_len, GFP_ATOMIC);
1600 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02001601 err = -ENOMEM;
1602 goto unlock;
1603 }
1604
Johan Hedberg2784eb42011-01-21 13:56:35 +02001605 put_unaligned_le16(count, &rp->conn_count);
1606
Johan Hedberg2784eb42011-01-21 13:56:35 +02001607 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001608 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02001609 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
1610 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001611 bacpy(&rp->addr[i].bdaddr, &c->dst);
Johan Hedberg48264f02011-11-09 13:58:58 +02001612 rp->addr[i].type = link_to_mgmt(c->type, c->dst_type);
Johan Hedberg4c659c32011-11-07 23:13:39 +02001613 if (rp->addr[i].type == MGMT_ADDR_INVALID)
1614 continue;
1615 i++;
1616 }
1617
1618 /* Recalculate length in case of filtered SCO connections, etc */
1619 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02001620
Johan Hedbergaee9b212012-02-18 15:07:59 +02001621 err = cmd_complete(sk, index, MGMT_OP_GET_CONNECTIONS, 0, rp, rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001622
1623unlock:
Johan Hedberga38528f2011-01-22 06:46:43 +02001624 kfree(rp);
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001625 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001626 hci_dev_put(hdev);
1627 return err;
1628}
1629
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001630static int send_pin_code_neg_reply(struct sock *sk, u16 index,
1631 struct hci_dev *hdev, struct mgmt_cp_pin_code_neg_reply *cp)
1632{
1633 struct pending_cmd *cmd;
1634 int err;
1635
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001636 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001637 sizeof(*cp));
1638 if (!cmd)
1639 return -ENOMEM;
1640
Johan Hedbergd8457692012-02-17 14:24:57 +02001641 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
1642 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001643 if (err < 0)
1644 mgmt_pending_remove(cmd);
1645
1646 return err;
1647}
1648
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001649static int pin_code_reply(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001650{
1651 struct hci_dev *hdev;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001652 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001653 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001654 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03001655 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001656 int err;
1657
1658 BT_DBG("");
1659
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001660 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001661 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1662 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001663
Szymon Janc4e51eae2011-02-25 19:05:48 +01001664 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001665 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001666 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1667 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001668
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001669 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001670
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001671 if (!hdev_is_powered(hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001672 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1673 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001674 goto failed;
1675 }
1676
Johan Hedbergd8457692012-02-17 14:24:57 +02001677 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001678 if (!conn) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001679 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1680 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001681 goto failed;
1682 }
1683
1684 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02001685 struct mgmt_cp_pin_code_neg_reply ncp;
1686
1687 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001688
1689 BT_ERR("PIN code is not 16 bytes long");
1690
1691 err = send_pin_code_neg_reply(sk, index, hdev, &ncp);
1692 if (err >= 0)
1693 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001694 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001695
1696 goto failed;
1697 }
1698
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001699 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data,
1700 len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001701 if (!cmd) {
1702 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001703 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001704 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02001705
Johan Hedbergd8457692012-02-17 14:24:57 +02001706 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001707 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02001708 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02001709
1710 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
1711 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001712 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001713
1714failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001715 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001716 hci_dev_put(hdev);
1717
1718 return err;
1719}
1720
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001721static int pin_code_neg_reply(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001722{
1723 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001724 struct mgmt_cp_pin_code_neg_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001725 int err;
1726
1727 BT_DBG("");
1728
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001729 if (len != sizeof(*cp))
1730 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001731 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001732
Szymon Janc4e51eae2011-02-25 19:05:48 +01001733 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001734 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001735 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001736 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001737
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001738 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001739
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001740 if (!hdev_is_powered(hdev)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001741 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001742 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001743 goto failed;
1744 }
1745
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001746 err = send_pin_code_neg_reply(sk, index, hdev, cp);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001747
1748failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001749 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001750 hci_dev_put(hdev);
1751
1752 return err;
1753}
1754
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001755static int set_io_capability(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001756{
1757 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001758 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001759
1760 BT_DBG("");
1761
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001762 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001763 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY,
1764 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001765
Szymon Janc4e51eae2011-02-25 19:05:48 +01001766 hdev = hci_dev_get(index);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001767 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001768 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY,
1769 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001770
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001771 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001772
1773 hdev->io_capability = cp->io_capability;
1774
1775 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Szymon Jancb8534e02011-03-01 16:55:34 +01001776 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001777
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001778 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001779 hci_dev_put(hdev);
1780
Johan Hedbergaee9b212012-02-18 15:07:59 +02001781 return cmd_complete(sk, index, MGMT_OP_SET_IO_CAPABILITY, 0, NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001782}
1783
Johan Hedberge9a416b2011-02-19 12:05:56 -03001784static inline struct pending_cmd *find_pairing(struct hci_conn *conn)
1785{
1786 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001787 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001788
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001789 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03001790 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
1791 continue;
1792
Johan Hedberge9a416b2011-02-19 12:05:56 -03001793 if (cmd->user_data != conn)
1794 continue;
1795
1796 return cmd;
1797 }
1798
1799 return NULL;
1800}
1801
1802static void pairing_complete(struct pending_cmd *cmd, u8 status)
1803{
1804 struct mgmt_rp_pair_device rp;
1805 struct hci_conn *conn = cmd->user_data;
1806
Johan Hedbergba4e5642011-11-11 00:07:34 +02001807 bacpy(&rp.addr.bdaddr, &conn->dst);
1808 rp.addr.type = link_to_mgmt(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001809
Johan Hedbergaee9b212012-02-18 15:07:59 +02001810 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, status,
1811 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001812
1813 /* So we don't get further callbacks for this connection */
1814 conn->connect_cfm_cb = NULL;
1815 conn->security_cfm_cb = NULL;
1816 conn->disconn_cfm_cb = NULL;
1817
1818 hci_conn_put(conn);
1819
Johan Hedberga664b5b2011-02-19 12:06:02 -03001820 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001821}
1822
1823static void pairing_complete_cb(struct hci_conn *conn, u8 status)
1824{
1825 struct pending_cmd *cmd;
1826
1827 BT_DBG("status %u", status);
1828
Johan Hedberg56e5cb82011-11-08 20:40:16 +02001829 cmd = find_pairing(conn);
1830 if (!cmd)
1831 BT_DBG("Unable to find a pending command");
1832 else
Johan Hedberge2113262012-02-18 15:20:03 +02001833 pairing_complete(cmd, mgmt_status(status));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001834}
1835
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001836static int pair_device(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001837{
1838 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001839 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02001840 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001841 struct pending_cmd *cmd;
1842 u8 sec_level, auth_type;
1843 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001844 int err;
1845
1846 BT_DBG("");
1847
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001848 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001849 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE,
1850 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001851
Szymon Janc4e51eae2011-02-25 19:05:48 +01001852 hdev = hci_dev_get(index);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001853 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001854 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE,
1855 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001856
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001857 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001858
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001859 sec_level = BT_SECURITY_MEDIUM;
1860 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001861 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001862 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03001863 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001864
Johan Hedbergba4e5642011-11-11 00:07:34 +02001865 if (cp->addr.type == MGMT_ADDR_BREDR)
1866 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr, sec_level,
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001867 auth_type);
1868 else
Johan Hedbergba4e5642011-11-11 00:07:34 +02001869 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr, sec_level,
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001870 auth_type);
1871
Johan Hedberg1425acb2011-11-11 00:07:35 +02001872 memset(&rp, 0, sizeof(rp));
1873 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1874 rp.addr.type = cp->addr.type;
1875
Ville Tervo30e76272011-02-22 16:10:53 -03001876 if (IS_ERR(conn)) {
Johan Hedberge2113262012-02-18 15:20:03 +02001877 err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE,
1878 MGMT_STATUS_CONNECT_FAILED,
1879 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001880 goto unlock;
1881 }
1882
1883 if (conn->connect_cfm_cb) {
1884 hci_conn_put(conn);
Johan Hedberge2113262012-02-18 15:20:03 +02001885 err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE,
1886 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001887 goto unlock;
1888 }
1889
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001890 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001891 if (!cmd) {
1892 err = -ENOMEM;
1893 hci_conn_put(conn);
1894 goto unlock;
1895 }
1896
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001897 /* For LE, just connecting isn't a proof that the pairing finished */
Johan Hedbergba4e5642011-11-11 00:07:34 +02001898 if (cp->addr.type == MGMT_ADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001899 conn->connect_cfm_cb = pairing_complete_cb;
1900
Johan Hedberge9a416b2011-02-19 12:05:56 -03001901 conn->security_cfm_cb = pairing_complete_cb;
1902 conn->disconn_cfm_cb = pairing_complete_cb;
1903 conn->io_capability = cp->io_cap;
1904 cmd->user_data = conn;
1905
1906 if (conn->state == BT_CONNECTED &&
1907 hci_conn_security(conn, sec_level, auth_type))
1908 pairing_complete(cmd, 0);
1909
1910 err = 0;
1911
1912unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001913 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001914 hci_dev_put(hdev);
1915
1916 return err;
1917}
1918
Johan Hedberg28424702012-02-02 04:02:29 +02001919static int cancel_pair_device(struct sock *sk, u16 index,
1920 unsigned char *data, u16 len)
1921{
1922 struct mgmt_addr_info *addr = (void *) data;
1923 struct hci_dev *hdev;
1924 struct pending_cmd *cmd;
1925 struct hci_conn *conn;
1926 int err;
1927
1928 BT_DBG("");
1929
1930 if (len != sizeof(*addr))
1931 return cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
1932 MGMT_STATUS_INVALID_PARAMS);
1933
1934 hdev = hci_dev_get(index);
1935 if (!hdev)
1936 return cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
1937 MGMT_STATUS_INVALID_PARAMS);
1938
1939 hci_dev_lock(hdev);
1940
1941 cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
1942 if (!cmd) {
1943 err = cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
1944 MGMT_STATUS_INVALID_PARAMS);
1945 goto unlock;
1946 }
1947
1948 conn = cmd->user_data;
1949
1950 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
1951 err = cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
1952 MGMT_STATUS_INVALID_PARAMS);
1953 goto unlock;
1954 }
1955
1956 pairing_complete(cmd, MGMT_STATUS_CANCELLED);
1957
Johan Hedbergaee9b212012-02-18 15:07:59 +02001958 err = cmd_complete(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE, 0, addr,
Johan Hedberg28424702012-02-02 04:02:29 +02001959 sizeof(*addr));
1960unlock:
1961 hci_dev_unlock(hdev);
1962 hci_dev_put(hdev);
1963
1964 return err;
1965}
1966
Brian Gix0df4c182011-11-16 13:53:13 -08001967static int user_pairing_resp(struct sock *sk, u16 index, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02001968 u8 type, u16 mgmt_op, u16 hci_op,
1969 __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03001970{
Johan Hedberga5c29682011-02-19 12:05:57 -03001971 struct pending_cmd *cmd;
1972 struct hci_dev *hdev;
Brian Gix0df4c182011-11-16 13:53:13 -08001973 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03001974 int err;
1975
Szymon Janc4e51eae2011-02-25 19:05:48 +01001976 hdev = hci_dev_get(index);
Johan Hedberga5c29682011-02-19 12:05:57 -03001977 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001978 return cmd_status(sk, index, mgmt_op,
1979 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga5c29682011-02-19 12:05:57 -03001980
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001981 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02001982
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001983 if (!hdev_is_powered(hdev)) {
Brian Gix0df4c182011-11-16 13:53:13 -08001984 err = cmd_status(sk, index, mgmt_op, MGMT_STATUS_NOT_POWERED);
1985 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03001986 }
1987
Johan Hedberg272d90d2012-02-09 15:26:12 +02001988 if (type == MGMT_ADDR_BREDR)
1989 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, bdaddr);
1990 else
Brian Gix47c15e22011-11-16 13:53:14 -08001991 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, bdaddr);
Brian Gix47c15e22011-11-16 13:53:14 -08001992
Johan Hedberg272d90d2012-02-09 15:26:12 +02001993 if (!conn) {
1994 err = cmd_status(sk, index, mgmt_op,
1995 MGMT_STATUS_NOT_CONNECTED);
1996 goto done;
1997 }
1998
1999 if (type == MGMT_ADDR_LE_PUBLIC || type == MGMT_ADDR_LE_RANDOM) {
Brian Gix47c15e22011-11-16 13:53:14 -08002000 /* Continue with pairing via SMP */
Brian Gix5fe57d92011-12-21 16:12:13 -08002001 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix47c15e22011-11-16 13:53:14 -08002002
Brian Gix5fe57d92011-12-21 16:12:13 -08002003 if (!err)
2004 err = cmd_status(sk, index, mgmt_op,
2005 MGMT_STATUS_SUCCESS);
2006 else
2007 err = cmd_status(sk, index, mgmt_op,
2008 MGMT_STATUS_FAILED);
2009
Brian Gix47c15e22011-11-16 13:53:14 -08002010 goto done;
2011 }
2012
Brian Gix0df4c182011-11-16 13:53:13 -08002013 cmd = mgmt_pending_add(sk, mgmt_op, hdev, bdaddr, sizeof(*bdaddr));
Johan Hedberga5c29682011-02-19 12:05:57 -03002014 if (!cmd) {
2015 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08002016 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002017 }
2018
Brian Gix0df4c182011-11-16 13:53:13 -08002019 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08002020 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
2021 struct hci_cp_user_passkey_reply cp;
2022
2023 bacpy(&cp.bdaddr, bdaddr);
2024 cp.passkey = passkey;
2025 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
2026 } else
2027 err = hci_send_cmd(hdev, hci_op, sizeof(*bdaddr), bdaddr);
2028
Johan Hedberga664b5b2011-02-19 12:06:02 -03002029 if (err < 0)
2030 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002031
Brian Gix0df4c182011-11-16 13:53:13 -08002032done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002033 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002034 hci_dev_put(hdev);
2035
2036 return err;
2037}
2038
Brian Gix0df4c182011-11-16 13:53:13 -08002039static int user_confirm_reply(struct sock *sk, u16 index, void *data, u16 len)
2040{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002041 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002042
2043 BT_DBG("");
2044
2045 if (len != sizeof(*cp))
2046 return cmd_status(sk, index, MGMT_OP_USER_CONFIRM_REPLY,
2047 MGMT_STATUS_INVALID_PARAMS);
2048
Johan Hedberg272d90d2012-02-09 15:26:12 +02002049 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
2050 MGMT_OP_USER_CONFIRM_REPLY,
2051 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002052}
2053
2054static int user_confirm_neg_reply(struct sock *sk, u16 index, void *data,
2055 u16 len)
2056{
Johan Hedbergc9c26592011-12-15 00:47:41 +02002057 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002058
2059 BT_DBG("");
2060
2061 if (len != sizeof(*cp))
2062 return cmd_status(sk, index, MGMT_OP_USER_CONFIRM_NEG_REPLY,
2063 MGMT_STATUS_INVALID_PARAMS);
2064
Johan Hedberg272d90d2012-02-09 15:26:12 +02002065 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
2066 MGMT_OP_USER_CONFIRM_NEG_REPLY,
2067 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002068}
2069
Brian Gix604086b2011-11-23 08:28:33 -08002070static int user_passkey_reply(struct sock *sk, u16 index, void *data, u16 len)
2071{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002072 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002073
2074 BT_DBG("");
2075
2076 if (len != sizeof(*cp))
2077 return cmd_status(sk, index, MGMT_OP_USER_PASSKEY_REPLY,
2078 EINVAL);
2079
Johan Hedberg272d90d2012-02-09 15:26:12 +02002080 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
2081 MGMT_OP_USER_PASSKEY_REPLY,
2082 HCI_OP_USER_PASSKEY_REPLY,
2083 cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08002084}
2085
2086static int user_passkey_neg_reply(struct sock *sk, u16 index, void *data,
2087 u16 len)
2088{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002089 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002090
2091 BT_DBG("");
2092
2093 if (len != sizeof(*cp))
2094 return cmd_status(sk, index, MGMT_OP_USER_PASSKEY_NEG_REPLY,
2095 EINVAL);
2096
Johan Hedberg272d90d2012-02-09 15:26:12 +02002097 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
2098 MGMT_OP_USER_PASSKEY_NEG_REPLY,
2099 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08002100}
2101
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002102static int set_local_name(struct sock *sk, u16 index, void *data,
Johan Hedbergb312b1612011-03-16 14:29:37 +02002103 u16 len)
2104{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002105 struct mgmt_cp_set_local_name *mgmt_cp = data;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002106 struct hci_cp_write_local_name hci_cp;
2107 struct hci_dev *hdev;
2108 struct pending_cmd *cmd;
2109 int err;
2110
2111 BT_DBG("");
2112
2113 if (len != sizeof(*mgmt_cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02002114 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME,
2115 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002116
2117 hdev = hci_dev_get(index);
2118 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002119 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME,
2120 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002121
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002122 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002123
Johan Hedbergb5235a62012-02-21 14:32:24 +02002124 if (!hdev_is_powered(hdev)) {
2125 err = cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME,
2126 MGMT_STATUS_NOT_POWERED);
2127 goto failed;
2128 }
2129
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002130 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data,
2131 len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002132 if (!cmd) {
2133 err = -ENOMEM;
2134 goto failed;
2135 }
2136
2137 memcpy(hci_cp.name, mgmt_cp->name, sizeof(hci_cp.name));
2138 err = hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(hci_cp),
2139 &hci_cp);
2140 if (err < 0)
2141 mgmt_pending_remove(cmd);
2142
2143failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002144 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002145 hci_dev_put(hdev);
2146
2147 return err;
2148}
2149
Szymon Jancc35938b2011-03-22 13:12:21 +01002150static int read_local_oob_data(struct sock *sk, u16 index)
2151{
2152 struct hci_dev *hdev;
2153 struct pending_cmd *cmd;
2154 int err;
2155
2156 BT_DBG("hci%u", index);
2157
2158 hdev = hci_dev_get(index);
2159 if (!hdev)
2160 return cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002161 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancc35938b2011-03-22 13:12:21 +01002162
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002163 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002164
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002165 if (!hdev_is_powered(hdev)) {
Szymon Jancc35938b2011-03-22 13:12:21 +01002166 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002167 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002168 goto unlock;
2169 }
2170
2171 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
2172 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002173 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002174 goto unlock;
2175 }
2176
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002177 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02002178 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2179 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01002180 goto unlock;
2181 }
2182
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002183 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01002184 if (!cmd) {
2185 err = -ENOMEM;
2186 goto unlock;
2187 }
2188
2189 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
2190 if (err < 0)
2191 mgmt_pending_remove(cmd);
2192
2193unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002194 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002195 hci_dev_put(hdev);
2196
2197 return err;
2198}
2199
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002200static int add_remote_oob_data(struct sock *sk, u16 index, void *data,
2201 u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002202{
2203 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002204 struct mgmt_cp_add_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002205 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002206 int err;
2207
2208 BT_DBG("hci%u ", index);
2209
2210 if (len != sizeof(*cp))
2211 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002212 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01002213
2214 hdev = hci_dev_get(index);
2215 if (!hdev)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002216 return cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
2217 MGMT_STATUS_INVALID_PARAMS,
2218 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002219
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002220 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002221
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002222 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, cp->hash,
Szymon Janc2763eda2011-03-22 13:12:22 +01002223 cp->randomizer);
2224 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002225 status = MGMT_STATUS_FAILED;
Szymon Janc2763eda2011-03-22 13:12:22 +01002226 else
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002227 status = 0;
2228
2229 err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, status,
2230 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002231
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002232 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002233 hci_dev_put(hdev);
2234
2235 return err;
2236}
2237
2238static int remove_remote_oob_data(struct sock *sk, u16 index,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002239 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002240{
2241 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002242 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002243 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002244 int err;
2245
2246 BT_DBG("hci%u ", index);
2247
2248 if (len != sizeof(*cp))
2249 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002250 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01002251
2252 hdev = hci_dev_get(index);
2253 if (!hdev)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002254 return cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2255 MGMT_STATUS_INVALID_PARAMS,
2256 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002257
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002258 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002259
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002260 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr);
Szymon Janc2763eda2011-03-22 13:12:22 +01002261 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002262 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01002263 else
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002264 status = 0;
2265
2266 err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA, status,
2267 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002268
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002269 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002270 hci_dev_put(hdev);
2271
2272 return err;
2273}
2274
Andre Guedes5e0452c2012-02-17 20:39:38 -03002275static int discovery(struct hci_dev *hdev)
2276{
2277 int err;
2278
2279 if (lmp_host_le_capable(hdev)) {
2280 if (lmp_bredr_capable(hdev)) {
2281 err = hci_le_scan(hdev, LE_SCAN_TYPE,
2282 LE_SCAN_INT, LE_SCAN_WIN,
2283 LE_SCAN_TIMEOUT_BREDR_LE);
2284 } else {
2285 hdev->discovery.type = DISCOV_TYPE_LE;
2286 err = hci_le_scan(hdev, LE_SCAN_TYPE,
2287 LE_SCAN_INT, LE_SCAN_WIN,
2288 LE_SCAN_TIMEOUT_LE_ONLY);
2289 }
2290 } else {
2291 hdev->discovery.type = DISCOV_TYPE_BREDR;
2292 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
2293 }
2294
2295 return err;
2296}
2297
2298int mgmt_interleaved_discovery(struct hci_dev *hdev)
2299{
2300 int err;
2301
2302 BT_DBG("%s", hdev->name);
2303
2304 hci_dev_lock(hdev);
2305
2306 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR_LE);
2307 if (err < 0)
2308 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2309
2310 hci_dev_unlock(hdev);
2311
2312 return err;
2313}
2314
Johan Hedberg450dfda2011-11-12 11:58:22 +02002315static int start_discovery(struct sock *sk, u16 index,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002316 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002317{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002318 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002319 struct pending_cmd *cmd;
2320 struct hci_dev *hdev;
2321 int err;
2322
2323 BT_DBG("hci%u", index);
2324
Johan Hedberg450dfda2011-11-12 11:58:22 +02002325 if (len != sizeof(*cp))
2326 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2327 MGMT_STATUS_INVALID_PARAMS);
2328
Johan Hedberg14a53662011-04-27 10:29:56 -04002329 hdev = hci_dev_get(index);
2330 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002331 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2332 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg14a53662011-04-27 10:29:56 -04002333
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002334 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002335
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002336 if (!hdev_is_powered(hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02002337 err = cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2338 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02002339 goto failed;
2340 }
2341
Johan Hedbergff9ef572012-01-04 14:23:45 +02002342 if (hdev->discovery.state != DISCOVERY_STOPPED) {
2343 err = cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2344 MGMT_STATUS_BUSY);
2345 goto failed;
2346 }
2347
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002348 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002349 if (!cmd) {
2350 err = -ENOMEM;
2351 goto failed;
2352 }
2353
Andre Guedes4aab14e2012-02-17 20:39:36 -03002354 hdev->discovery.type = cp->type;
2355
2356 switch (hdev->discovery.type) {
Andre Guedesf39799f2012-02-17 20:39:35 -03002357 case DISCOV_TYPE_BREDR:
Andre Guedes3fd24152012-02-03 17:48:01 -03002358 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
Andre Guedesf39799f2012-02-17 20:39:35 -03002359 break;
2360
2361 case DISCOV_TYPE_LE:
Andre Guedes3fd24152012-02-03 17:48:01 -03002362 err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT,
2363 LE_SCAN_WIN, LE_SCAN_TIMEOUT_LE_ONLY);
Andre Guedesf39799f2012-02-17 20:39:35 -03002364 break;
2365
Andre Guedes5e0452c2012-02-17 20:39:38 -03002366 case DISCOV_TYPE_INTERLEAVED:
2367 err = discovery(hdev);
2368 break;
2369
Andre Guedesf39799f2012-02-17 20:39:35 -03002370 default:
Andre Guedes3fd24152012-02-03 17:48:01 -03002371 err = -EINVAL;
Andre Guedesf39799f2012-02-17 20:39:35 -03002372 }
Andre Guedes3fd24152012-02-03 17:48:01 -03002373
Johan Hedberg14a53662011-04-27 10:29:56 -04002374 if (err < 0)
2375 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002376 else
2377 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002378
2379failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002380 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002381 hci_dev_put(hdev);
2382
2383 return err;
2384}
2385
Johan Hedbergd9306502012-02-20 23:25:18 +02002386static int stop_discovery(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002387{
Johan Hedbergd9306502012-02-20 23:25:18 +02002388 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002389 struct hci_dev *hdev;
2390 struct pending_cmd *cmd;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002391 struct hci_cp_remote_name_req_cancel cp;
2392 struct inquiry_entry *e;
Johan Hedberg14a53662011-04-27 10:29:56 -04002393 int err;
2394
2395 BT_DBG("hci%u", index);
2396
Johan Hedbergd9306502012-02-20 23:25:18 +02002397 if (len != sizeof(*mgmt_cp))
2398 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY,
2399 MGMT_STATUS_INVALID_PARAMS);
2400
Johan Hedberg14a53662011-04-27 10:29:56 -04002401 hdev = hci_dev_get(index);
2402 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002403 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY,
2404 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg14a53662011-04-27 10:29:56 -04002405
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002406 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002407
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002408 if (!hci_discovery_active(hdev)) {
Johan Hedbergd9306502012-02-20 23:25:18 +02002409 err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY,
2410 MGMT_STATUS_REJECTED,
2411 &mgmt_cp->type, sizeof(mgmt_cp->type));
2412 goto unlock;
2413 }
2414
2415 if (hdev->discovery.type != mgmt_cp->type) {
2416 err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY,
2417 MGMT_STATUS_INVALID_PARAMS,
2418 &mgmt_cp->type, sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002419 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02002420 }
2421
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002422 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002423 if (!cmd) {
2424 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002425 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04002426 }
2427
Andre Guedes343f9352012-02-17 20:39:37 -03002428 if (hdev->discovery.state == DISCOVERY_FINDING) {
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002429 err = hci_cancel_inquiry(hdev);
2430 if (err < 0)
2431 mgmt_pending_remove(cmd);
2432 else
2433 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
2434 goto unlock;
2435 }
2436
2437 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY, NAME_PENDING);
2438 if (!e) {
2439 mgmt_pending_remove(cmd);
Johan Hedbergaee9b212012-02-18 15:07:59 +02002440 err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY, 0,
Johan Hedbergd9306502012-02-20 23:25:18 +02002441 &mgmt_cp->type, sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002442 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2443 goto unlock;
2444 }
2445
2446 bacpy(&cp.bdaddr, &e->data.bdaddr);
2447 err = hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ_CANCEL,
2448 sizeof(cp), &cp);
Johan Hedberg14a53662011-04-27 10:29:56 -04002449 if (err < 0)
2450 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002451 else
2452 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002453
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002454unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002455 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002456 hci_dev_put(hdev);
2457
2458 return err;
2459}
2460
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002461static int confirm_name(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02002462{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002463 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002464 struct inquiry_entry *e;
2465 struct hci_dev *hdev;
2466 int err;
2467
2468 BT_DBG("hci%u", index);
2469
2470 if (len != sizeof(*cp))
2471 return cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2472 MGMT_STATUS_INVALID_PARAMS);
2473
2474 hdev = hci_dev_get(index);
2475 if (!hdev)
2476 return cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2477 MGMT_STATUS_INVALID_PARAMS);
2478
2479 hci_dev_lock(hdev);
2480
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002481 if (!hci_discovery_active(hdev)) {
2482 err = cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2483 MGMT_STATUS_FAILED);
2484 goto failed;
2485 }
2486
Johan Hedberga198e7b2012-02-17 14:27:06 +02002487 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002488 if (!e) {
2489 err = cmd_status (sk, index, MGMT_OP_CONFIRM_NAME,
2490 MGMT_STATUS_INVALID_PARAMS);
2491 goto failed;
2492 }
2493
2494 if (cp->name_known) {
2495 e->name_state = NAME_KNOWN;
2496 list_del(&e->list);
2497 } else {
2498 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e202012-01-09 00:53:02 +02002499 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002500 }
2501
2502 err = 0;
2503
2504failed:
2505 hci_dev_unlock(hdev);
2506
2507 return err;
2508}
2509
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002510static int block_device(struct sock *sk, u16 index, void *data, u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002511{
2512 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002513 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002514 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03002515 int err;
2516
2517 BT_DBG("hci%u", index);
2518
Antti Julku7fbec222011-06-15 12:01:15 +03002519 if (len != sizeof(*cp))
2520 return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002521 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002522
2523 hdev = hci_dev_get(index);
2524 if (!hdev)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002525 return cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE,
2526 MGMT_STATUS_INVALID_PARAMS,
2527 &cp->addr, sizeof(cp->addr));
Antti Julku7fbec222011-06-15 12:01:15 +03002528
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002529 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002530
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002531 err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002532 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002533 status = MGMT_STATUS_FAILED;
Antti Julku7fbec222011-06-15 12:01:15 +03002534 else
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002535 status = 0;
2536
2537 err = cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE, status,
2538 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03002539
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002540 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002541 hci_dev_put(hdev);
2542
2543 return err;
2544}
2545
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002546static int unblock_device(struct sock *sk, u16 index, void *data, u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002547{
2548 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002549 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002550 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03002551 int err;
2552
2553 BT_DBG("hci%u", index);
2554
Antti Julku7fbec222011-06-15 12:01:15 +03002555 if (len != sizeof(*cp))
2556 return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002557 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002558
2559 hdev = hci_dev_get(index);
2560 if (!hdev)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002561 return cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE,
2562 MGMT_STATUS_INVALID_PARAMS,
2563 &cp->addr, sizeof(cp->addr));
Antti Julku7fbec222011-06-15 12:01:15 +03002564
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002565 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002566
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002567 err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002568 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002569 status = MGMT_STATUS_INVALID_PARAMS;
Antti Julku7fbec222011-06-15 12:01:15 +03002570 else
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002571 status = 0;
2572
2573 err = cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE, status,
2574 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03002575
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002576 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002577 hci_dev_put(hdev);
2578
2579 return err;
2580}
2581
Antti Julkuf6422ec2011-06-22 13:11:56 +03002582static int set_fast_connectable(struct sock *sk, u16 index,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002583 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03002584{
2585 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002586 struct mgmt_mode *cp = data;
Antti Julkuf6422ec2011-06-22 13:11:56 +03002587 struct hci_cp_write_page_scan_activity acp;
2588 u8 type;
2589 int err;
2590
2591 BT_DBG("hci%u", index);
2592
2593 if (len != sizeof(*cp))
2594 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002595 MGMT_STATUS_INVALID_PARAMS);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002596
2597 hdev = hci_dev_get(index);
2598 if (!hdev)
2599 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002600 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg5400c042012-02-21 16:40:33 +02002601 if (!hdev_is_powered(hdev))
2602 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
2603 MGMT_STATUS_NOT_POWERED);
2604
2605 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
2606 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
2607 MGMT_STATUS_REJECTED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002608
2609 hci_dev_lock(hdev);
2610
Johan Hedbergf7c68692011-12-15 00:47:36 +02002611 if (cp->val) {
Antti Julkuf6422ec2011-06-22 13:11:56 +03002612 type = PAGE_SCAN_TYPE_INTERLACED;
2613 acp.interval = 0x0024; /* 22.5 msec page scan interval */
2614 } else {
2615 type = PAGE_SCAN_TYPE_STANDARD; /* default */
2616 acp.interval = 0x0800; /* default 1.28 sec page scan */
2617 }
2618
2619 acp.window = 0x0012; /* default 11.25 msec page scan window */
2620
2621 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
2622 sizeof(acp), &acp);
2623 if (err < 0) {
2624 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002625 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002626 goto done;
2627 }
2628
2629 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
2630 if (err < 0) {
2631 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002632 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002633 goto done;
2634 }
2635
Johan Hedbergaee9b212012-02-18 15:07:59 +02002636 err = cmd_complete(sk, index, MGMT_OP_SET_FAST_CONNECTABLE, 0,
2637 NULL, 0);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002638done:
2639 hci_dev_unlock(hdev);
2640 hci_dev_put(hdev);
2641
2642 return err;
2643}
2644
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002645static int load_long_term_keys(struct sock *sk, u16 index,
2646 void *cp_data, u16 len)
2647{
2648 struct hci_dev *hdev;
2649 struct mgmt_cp_load_long_term_keys *cp = cp_data;
2650 u16 key_count, expected_len;
2651 int i;
2652
2653 if (len < sizeof(*cp))
2654 return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS,
2655 EINVAL);
2656
2657 key_count = get_unaligned_le16(&cp->key_count);
2658
2659 expected_len = sizeof(*cp) + key_count *
2660 sizeof(struct mgmt_ltk_info);
2661 if (expected_len != len) {
2662 BT_ERR("load_keys: expected %u bytes, got %u bytes",
2663 len, expected_len);
2664 return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS,
2665 EINVAL);
2666 }
2667
2668 hdev = hci_dev_get(index);
2669 if (!hdev)
2670 return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS,
2671 ENODEV);
2672
2673 BT_DBG("hci%u key_count %u", index, key_count);
2674
2675 hci_dev_lock(hdev);
2676
2677 hci_smp_ltks_clear(hdev);
2678
2679 for (i = 0; i < key_count; i++) {
2680 struct mgmt_ltk_info *key = &cp->keys[i];
2681 u8 type;
2682
2683 if (key->master)
2684 type = HCI_SMP_LTK;
2685 else
2686 type = HCI_SMP_LTK_SLAVE;
2687
2688 hci_add_ltk(hdev, &key->addr.bdaddr, key->addr.type,
2689 type, 0, key->authenticated, key->val,
2690 key->enc_size, key->ediv, key->rand);
2691 }
2692
2693 hci_dev_unlock(hdev);
2694 hci_dev_put(hdev);
2695
2696 return 0;
2697}
2698
Johan Hedberg03811012010-12-08 00:21:06 +02002699int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
2700{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002701 void *buf;
2702 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02002703 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002704 u16 opcode, index, len;
Johan Hedberg03811012010-12-08 00:21:06 +02002705 int err;
2706
2707 BT_DBG("got %zu bytes", msglen);
2708
2709 if (msglen < sizeof(*hdr))
2710 return -EINVAL;
2711
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03002712 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02002713 if (!buf)
2714 return -ENOMEM;
2715
2716 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
2717 err = -EFAULT;
2718 goto done;
2719 }
2720
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002721 hdr = buf;
Johan Hedberg03811012010-12-08 00:21:06 +02002722 opcode = get_unaligned_le16(&hdr->opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002723 index = get_unaligned_le16(&hdr->index);
Johan Hedberg03811012010-12-08 00:21:06 +02002724 len = get_unaligned_le16(&hdr->len);
2725
2726 if (len != msglen - sizeof(*hdr)) {
2727 err = -EINVAL;
2728 goto done;
2729 }
2730
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002731 cp = buf + sizeof(*hdr);
2732
Johan Hedberg03811012010-12-08 00:21:06 +02002733 switch (opcode) {
Johan Hedberg02d98122010-12-13 21:07:04 +02002734 case MGMT_OP_READ_VERSION:
2735 err = read_version(sk);
2736 break;
Johan Hedberge70bb2e2012-02-13 16:59:33 +02002737 case MGMT_OP_READ_COMMANDS:
2738 err = read_commands(sk);
2739 break;
Johan Hedbergfaba42e2010-12-13 21:07:05 +02002740 case MGMT_OP_READ_INDEX_LIST:
2741 err = read_index_list(sk);
2742 break;
Johan Hedbergf7b64e62010-12-13 21:07:06 +02002743 case MGMT_OP_READ_INFO:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002744 err = read_controller_info(sk, index);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02002745 break;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002746 case MGMT_OP_SET_POWERED:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002747 err = set_powered(sk, index, cp, len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002748 break;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002749 case MGMT_OP_SET_DISCOVERABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002750 err = set_discoverable(sk, index, cp, len);
Johan Hedberg73f22f62010-12-29 16:00:25 +02002751 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002752 case MGMT_OP_SET_CONNECTABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002753 err = set_connectable(sk, index, cp, len);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002754 break;
Johan Hedbergf7c68692011-12-15 00:47:36 +02002755 case MGMT_OP_SET_FAST_CONNECTABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002756 err = set_fast_connectable(sk, index, cp, len);
Johan Hedbergf7c68692011-12-15 00:47:36 +02002757 break;
Johan Hedbergc542a062011-01-26 13:11:03 +02002758 case MGMT_OP_SET_PAIRABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002759 err = set_pairable(sk, index, cp, len);
Johan Hedbergc542a062011-01-26 13:11:03 +02002760 break;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02002761 case MGMT_OP_SET_LINK_SECURITY:
2762 err = set_link_security(sk, index, cp, len);
2763 break;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02002764 case MGMT_OP_SET_SSP:
2765 err = set_ssp(sk, index, cp, len);
2766 break;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02002767 case MGMT_OP_SET_HS:
2768 err = set_hs(sk, index, cp, len);
2769 break;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002770 case MGMT_OP_ADD_UUID:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002771 err = add_uuid(sk, index, cp, len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002772 break;
2773 case MGMT_OP_REMOVE_UUID:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002774 err = remove_uuid(sk, index, cp, len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002775 break;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002776 case MGMT_OP_SET_DEV_CLASS:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002777 err = set_dev_class(sk, index, cp, len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002778 break;
Johan Hedberg86742e12011-11-07 23:13:38 +02002779 case MGMT_OP_LOAD_LINK_KEYS:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002780 err = load_link_keys(sk, index, cp, len);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002781 break;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002782 case MGMT_OP_DISCONNECT:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002783 err = disconnect(sk, index, cp, len);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002784 break;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002785 case MGMT_OP_GET_CONNECTIONS:
Szymon Janc8ce62842011-03-01 16:55:32 +01002786 err = get_connections(sk, index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002787 break;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002788 case MGMT_OP_PIN_CODE_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002789 err = pin_code_reply(sk, index, cp, len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002790 break;
2791 case MGMT_OP_PIN_CODE_NEG_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002792 err = pin_code_neg_reply(sk, index, cp, len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002793 break;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002794 case MGMT_OP_SET_IO_CAPABILITY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002795 err = set_io_capability(sk, index, cp, len);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002796 break;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002797 case MGMT_OP_PAIR_DEVICE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002798 err = pair_device(sk, index, cp, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002799 break;
Johan Hedberg28424702012-02-02 04:02:29 +02002800 case MGMT_OP_CANCEL_PAIR_DEVICE:
2801 err = cancel_pair_device(sk, index, buf + sizeof(*hdr), len);
2802 break;
Johan Hedberg124f6e32012-02-09 13:50:12 +02002803 case MGMT_OP_UNPAIR_DEVICE:
2804 err = unpair_device(sk, index, cp, len);
2805 break;
Johan Hedberga5c29682011-02-19 12:05:57 -03002806 case MGMT_OP_USER_CONFIRM_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002807 err = user_confirm_reply(sk, index, cp, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03002808 break;
2809 case MGMT_OP_USER_CONFIRM_NEG_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002810 err = user_confirm_neg_reply(sk, index, cp, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03002811 break;
Brian Gix604086b2011-11-23 08:28:33 -08002812 case MGMT_OP_USER_PASSKEY_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002813 err = user_passkey_reply(sk, index, cp, len);
Brian Gix604086b2011-11-23 08:28:33 -08002814 break;
2815 case MGMT_OP_USER_PASSKEY_NEG_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002816 err = user_passkey_neg_reply(sk, index, cp, len);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002817 break;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002818 case MGMT_OP_SET_LOCAL_NAME:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002819 err = set_local_name(sk, index, cp, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002820 break;
Szymon Jancc35938b2011-03-22 13:12:21 +01002821 case MGMT_OP_READ_LOCAL_OOB_DATA:
2822 err = read_local_oob_data(sk, index);
2823 break;
Szymon Janc2763eda2011-03-22 13:12:22 +01002824 case MGMT_OP_ADD_REMOTE_OOB_DATA:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002825 err = add_remote_oob_data(sk, index, cp, len);
Szymon Janc2763eda2011-03-22 13:12:22 +01002826 break;
2827 case MGMT_OP_REMOVE_REMOTE_OOB_DATA:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002828 err = remove_remote_oob_data(sk, index, cp, len);
Szymon Janc2763eda2011-03-22 13:12:22 +01002829 break;
Johan Hedberg14a53662011-04-27 10:29:56 -04002830 case MGMT_OP_START_DISCOVERY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002831 err = start_discovery(sk, index, cp, len);
Johan Hedberg14a53662011-04-27 10:29:56 -04002832 break;
2833 case MGMT_OP_STOP_DISCOVERY:
Johan Hedbergd9306502012-02-20 23:25:18 +02002834 err = stop_discovery(sk, index, cp, len);
Johan Hedberg14a53662011-04-27 10:29:56 -04002835 break;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002836 case MGMT_OP_CONFIRM_NAME:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002837 err = confirm_name(sk, index, cp, len);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002838 break;
Antti Julku7fbec222011-06-15 12:01:15 +03002839 case MGMT_OP_BLOCK_DEVICE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002840 err = block_device(sk, index, cp, len);
Antti Julku7fbec222011-06-15 12:01:15 +03002841 break;
2842 case MGMT_OP_UNBLOCK_DEVICE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002843 err = unblock_device(sk, index, cp, len);
Antti Julku7fbec222011-06-15 12:01:15 +03002844 break;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002845 case MGMT_OP_LOAD_LONG_TERM_KEYS:
2846 err = load_long_term_keys(sk, index, cp, len);
2847 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002848 default:
Johan Hedberg72a734e2010-12-30 00:38:22 +02002849 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02002850 err = cmd_status(sk, index, opcode,
2851 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002852 break;
2853 }
Johan Hedberg72a734e2010-12-30 00:38:22 +02002854
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002855 if (err < 0)
Johan Hedberg72a734e2010-12-30 00:38:22 +02002856 goto done;
2857
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002858 err = msglen;
2859
2860done:
2861 kfree(buf);
2862 return err;
2863}
2864
Johan Hedbergb24752f2011-11-03 14:40:33 +02002865static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
2866{
2867 u8 *status = data;
2868
2869 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
2870 mgmt_pending_remove(cmd);
2871}
2872
Johan Hedberg744cf192011-11-08 20:40:14 +02002873int mgmt_index_added(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +02002874{
Johan Hedberg744cf192011-11-08 20:40:14 +02002875 return mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02002876}
2877
Johan Hedberg744cf192011-11-08 20:40:14 +02002878int mgmt_index_removed(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +02002879{
Johan Hedbergb24752f2011-11-03 14:40:33 +02002880 u8 status = ENODEV;
2881
Johan Hedberg744cf192011-11-08 20:40:14 +02002882 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002883
Johan Hedberg744cf192011-11-08 20:40:14 +02002884 return mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02002885}
2886
2887struct cmd_lookup {
Johan Hedberg03811012010-12-08 00:21:06 +02002888 struct sock *sk;
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002889 struct hci_dev *hdev;
Johan Hedberg03811012010-12-08 00:21:06 +02002890};
2891
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002892static void settings_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberg03811012010-12-08 00:21:06 +02002893{
Johan Hedberg03811012010-12-08 00:21:06 +02002894 struct cmd_lookup *match = data;
2895
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002896 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02002897
2898 list_del(&cmd->list);
2899
2900 if (match->sk == NULL) {
2901 match->sk = cmd->sk;
2902 sock_hold(match->sk);
2903 }
2904
2905 mgmt_pending_free(cmd);
2906}
2907
Johan Hedberg744cf192011-11-08 20:40:14 +02002908int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg03811012010-12-08 00:21:06 +02002909{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002910 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002911 int err;
Johan Hedberg03811012010-12-08 00:21:06 +02002912
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002913 if (!test_bit(HCI_MGMT, &hdev->dev_flags))
2914 return 0;
2915
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002916 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
Johan Hedberg03811012010-12-08 00:21:06 +02002917
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002918 if (powered) {
2919 u8 scan = 0;
2920
2921 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
2922 scan |= SCAN_PAGE;
2923 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
2924 scan |= SCAN_INQUIRY;
2925
2926 if (scan)
2927 hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
2928 } else {
Johan Hedbergb24752f2011-11-03 14:40:33 +02002929 u8 status = ENETDOWN;
Johan Hedberg744cf192011-11-08 20:40:14 +02002930 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002931 }
2932
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02002933 err = new_settings(hdev, match.sk);
Johan Hedberg03811012010-12-08 00:21:06 +02002934
2935 if (match.sk)
2936 sock_put(match.sk);
2937
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002938 return err;
Johan Hedberg03811012010-12-08 00:21:06 +02002939}
2940
Johan Hedberg744cf192011-11-08 20:40:14 +02002941int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg03811012010-12-08 00:21:06 +02002942{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002943 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002944 bool changed = false;
2945 int err = 0;
Johan Hedberg03811012010-12-08 00:21:06 +02002946
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002947 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp, &match);
Johan Hedberg03811012010-12-08 00:21:06 +02002948
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002949 if (discoverable) {
2950 if (!test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
2951 changed = true;
2952 } else {
2953 if (test_and_clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
2954 changed = true;
2955 }
Johan Hedberg03811012010-12-08 00:21:06 +02002956
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02002957 if (changed)
2958 err = new_settings(hdev, match.sk);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002959
Johan Hedberg03811012010-12-08 00:21:06 +02002960 if (match.sk)
2961 sock_put(match.sk);
2962
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002963 return err;
Johan Hedberg03811012010-12-08 00:21:06 +02002964}
2965
Johan Hedberg744cf192011-11-08 20:40:14 +02002966int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg03811012010-12-08 00:21:06 +02002967{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002968 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002969 bool changed = false;
2970 int err = 0;
Johan Hedberg03811012010-12-08 00:21:06 +02002971
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002972 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev, settings_rsp,
2973 &match);
Johan Hedberg03811012010-12-08 00:21:06 +02002974
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002975 if (connectable) {
2976 if (!test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags))
2977 changed = true;
2978 } else {
2979 if (test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags))
2980 changed = true;
2981 }
Johan Hedberg03811012010-12-08 00:21:06 +02002982
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02002983 if (changed)
2984 err = new_settings(hdev, match.sk);
Johan Hedberg03811012010-12-08 00:21:06 +02002985
2986 if (match.sk)
2987 sock_put(match.sk);
2988
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002989 return err;
Johan Hedberg03811012010-12-08 00:21:06 +02002990}
2991
Johan Hedberg744cf192011-11-08 20:40:14 +02002992int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002993{
Johan Hedbergca69b792011-11-11 18:10:00 +02002994 u8 mgmt_err = mgmt_status(status);
2995
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002996 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02002997 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Johan Hedbergca69b792011-11-11 18:10:00 +02002998 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002999
3000 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02003001 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Johan Hedbergca69b792011-11-11 18:10:00 +02003002 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003003
3004 return 0;
3005}
3006
Johan Hedberg744cf192011-11-08 20:40:14 +02003007int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
3008 u8 persistent)
Johan Hedberg03811012010-12-08 00:21:06 +02003009{
Johan Hedberg86742e12011-11-07 23:13:38 +02003010 struct mgmt_ev_new_link_key ev;
Johan Hedberg03811012010-12-08 00:21:06 +02003011
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003012 memset(&ev, 0, sizeof(ev));
Johan Hedberg03811012010-12-08 00:21:06 +02003013
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003014 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02003015 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
3016 ev.key.addr.type = MGMT_ADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003017 ev.key.type = key->type;
3018 memcpy(ev.key.val, key->val, 16);
3019 ev.key.pin_len = key->pin_len;
Johan Hedberg03811012010-12-08 00:21:06 +02003020
Johan Hedberg744cf192011-11-08 20:40:14 +02003021 return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02003022}
Johan Hedbergf7520542011-01-20 12:34:39 +02003023
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003024int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
3025{
3026 struct mgmt_ev_new_long_term_key ev;
3027
3028 memset(&ev, 0, sizeof(ev));
3029
3030 ev.store_hint = persistent;
3031 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
3032 ev.key.addr.type = key->bdaddr_type;
3033 ev.key.authenticated = key->authenticated;
3034 ev.key.enc_size = key->enc_size;
3035 ev.key.ediv = key->ediv;
3036
3037 if (key->type == HCI_SMP_LTK)
3038 ev.key.master = 1;
3039
3040 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
3041 memcpy(ev.key.val, key->val, sizeof(key->val));
3042
3043 return mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev,
3044 &ev, sizeof(ev), NULL);
3045}
3046
Johan Hedbergafc747a2012-01-15 18:11:07 +02003047int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Johan Hedbergb644ba32012-01-17 21:48:47 +02003048 u8 addr_type, u8 *name, u8 name_len,
3049 u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02003050{
Johan Hedbergb644ba32012-01-17 21:48:47 +02003051 char buf[512];
3052 struct mgmt_ev_device_connected *ev = (void *) buf;
3053 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02003054
Johan Hedbergb644ba32012-01-17 21:48:47 +02003055 bacpy(&ev->addr.bdaddr, bdaddr);
3056 ev->addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02003057
Johan Hedbergb644ba32012-01-17 21:48:47 +02003058 if (name_len > 0)
3059 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
3060 name, name_len);
3061
3062 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
3063 eir_len = eir_append_data(&ev->eir[eir_len], eir_len,
3064 EIR_CLASS_OF_DEV, dev_class, 3);
3065
3066 put_unaligned_le16(eir_len, &ev->eir_len);
3067
3068 return mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
3069 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02003070}
3071
Johan Hedberg8962ee72011-01-20 12:40:27 +02003072static void disconnect_rsp(struct pending_cmd *cmd, void *data)
3073{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01003074 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003075 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02003076 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003077
Johan Hedberg88c3df12012-02-09 14:27:38 +02003078 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3079 rp.addr.type = cp->addr.type;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003080
Johan Hedbergaee9b212012-02-18 15:07:59 +02003081 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, 0, &rp,
3082 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003083
3084 *sk = cmd->sk;
3085 sock_hold(*sk);
3086
Johan Hedberga664b5b2011-02-19 12:06:02 -03003087 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003088}
3089
Johan Hedberg124f6e32012-02-09 13:50:12 +02003090static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02003091{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003092 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02003093 struct mgmt_cp_unpair_device *cp = cmd->param;
3094 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02003095
3096 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02003097 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3098 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02003099
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003100 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
3101
Johan Hedbergaee9b212012-02-18 15:07:59 +02003102 cmd_complete(cmd->sk, cmd->index, cmd->opcode, 0, &rp, sizeof(rp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02003103
3104 mgmt_pending_remove(cmd);
3105}
3106
Johan Hedbergafc747a2012-01-15 18:11:07 +02003107int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
3108 u8 link_type, u8 addr_type)
Johan Hedbergf7520542011-01-20 12:34:39 +02003109{
Johan Hedberg4c659c32011-11-07 23:13:39 +02003110 struct mgmt_addr_info ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003111 struct sock *sk = NULL;
3112 int err;
3113
Johan Hedberg744cf192011-11-08 20:40:14 +02003114 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02003115
Johan Hedbergf7520542011-01-20 12:34:39 +02003116 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02003117 ev.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02003118
Johan Hedbergafc747a2012-01-15 18:11:07 +02003119 err = mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev),
3120 sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003121
3122 if (sk)
3123 sock_put(sk);
3124
Johan Hedberg124f6e32012-02-09 13:50:12 +02003125 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003126 hdev);
Johan Hedberga8a1d192011-11-10 15:54:38 +02003127
Johan Hedberg8962ee72011-01-20 12:40:27 +02003128 return err;
3129}
3130
Johan Hedberg88c3df12012-02-09 14:27:38 +02003131int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
3132 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02003133{
Johan Hedberg88c3df12012-02-09 14:27:38 +02003134 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003135 struct pending_cmd *cmd;
3136 int err;
3137
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003138 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003139 if (!cmd)
3140 return -ENOENT;
3141
Johan Hedberg88c3df12012-02-09 14:27:38 +02003142 bacpy(&rp.addr.bdaddr, bdaddr);
3143 rp.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02003144
Johan Hedberg88c3df12012-02-09 14:27:38 +02003145 err = cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
Johan Hedbergaee9b212012-02-18 15:07:59 +02003146 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003147
Johan Hedberga664b5b2011-02-19 12:06:02 -03003148 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003149
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003150 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
3151 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003152 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02003153}
Johan Hedberg17d5c042011-01-22 06:09:08 +02003154
Johan Hedberg48264f02011-11-09 13:58:58 +02003155int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
3156 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02003157{
3158 struct mgmt_ev_connect_failed ev;
3159
Johan Hedberg4c659c32011-11-07 23:13:39 +02003160 bacpy(&ev.addr.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02003161 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003162 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003163
Johan Hedberg744cf192011-11-08 20:40:14 +02003164 return mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003165}
Johan Hedberg980e1a52011-01-22 06:10:07 +02003166
Johan Hedberg744cf192011-11-08 20:40:14 +02003167int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003168{
3169 struct mgmt_ev_pin_code_request ev;
3170
Johan Hedbergd8457692012-02-17 14:24:57 +02003171 bacpy(&ev.addr.bdaddr, bdaddr);
3172 ev.addr.type = MGMT_ADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02003173 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003174
Johan Hedberg744cf192011-11-08 20:40:14 +02003175 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01003176 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003177}
3178
Johan Hedberg744cf192011-11-08 20:40:14 +02003179int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3180 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003181{
3182 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003183 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003184 int err;
3185
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003186 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003187 if (!cmd)
3188 return -ENOENT;
3189
Johan Hedbergd8457692012-02-17 14:24:57 +02003190 bacpy(&rp.addr.bdaddr, bdaddr);
3191 rp.addr.type = MGMT_ADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003192
Johan Hedbergaee9b212012-02-18 15:07:59 +02003193 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
3194 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003195
Johan Hedberga664b5b2011-02-19 12:06:02 -03003196 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003197
3198 return err;
3199}
3200
Johan Hedberg744cf192011-11-08 20:40:14 +02003201int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3202 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003203{
3204 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003205 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003206 int err;
3207
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003208 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003209 if (!cmd)
3210 return -ENOENT;
3211
Johan Hedbergd8457692012-02-17 14:24:57 +02003212 bacpy(&rp.addr.bdaddr, bdaddr);
3213 rp.addr.type = MGMT_ADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003214
Johan Hedbergaee9b212012-02-18 15:07:59 +02003215 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
3216 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003217
Johan Hedberga664b5b2011-02-19 12:06:02 -03003218 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003219
3220 return err;
3221}
Johan Hedberga5c29682011-02-19 12:05:57 -03003222
Johan Hedberg744cf192011-11-08 20:40:14 +02003223int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003224 u8 link_type, u8 addr_type, __le32 value,
3225 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03003226{
3227 struct mgmt_ev_user_confirm_request ev;
3228
Johan Hedberg744cf192011-11-08 20:40:14 +02003229 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03003230
Johan Hedberg272d90d2012-02-09 15:26:12 +02003231 bacpy(&ev.addr.bdaddr, bdaddr);
3232 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07003233 ev.confirm_hint = confirm_hint;
Johan Hedberga5c29682011-02-19 12:05:57 -03003234 put_unaligned_le32(value, &ev.value);
3235
Johan Hedberg744cf192011-11-08 20:40:14 +02003236 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01003237 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03003238}
3239
Johan Hedberg272d90d2012-02-09 15:26:12 +02003240int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
3241 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08003242{
3243 struct mgmt_ev_user_passkey_request ev;
3244
3245 BT_DBG("%s", hdev->name);
3246
Johan Hedberg272d90d2012-02-09 15:26:12 +02003247 bacpy(&ev.addr.bdaddr, bdaddr);
3248 ev.addr.type = link_to_mgmt(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08003249
3250 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
3251 NULL);
3252}
3253
Brian Gix0df4c182011-11-16 13:53:13 -08003254static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003255 u8 link_type, u8 addr_type, u8 status,
3256 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03003257{
3258 struct pending_cmd *cmd;
3259 struct mgmt_rp_user_confirm_reply rp;
3260 int err;
3261
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003262 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03003263 if (!cmd)
3264 return -ENOENT;
3265
Johan Hedberg272d90d2012-02-09 15:26:12 +02003266 bacpy(&rp.addr.bdaddr, bdaddr);
3267 rp.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergaee9b212012-02-18 15:07:59 +02003268 err = cmd_complete(cmd->sk, hdev->id, opcode, mgmt_status(status),
3269 &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03003270
Johan Hedberga664b5b2011-02-19 12:06:02 -03003271 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03003272
3273 return err;
3274}
3275
Johan Hedberg744cf192011-11-08 20:40:14 +02003276int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003277 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003278{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003279 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3280 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003281}
3282
Johan Hedberg272d90d2012-02-09 15:26:12 +02003283int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3284 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003285{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003286 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3287 status, MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003288}
Johan Hedberg2a611692011-02-19 12:06:00 -03003289
Brian Gix604086b2011-11-23 08:28:33 -08003290int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003291 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003292{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003293 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3294 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003295}
3296
Johan Hedberg272d90d2012-02-09 15:26:12 +02003297int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3298 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003299{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003300 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3301 status, MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003302}
3303
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003304int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
3305 u8 addr_type, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03003306{
3307 struct mgmt_ev_auth_failed ev;
3308
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003309 bacpy(&ev.addr.bdaddr, bdaddr);
3310 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003311 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03003312
Johan Hedberg744cf192011-11-08 20:40:14 +02003313 return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03003314}
Johan Hedbergb312b1612011-03-16 14:29:37 +02003315
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003316int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
3317{
3318 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003319 int err;
3320
3321 if (status) {
3322 u8 mgmt_err = mgmt_status(status);
3323 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
3324 cmd_status_rsp, &mgmt_err);
3325 return 0;
3326 }
3327
3328 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
3329 &match);
3330
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003331 err = new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003332
3333 if (match.sk)
3334 sock_put(match.sk);
3335
3336 return err;
3337}
3338
Johan Hedbergcacaf522012-02-21 00:52:42 +02003339static int clear_eir(struct hci_dev *hdev)
3340{
3341 struct hci_cp_write_eir cp;
3342
3343 if (!(hdev->features[6] & LMP_EXT_INQ))
3344 return 0;
3345
3346 memset(&cp, 0, sizeof(cp));
3347
3348 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
3349}
3350
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003351int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 status)
3352{
3353 struct cmd_lookup match = { NULL, hdev };
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003354 int err;
3355
3356 if (status) {
3357 u8 mgmt_err = mgmt_status(status);
3358 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev,
3359 cmd_status_rsp, &mgmt_err);
3360 return 0;
3361 }
3362
3363 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
3364
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003365 err = new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003366
Johan Hedbergcacaf522012-02-21 00:52:42 +02003367 if (match.sk) {
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003368 sock_put(match.sk);
3369
Johan Hedbergcacaf522012-02-21 00:52:42 +02003370 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3371 update_eir(hdev);
3372 else
3373 clear_eir(hdev);
3374 }
3375
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003376 return err;
3377}
3378
Johan Hedberg744cf192011-11-08 20:40:14 +02003379int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02003380{
3381 struct pending_cmd *cmd;
3382 struct mgmt_cp_set_local_name ev;
3383 int err;
3384
3385 memset(&ev, 0, sizeof(ev));
3386 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
3387
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003388 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003389 if (!cmd)
3390 goto send_event;
3391
3392 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02003393 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
Johan Hedbergca69b792011-11-11 18:10:00 +02003394 mgmt_status(status));
Johan Hedbergb312b1612011-03-16 14:29:37 +02003395 goto failed;
3396 }
3397
Johan Hedberg744cf192011-11-08 20:40:14 +02003398 update_eir(hdev);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03003399
Johan Hedbergaee9b212012-02-18 15:07:59 +02003400 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0, &ev,
Johan Hedbergb312b1612011-03-16 14:29:37 +02003401 sizeof(ev));
3402 if (err < 0)
3403 goto failed;
3404
3405send_event:
Johan Hedberg744cf192011-11-08 20:40:14 +02003406 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
Johan Hedbergb312b1612011-03-16 14:29:37 +02003407 cmd ? cmd->sk : NULL);
3408
3409failed:
3410 if (cmd)
3411 mgmt_pending_remove(cmd);
3412 return err;
3413}
Szymon Jancc35938b2011-03-22 13:12:21 +01003414
Johan Hedberg744cf192011-11-08 20:40:14 +02003415int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
3416 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01003417{
3418 struct pending_cmd *cmd;
3419 int err;
3420
Johan Hedberg744cf192011-11-08 20:40:14 +02003421 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01003422
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003423 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003424 if (!cmd)
3425 return -ENOENT;
3426
3427 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02003428 err = cmd_status(cmd->sk, hdev->id,
Johan Hedbergca69b792011-11-11 18:10:00 +02003429 MGMT_OP_READ_LOCAL_OOB_DATA,
3430 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01003431 } else {
3432 struct mgmt_rp_read_local_oob_data rp;
3433
3434 memcpy(rp.hash, hash, sizeof(rp.hash));
3435 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
3436
Johan Hedberg744cf192011-11-08 20:40:14 +02003437 err = cmd_complete(cmd->sk, hdev->id,
3438 MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergaee9b212012-02-18 15:07:59 +02003439 0, &rp, sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01003440 }
3441
3442 mgmt_pending_remove(cmd);
3443
3444 return err;
3445}
Johan Hedberge17acd42011-03-30 23:57:16 +03003446
Johan Hedberg48264f02011-11-09 13:58:58 +02003447int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Johan Hedberg561aafb2012-01-04 13:31:59 +02003448 u8 addr_type, u8 *dev_class, s8 rssi,
Johan Hedberge319d2e2012-01-15 19:51:59 +02003449 u8 cfm_name, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03003450{
Johan Hedberge319d2e2012-01-15 19:51:59 +02003451 char buf[512];
3452 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02003453 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03003454
Johan Hedberg1dc06092012-01-15 21:01:23 +02003455 /* Leave 5 bytes for a potential CoD field */
3456 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Andre Guedes7d262f82012-01-10 18:20:49 -03003457 return -EINVAL;
3458
Johan Hedberg1dc06092012-01-15 21:01:23 +02003459 memset(buf, 0, sizeof(buf));
3460
Johan Hedberge319d2e2012-01-15 19:51:59 +02003461 bacpy(&ev->addr.bdaddr, bdaddr);
3462 ev->addr.type = link_to_mgmt(link_type, addr_type);
3463 ev->rssi = rssi;
3464 ev->confirm_name = cfm_name;
Johan Hedberge17acd42011-03-30 23:57:16 +03003465
Johan Hedberg1dc06092012-01-15 21:01:23 +02003466 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02003467 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03003468
Johan Hedberg1dc06092012-01-15 21:01:23 +02003469 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
3470 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
3471 dev_class, 3);
3472
3473 put_unaligned_le16(eir_len, &ev->eir_len);
3474
3475 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03003476
Johan Hedberge319d2e2012-01-15 19:51:59 +02003477 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03003478}
Johan Hedberga88a9652011-03-30 13:18:12 +03003479
Johan Hedbergb644ba32012-01-17 21:48:47 +02003480int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
3481 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03003482{
Johan Hedbergb644ba32012-01-17 21:48:47 +02003483 struct mgmt_ev_device_found *ev;
3484 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
3485 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03003486
Johan Hedbergb644ba32012-01-17 21:48:47 +02003487 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03003488
Johan Hedbergb644ba32012-01-17 21:48:47 +02003489 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03003490
Johan Hedbergb644ba32012-01-17 21:48:47 +02003491 bacpy(&ev->addr.bdaddr, bdaddr);
3492 ev->addr.type = link_to_mgmt(link_type, addr_type);
3493 ev->rssi = rssi;
3494
3495 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
3496 name_len);
3497
3498 put_unaligned_le16(eir_len, &ev->eir_len);
3499
Johan Hedberg053c7e02012-02-04 00:06:00 +02003500 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev,
3501 sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03003502}
Johan Hedberg314b2382011-04-27 10:29:57 -04003503
Andre Guedes7a135102011-11-09 17:14:25 -03003504int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
Johan Hedberg164a6e72011-11-01 17:06:44 +02003505{
3506 struct pending_cmd *cmd;
Johan Hedbergf808e162012-02-19 12:52:07 +02003507 u8 type;
Johan Hedberg164a6e72011-11-01 17:06:44 +02003508 int err;
3509
Andre Guedes203159d2012-02-13 15:41:01 -03003510 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3511
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003512 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003513 if (!cmd)
3514 return -ENOENT;
3515
Johan Hedbergf808e162012-02-19 12:52:07 +02003516 type = hdev->discovery.type;
3517
3518 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
3519 &type, sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02003520 mgmt_pending_remove(cmd);
3521
3522 return err;
3523}
3524
Andre Guedese6d465c2011-11-09 17:14:26 -03003525int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
3526{
3527 struct pending_cmd *cmd;
3528 int err;
3529
3530 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
3531 if (!cmd)
3532 return -ENOENT;
3533
Johan Hedbergd9306502012-02-20 23:25:18 +02003534 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
3535 &hdev->discovery.type,
3536 sizeof(hdev->discovery.type));
Johan Hedberg03811012010-12-08 00:21:06 +02003537 mgmt_pending_remove(cmd);
3538
3539 return err;
3540}
Johan Hedberg314b2382011-04-27 10:29:57 -04003541
Johan Hedberg744cf192011-11-08 20:40:14 +02003542int mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04003543{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02003544 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02003545 struct pending_cmd *cmd;
3546
Andre Guedes343fb142011-11-22 17:14:19 -03003547 BT_DBG("%s discovering %u", hdev->name, discovering);
3548
Johan Hedberg164a6e72011-11-01 17:06:44 +02003549 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003550 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003551 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003552 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003553
3554 if (cmd != NULL) {
Johan Hedbergf808e162012-02-19 12:52:07 +02003555 u8 type = hdev->discovery.type;
3556
Johan Hedbergd9306502012-02-20 23:25:18 +02003557 cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0,
Johan Hedbergf808e162012-02-19 12:52:07 +02003558 &type, sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02003559 mgmt_pending_remove(cmd);
3560 }
3561
Johan Hedbergf963e8e2012-02-20 23:30:44 +02003562 memset(&ev, 0, sizeof(ev));
3563 ev.type = hdev->discovery.type;
3564 ev.discovering = discovering;
3565
3566 return mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04003567}
Antti Julku5e762442011-08-25 16:48:02 +03003568
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003569int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003570{
3571 struct pending_cmd *cmd;
3572 struct mgmt_ev_device_blocked ev;
3573
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003574 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003575
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003576 bacpy(&ev.addr.bdaddr, bdaddr);
3577 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003578
Johan Hedberg744cf192011-11-08 20:40:14 +02003579 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
3580 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003581}
3582
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003583int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003584{
3585 struct pending_cmd *cmd;
3586 struct mgmt_ev_device_unblocked ev;
3587
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003588 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003589
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003590 bacpy(&ev.addr.bdaddr, bdaddr);
3591 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003592
Johan Hedberg744cf192011-11-08 20:40:14 +02003593 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
3594 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003595}
Marcel Holtmannd7b7e792012-02-20 21:47:49 +01003596
3597module_param(enable_hs, bool, 0644);
3598MODULE_PARM_DESC(enable_hs, "Enable High Speed support");
3599
3600module_param(enable_le, bool, 0644);
3601MODULE_PARM_DESC(enable_le, "Enable Low Energy support");