blob: 8b4df0473ec3bcc2ff660d934b615f43d9351d20 [file] [log] [blame]
Johan Hedberg03811012010-12-08 00:21:06 +02001/*
2 BlueZ - Bluetooth protocol stack for Linux
Johan Hedbergea585ab2012-02-17 14:50:39 +02003
Johan Hedberg03811012010-12-08 00:21:06 +02004 Copyright (C) 2010 Nokia Corporation
Johan Hedbergea585ab2012-02-17 14:50:39 +02005 Copyright (C) 2011-2012 Intel Corporation
Johan Hedberg03811012010-12-08 00:21:06 +02006
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License version 2 as
9 published by the Free Software Foundation;
10
11 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
12 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
13 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
14 IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
15 CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
16 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19
20 ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
21 COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
22 SOFTWARE IS DISCLAIMED.
23*/
24
25/* Bluetooth HCI Management interface */
26
Johan Hedbergca69b792011-11-11 18:10:00 +020027#include <linux/kernel.h>
Szymon Janc72359752011-02-17 14:16:32 +010028#include <linux/uaccess.h>
Paul Gortmaker3a9a2312011-05-27 09:12:25 -040029#include <linux/module.h>
Johan Hedberg03811012010-12-08 00:21:06 +020030#include <asm/unaligned.h>
31
32#include <net/bluetooth/bluetooth.h>
33#include <net/bluetooth/hci_core.h>
34#include <net/bluetooth/mgmt.h>
Brian Gix5fe57d92011-12-21 16:12:13 -080035#include <net/bluetooth/smp.h>
Johan Hedberg03811012010-12-08 00:21:06 +020036
Marcel Holtmannd7b7e792012-02-20 21:47:49 +010037bool enable_hs;
38bool enable_le;
39
Johan Hedberg2da9c552012-02-17 14:39:28 +020040#define MGMT_VERSION 1
41#define MGMT_REVISION 0
Johan Hedberg02d98122010-12-13 21:07:04 +020042
Johan Hedberge70bb2e2012-02-13 16:59:33 +020043static const u16 mgmt_commands[] = {
44 MGMT_OP_READ_INDEX_LIST,
45 MGMT_OP_READ_INFO,
46 MGMT_OP_SET_POWERED,
47 MGMT_OP_SET_DISCOVERABLE,
48 MGMT_OP_SET_CONNECTABLE,
49 MGMT_OP_SET_FAST_CONNECTABLE,
50 MGMT_OP_SET_PAIRABLE,
51 MGMT_OP_SET_LINK_SECURITY,
52 MGMT_OP_SET_SSP,
53 MGMT_OP_SET_HS,
54 MGMT_OP_SET_LE,
55 MGMT_OP_SET_DEV_CLASS,
56 MGMT_OP_SET_LOCAL_NAME,
57 MGMT_OP_ADD_UUID,
58 MGMT_OP_REMOVE_UUID,
59 MGMT_OP_LOAD_LINK_KEYS,
60 MGMT_OP_LOAD_LONG_TERM_KEYS,
61 MGMT_OP_DISCONNECT,
62 MGMT_OP_GET_CONNECTIONS,
63 MGMT_OP_PIN_CODE_REPLY,
64 MGMT_OP_PIN_CODE_NEG_REPLY,
65 MGMT_OP_SET_IO_CAPABILITY,
66 MGMT_OP_PAIR_DEVICE,
67 MGMT_OP_CANCEL_PAIR_DEVICE,
68 MGMT_OP_UNPAIR_DEVICE,
69 MGMT_OP_USER_CONFIRM_REPLY,
70 MGMT_OP_USER_CONFIRM_NEG_REPLY,
71 MGMT_OP_USER_PASSKEY_REPLY,
72 MGMT_OP_USER_PASSKEY_NEG_REPLY,
73 MGMT_OP_READ_LOCAL_OOB_DATA,
74 MGMT_OP_ADD_REMOTE_OOB_DATA,
75 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
76 MGMT_OP_START_DISCOVERY,
77 MGMT_OP_STOP_DISCOVERY,
78 MGMT_OP_CONFIRM_NAME,
79 MGMT_OP_BLOCK_DEVICE,
80 MGMT_OP_UNBLOCK_DEVICE,
81};
82
83static const u16 mgmt_events[] = {
84 MGMT_EV_CONTROLLER_ERROR,
85 MGMT_EV_INDEX_ADDED,
86 MGMT_EV_INDEX_REMOVED,
87 MGMT_EV_NEW_SETTINGS,
88 MGMT_EV_CLASS_OF_DEV_CHANGED,
89 MGMT_EV_LOCAL_NAME_CHANGED,
90 MGMT_EV_NEW_LINK_KEY,
91 MGMT_EV_NEW_LONG_TERM_KEY,
92 MGMT_EV_DEVICE_CONNECTED,
93 MGMT_EV_DEVICE_DISCONNECTED,
94 MGMT_EV_CONNECT_FAILED,
95 MGMT_EV_PIN_CODE_REQUEST,
96 MGMT_EV_USER_CONFIRM_REQUEST,
97 MGMT_EV_USER_PASSKEY_REQUEST,
98 MGMT_EV_AUTH_FAILED,
99 MGMT_EV_DEVICE_FOUND,
100 MGMT_EV_DISCOVERING,
101 MGMT_EV_DEVICE_BLOCKED,
102 MGMT_EV_DEVICE_UNBLOCKED,
103 MGMT_EV_DEVICE_UNPAIRED,
104};
105
Andre Guedes3fd24152012-02-03 17:48:01 -0300106/*
107 * These LE scan and inquiry parameters were chosen according to LE General
108 * Discovery Procedure specification.
109 */
110#define LE_SCAN_TYPE 0x01
111#define LE_SCAN_WIN 0x12
112#define LE_SCAN_INT 0x12
113#define LE_SCAN_TIMEOUT_LE_ONLY 10240 /* TGAP(gen_disc_scan_min) */
Andre Guedes5e0452c2012-02-17 20:39:38 -0300114#define LE_SCAN_TIMEOUT_BREDR_LE 5120 /* TGAP(100)/2 */
Andre Guedes3fd24152012-02-03 17:48:01 -0300115
Andre Guedese8777522012-02-03 17:48:02 -0300116#define INQUIRY_LEN_BREDR 0x08 /* TGAP(100) */
Andre Guedes5e0452c2012-02-17 20:39:38 -0300117#define INQUIRY_LEN_BREDR_LE 0x04 /* TGAP(100)/2 */
Andre Guedes2519a1f2011-11-07 11:45:24 -0300118
Johan Hedberg7d785252011-12-15 00:47:39 +0200119#define SERVICE_CACHE_TIMEOUT (5 * 1000)
120
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200121#define hdev_is_powered(hdev) (test_bit(HCI_UP, &hdev->flags) && \
122 !test_bit(HCI_AUTO_OFF, &hdev->dev_flags))
123
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200124struct pending_cmd {
125 struct list_head list;
Johan Hedbergfc2f4b12011-11-09 13:58:56 +0200126 u16 opcode;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200127 int index;
Szymon Jancc68fb7f2011-03-22 13:12:19 +0100128 void *param;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200129 struct sock *sk;
Johan Hedberge9a416b2011-02-19 12:05:56 -0300130 void *user_data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200131};
132
Johan Hedbergca69b792011-11-11 18:10:00 +0200133/* HCI to MGMT error code conversion table */
134static u8 mgmt_status_table[] = {
135 MGMT_STATUS_SUCCESS,
136 MGMT_STATUS_UNKNOWN_COMMAND, /* Unknown Command */
137 MGMT_STATUS_NOT_CONNECTED, /* No Connection */
138 MGMT_STATUS_FAILED, /* Hardware Failure */
139 MGMT_STATUS_CONNECT_FAILED, /* Page Timeout */
140 MGMT_STATUS_AUTH_FAILED, /* Authentication Failed */
141 MGMT_STATUS_NOT_PAIRED, /* PIN or Key Missing */
142 MGMT_STATUS_NO_RESOURCES, /* Memory Full */
143 MGMT_STATUS_TIMEOUT, /* Connection Timeout */
144 MGMT_STATUS_NO_RESOURCES, /* Max Number of Connections */
145 MGMT_STATUS_NO_RESOURCES, /* Max Number of SCO Connections */
146 MGMT_STATUS_ALREADY_CONNECTED, /* ACL Connection Exists */
147 MGMT_STATUS_BUSY, /* Command Disallowed */
148 MGMT_STATUS_NO_RESOURCES, /* Rejected Limited Resources */
149 MGMT_STATUS_REJECTED, /* Rejected Security */
150 MGMT_STATUS_REJECTED, /* Rejected Personal */
151 MGMT_STATUS_TIMEOUT, /* Host Timeout */
152 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Feature */
153 MGMT_STATUS_INVALID_PARAMS, /* Invalid Parameters */
154 MGMT_STATUS_DISCONNECTED, /* OE User Ended Connection */
155 MGMT_STATUS_NO_RESOURCES, /* OE Low Resources */
156 MGMT_STATUS_DISCONNECTED, /* OE Power Off */
157 MGMT_STATUS_DISCONNECTED, /* Connection Terminated */
158 MGMT_STATUS_BUSY, /* Repeated Attempts */
159 MGMT_STATUS_REJECTED, /* Pairing Not Allowed */
160 MGMT_STATUS_FAILED, /* Unknown LMP PDU */
161 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Remote Feature */
162 MGMT_STATUS_REJECTED, /* SCO Offset Rejected */
163 MGMT_STATUS_REJECTED, /* SCO Interval Rejected */
164 MGMT_STATUS_REJECTED, /* Air Mode Rejected */
165 MGMT_STATUS_INVALID_PARAMS, /* Invalid LMP Parameters */
166 MGMT_STATUS_FAILED, /* Unspecified Error */
167 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported LMP Parameter Value */
168 MGMT_STATUS_FAILED, /* Role Change Not Allowed */
169 MGMT_STATUS_TIMEOUT, /* LMP Response Timeout */
170 MGMT_STATUS_FAILED, /* LMP Error Transaction Collision */
171 MGMT_STATUS_FAILED, /* LMP PDU Not Allowed */
172 MGMT_STATUS_REJECTED, /* Encryption Mode Not Accepted */
173 MGMT_STATUS_FAILED, /* Unit Link Key Used */
174 MGMT_STATUS_NOT_SUPPORTED, /* QoS Not Supported */
175 MGMT_STATUS_TIMEOUT, /* Instant Passed */
176 MGMT_STATUS_NOT_SUPPORTED, /* Pairing Not Supported */
177 MGMT_STATUS_FAILED, /* Transaction Collision */
178 MGMT_STATUS_INVALID_PARAMS, /* Unacceptable Parameter */
179 MGMT_STATUS_REJECTED, /* QoS Rejected */
180 MGMT_STATUS_NOT_SUPPORTED, /* Classification Not Supported */
181 MGMT_STATUS_REJECTED, /* Insufficient Security */
182 MGMT_STATUS_INVALID_PARAMS, /* Parameter Out Of Range */
183 MGMT_STATUS_BUSY, /* Role Switch Pending */
184 MGMT_STATUS_FAILED, /* Slot Violation */
185 MGMT_STATUS_FAILED, /* Role Switch Failed */
186 MGMT_STATUS_INVALID_PARAMS, /* EIR Too Large */
187 MGMT_STATUS_NOT_SUPPORTED, /* Simple Pairing Not Supported */
188 MGMT_STATUS_BUSY, /* Host Busy Pairing */
189 MGMT_STATUS_REJECTED, /* Rejected, No Suitable Channel */
190 MGMT_STATUS_BUSY, /* Controller Busy */
191 MGMT_STATUS_INVALID_PARAMS, /* Unsuitable Connection Interval */
192 MGMT_STATUS_TIMEOUT, /* Directed Advertising Timeout */
193 MGMT_STATUS_AUTH_FAILED, /* Terminated Due to MIC Failure */
194 MGMT_STATUS_CONNECT_FAILED, /* Connection Establishment Failed */
195 MGMT_STATUS_CONNECT_FAILED, /* MAC Connection Failed */
196};
197
198static u8 mgmt_status(u8 hci_status)
199{
200 if (hci_status < ARRAY_SIZE(mgmt_status_table))
201 return mgmt_status_table[hci_status];
202
203 return MGMT_STATUS_FAILED;
204}
205
Szymon Janc4e51eae2011-02-25 19:05:48 +0100206static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200207{
208 struct sk_buff *skb;
209 struct mgmt_hdr *hdr;
210 struct mgmt_ev_cmd_status *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300211 int err;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200212
Szymon Janc34eb5252011-02-28 14:10:08 +0100213 BT_DBG("sock %p, index %u, cmd %u, status %u", sk, index, cmd, status);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200214
215 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_ATOMIC);
216 if (!skb)
217 return -ENOMEM;
218
219 hdr = (void *) skb_put(skb, sizeof(*hdr));
220
221 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_STATUS);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100222 hdr->index = cpu_to_le16(index);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200223 hdr->len = cpu_to_le16(sizeof(*ev));
224
225 ev = (void *) skb_put(skb, sizeof(*ev));
226 ev->status = status;
227 put_unaligned_le16(cmd, &ev->opcode);
228
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300229 err = sock_queue_rcv_skb(sk, skb);
230 if (err < 0)
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200231 kfree_skb(skb);
232
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300233 return err;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200234}
235
Johan Hedbergaee9b212012-02-18 15:07:59 +0200236static int cmd_complete(struct sock *sk, u16 index, u16 cmd, u8 status,
237 void *rp, size_t rp_len)
Johan Hedberg02d98122010-12-13 21:07:04 +0200238{
239 struct sk_buff *skb;
240 struct mgmt_hdr *hdr;
241 struct mgmt_ev_cmd_complete *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300242 int err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200243
244 BT_DBG("sock %p", sk);
245
Johan Hedberga38528f2011-01-22 06:46:43 +0200246 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + rp_len, GFP_ATOMIC);
Johan Hedberg02d98122010-12-13 21:07:04 +0200247 if (!skb)
248 return -ENOMEM;
249
250 hdr = (void *) skb_put(skb, sizeof(*hdr));
Johan Hedberga38528f2011-01-22 06:46:43 +0200251
Johan Hedberg02d98122010-12-13 21:07:04 +0200252 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100253 hdr->index = cpu_to_le16(index);
Johan Hedberga38528f2011-01-22 06:46:43 +0200254 hdr->len = cpu_to_le16(sizeof(*ev) + rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200255
Johan Hedberga38528f2011-01-22 06:46:43 +0200256 ev = (void *) skb_put(skb, sizeof(*ev) + rp_len);
257 put_unaligned_le16(cmd, &ev->opcode);
Johan Hedbergaee9b212012-02-18 15:07:59 +0200258 ev->status = status;
Szymon Janc8020c162011-02-28 14:09:50 +0100259
260 if (rp)
261 memcpy(ev->data, rp, rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200262
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300263 err = sock_queue_rcv_skb(sk, skb);
264 if (err < 0)
Johan Hedberg02d98122010-12-13 21:07:04 +0200265 kfree_skb(skb);
266
Marcel Holtmanne5f0e152012-02-22 11:59:01 +0100267 return err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200268}
269
Johan Hedberga38528f2011-01-22 06:46:43 +0200270static int read_version(struct sock *sk)
271{
272 struct mgmt_rp_read_version rp;
273
274 BT_DBG("sock %p", sk);
275
276 rp.version = MGMT_VERSION;
277 put_unaligned_le16(MGMT_REVISION, &rp.revision);
278
Johan Hedbergaee9b212012-02-18 15:07:59 +0200279 return cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, 0, &rp,
Szymon Janc4e51eae2011-02-25 19:05:48 +0100280 sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200281}
282
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200283static int read_commands(struct sock *sk)
284{
285 struct mgmt_rp_read_commands *rp;
286 u16 num_commands = ARRAY_SIZE(mgmt_commands);
287 u16 num_events = ARRAY_SIZE(mgmt_events);
288 u16 *opcode;
289 size_t rp_size;
290 int i, err;
291
292 BT_DBG("sock %p", sk);
293
294 rp_size = sizeof(*rp) + ((num_commands + num_events) * sizeof(u16));
295
296 rp = kmalloc(rp_size, GFP_KERNEL);
297 if (!rp)
298 return -ENOMEM;
299
300 put_unaligned_le16(num_commands, &rp->num_commands);
301 put_unaligned_le16(num_events, &rp->num_events);
302
303 for (i = 0, opcode = rp->opcodes; i < num_commands; i++, opcode++)
304 put_unaligned_le16(mgmt_commands[i], opcode);
305
306 for (i = 0; i < num_events; i++, opcode++)
307 put_unaligned_le16(mgmt_events[i], opcode);
308
Johan Hedbergaee9b212012-02-18 15:07:59 +0200309 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_COMMANDS, 0, rp,
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200310 rp_size);
311 kfree(rp);
312
313 return err;
314}
315
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200316static int read_index_list(struct sock *sk)
317{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200318 struct mgmt_rp_read_index_list *rp;
319 struct list_head *p;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200320 struct hci_dev *d;
Johan Hedberga38528f2011-01-22 06:46:43 +0200321 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200322 u16 count;
Johan Hedberga38528f2011-01-22 06:46:43 +0200323 int i, err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200324
325 BT_DBG("sock %p", sk);
326
327 read_lock(&hci_dev_list_lock);
328
329 count = 0;
330 list_for_each(p, &hci_dev_list) {
331 count++;
332 }
333
Johan Hedberga38528f2011-01-22 06:46:43 +0200334 rp_len = sizeof(*rp) + (2 * count);
335 rp = kmalloc(rp_len, GFP_ATOMIC);
336 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100337 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200338 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100339 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200340
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200341 put_unaligned_le16(count, &rp->num_controllers);
342
343 i = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200344 list_for_each_entry(d, &hci_dev_list, list) {
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200345 if (test_bit(HCI_SETUP, &d->dev_flags))
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200346 continue;
347
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200348 put_unaligned_le16(d->id, &rp->index[i++]);
349 BT_DBG("Added hci%u", d->id);
350 }
351
352 read_unlock(&hci_dev_list_lock);
353
Johan Hedbergaee9b212012-02-18 15:07:59 +0200354 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST, 0, rp,
Szymon Janc4e51eae2011-02-25 19:05:48 +0100355 rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200356
Johan Hedberga38528f2011-01-22 06:46:43 +0200357 kfree(rp);
358
359 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200360}
361
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200362static u32 get_supported_settings(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +0200363{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200364 u32 settings = 0;
Johan Hedberg03811012010-12-08 00:21:06 +0200365
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200366 settings |= MGMT_SETTING_POWERED;
367 settings |= MGMT_SETTING_CONNECTABLE;
368 settings |= MGMT_SETTING_FAST_CONNECTABLE;
369 settings |= MGMT_SETTING_DISCOVERABLE;
370 settings |= MGMT_SETTING_PAIRABLE;
Johan Hedberg03811012010-12-08 00:21:06 +0200371
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200372 if (hdev->features[6] & LMP_SIMPLE_PAIR)
373 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200374
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200375 if (!(hdev->features[4] & LMP_NO_BREDR)) {
376 settings |= MGMT_SETTING_BREDR;
377 settings |= MGMT_SETTING_LINK_SECURITY;
378 }
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200379
Marcel Holtmannd7b7e792012-02-20 21:47:49 +0100380 if (enable_hs)
381 settings |= MGMT_SETTING_HS;
382
383 if (enable_le) {
384 if (hdev->features[4] & LMP_LE)
385 settings |= MGMT_SETTING_LE;
386 }
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200387
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200388 return settings;
389}
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200390
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200391static u32 get_current_settings(struct hci_dev *hdev)
392{
393 u32 settings = 0;
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200394
Johan Hedbergf1f0eb02012-02-21 17:15:41 +0200395 if (hdev_is_powered(hdev))
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100396 settings |= MGMT_SETTING_POWERED;
397
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200398 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200399 settings |= MGMT_SETTING_CONNECTABLE;
400
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200401 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200402 settings |= MGMT_SETTING_DISCOVERABLE;
403
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200404 if (test_bit(HCI_PAIRABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200405 settings |= MGMT_SETTING_PAIRABLE;
406
407 if (!(hdev->features[4] & LMP_NO_BREDR))
408 settings |= MGMT_SETTING_BREDR;
409
Andre Guedes59e29402011-12-30 10:34:03 -0300410 if (hdev->host_features[0] & LMP_HOST_LE)
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200411 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200412
Johan Hedberg47990ea2012-02-22 11:58:37 +0200413 if (test_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200414 settings |= MGMT_SETTING_LINK_SECURITY;
Johan Hedbergf7b64e692010-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 Hedbergf7b64e692010-12-13 21:07:06 +0200418
Johan Hedberg6d80dfd2012-02-20 23:50:38 +0200419 if (test_bit(HCI_HS_ENABLED, &hdev->dev_flags))
420 settings |= MGMT_SETTING_HS;
421
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200422 return settings;
Johan Hedbergc542a062011-01-26 13:11:03 +0200423}
424
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300425#define PNP_INFO_SVCLASS_ID 0x1200
426
427static u8 bluetooth_base_uuid[] = {
428 0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80,
429 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
430};
431
432static u16 get_uuid16(u8 *uuid128)
433{
434 u32 val;
435 int i;
436
437 for (i = 0; i < 12; i++) {
438 if (bluetooth_base_uuid[i] != uuid128[i])
439 return 0;
440 }
441
442 memcpy(&val, &uuid128[12], 4);
443
444 val = le32_to_cpu(val);
445 if (val > 0xffff)
446 return 0;
447
448 return (u16) val;
449}
450
451static void create_eir(struct hci_dev *hdev, u8 *data)
452{
453 u8 *ptr = data;
454 u16 eir_len = 0;
455 u16 uuid16_list[HCI_MAX_EIR_LENGTH / sizeof(u16)];
456 int i, truncated = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200457 struct bt_uuid *uuid;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300458 size_t name_len;
459
460 name_len = strlen(hdev->dev_name);
461
462 if (name_len > 0) {
463 /* EIR Data type */
464 if (name_len > 48) {
465 name_len = 48;
466 ptr[1] = EIR_NAME_SHORT;
467 } else
468 ptr[1] = EIR_NAME_COMPLETE;
469
470 /* EIR Data length */
471 ptr[0] = name_len + 1;
472
473 memcpy(ptr + 2, hdev->dev_name, name_len);
474
475 eir_len += (name_len + 2);
476 ptr += (name_len + 2);
477 }
478
479 memset(uuid16_list, 0, sizeof(uuid16_list));
480
481 /* Group all UUID16 types */
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200482 list_for_each_entry(uuid, &hdev->uuids, list) {
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300483 u16 uuid16;
484
485 uuid16 = get_uuid16(uuid->uuid);
486 if (uuid16 == 0)
487 return;
488
489 if (uuid16 < 0x1100)
490 continue;
491
492 if (uuid16 == PNP_INFO_SVCLASS_ID)
493 continue;
494
495 /* Stop if not enough space to put next UUID */
496 if (eir_len + 2 + sizeof(u16) > HCI_MAX_EIR_LENGTH) {
497 truncated = 1;
498 break;
499 }
500
501 /* Check for duplicates */
502 for (i = 0; uuid16_list[i] != 0; i++)
503 if (uuid16_list[i] == uuid16)
504 break;
505
506 if (uuid16_list[i] == 0) {
507 uuid16_list[i] = uuid16;
508 eir_len += sizeof(u16);
509 }
510 }
511
512 if (uuid16_list[0] != 0) {
513 u8 *length = ptr;
514
515 /* EIR Data type */
516 ptr[1] = truncated ? EIR_UUID16_SOME : EIR_UUID16_ALL;
517
518 ptr += 2;
519 eir_len += 2;
520
521 for (i = 0; uuid16_list[i] != 0; i++) {
522 *ptr++ = (uuid16_list[i] & 0x00ff);
523 *ptr++ = (uuid16_list[i] & 0xff00) >> 8;
524 }
525
526 /* EIR Data length */
527 *length = (i * sizeof(u16)) + 1;
528 }
529}
530
531static int update_eir(struct hci_dev *hdev)
532{
533 struct hci_cp_write_eir cp;
534
535 if (!(hdev->features[6] & LMP_EXT_INQ))
536 return 0;
537
Johan 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
Marcel Holtmann97e0bde2012-02-22 13:49:28 +0100820 /* Time stamp */
821 __net_timestamp(skb);
822
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200823 hci_send_to_control(skb, skip_sk);
824 kfree_skb(skb);
825
826 return 0;
827}
828
829static int new_settings(struct hci_dev *hdev, struct sock *skip)
830{
831 __le32 ev;
832
833 ev = cpu_to_le32(get_current_settings(hdev));
834
835 return mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), skip);
836}
837
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300838static int set_discoverable(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200839{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300840 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberge41d8b42010-12-13 21:07:03 +0200841 struct hci_dev *hdev;
Johan Hedberg03811012010-12-08 00:21:06 +0200842 struct pending_cmd *cmd;
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200843 u16 timeout;
Johan Hedberg03811012010-12-08 00:21:06 +0200844 u8 scan;
845 int err;
846
Johan Hedberg03811012010-12-08 00:21:06 +0200847 BT_DBG("request for hci%u", index);
848
849 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200850 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
851 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200852
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200853 hdev = hci_dev_get(index);
854 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200855 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
856 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200857
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200858 timeout = get_unaligned_le16(&cp->timeout);
859
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300860 hci_dev_lock(hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200861
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200862 if (!hdev_is_powered(hdev) && timeout > 0) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200863 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
864 MGMT_STATUS_NOT_POWERED);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200865 goto failed;
866 }
867
868 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
869 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200870 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
871 MGMT_STATUS_BUSY);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200872 goto failed;
873 }
874
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200875 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) {
876 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
877 MGMT_STATUS_REJECTED);
878 goto failed;
879 }
880
881 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200882 bool changed = false;
883
884 if (!!cp->val != test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
885 change_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
886 changed = true;
887 }
888
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200889 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200890 if (err < 0)
891 goto failed;
892
893 if (changed)
894 err = new_settings(hdev, sk);
895
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200896 goto failed;
897 }
898
899 if (!!cp->val == test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200900 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200901 goto failed;
902 }
903
904 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
905 if (!cmd) {
906 err = -ENOMEM;
907 goto failed;
908 }
909
910 scan = SCAN_PAGE;
911
912 if (cp->val)
913 scan |= SCAN_INQUIRY;
914 else
915 cancel_delayed_work(&hdev->discov_off);
916
917 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
918 if (err < 0)
919 mgmt_pending_remove(cmd);
920
Johan Hedberg03811012010-12-08 00:21:06 +0200921 if (cp->val)
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200922 hdev->discov_timeout = timeout;
Johan Hedberg03811012010-12-08 00:21:06 +0200923
924failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300925 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200926 hci_dev_put(hdev);
927
928 return err;
929}
930
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300931static int set_connectable(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200932{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300933 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200934 struct hci_dev *hdev;
935 struct pending_cmd *cmd;
936 u8 scan;
937 int err;
938
Johan Hedberge41d8b42010-12-13 21:07:03 +0200939 BT_DBG("request for hci%u", index);
940
Johan Hedberg03811012010-12-08 00:21:06 +0200941 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200942 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
943 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200944
945 hdev = hci_dev_get(index);
946 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200947 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
948 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200949
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300950 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200951
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200952 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200953 bool changed = false;
954
955 if (!!cp->val != test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
956 changed = true;
957
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +0200958 if (cp->val) {
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200959 set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +0200960 } else {
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200961 clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
962 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
963 }
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200964
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200965 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200966 if (err < 0)
967 goto failed;
968
969 if (changed)
970 err = new_settings(hdev, sk);
971
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200972 goto failed;
973 }
974
975 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
976 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200977 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
978 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200979 goto failed;
980 }
981
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200982 if (!!cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200983 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200984 goto failed;
985 }
986
987 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
988 if (!cmd) {
989 err = -ENOMEM;
990 goto failed;
991 }
992
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +0200993 if (cp->val) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200994 scan = SCAN_PAGE;
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +0200995 } else {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200996 scan = 0;
997
Johan Hedbergdf2c6c52012-02-21 19:15:49 +0200998 if (test_bit(HCI_ISCAN, &hdev->flags) &&
999 hdev->discov_timeout > 0)
1000 cancel_delayed_work(&hdev->discov_off);
1001 }
1002
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001003 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1004 if (err < 0)
1005 mgmt_pending_remove(cmd);
1006
1007failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001008 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001009 hci_dev_put(hdev);
1010
1011 return err;
1012}
1013
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001014static int set_pairable(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001015{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001016 struct mgmt_mode *cp = data;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001017 struct hci_dev *hdev;
1018 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001019
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001020 BT_DBG("request for hci%u", index);
1021
1022 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001023 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE,
1024 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001025
1026 hdev = hci_dev_get(index);
1027 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001028 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE,
1029 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001030
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001031 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001032
1033 if (cp->val)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001034 set_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001035 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001036 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001037
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001038 err = send_settings_rsp(sk, MGMT_OP_SET_PAIRABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001039 if (err < 0)
1040 goto failed;
1041
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001042 err = new_settings(hdev, sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001043
1044failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001045 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001046 hci_dev_put(hdev);
1047
1048 return err;
1049}
Johan Hedberg72a734e2010-12-30 00:38:22 +02001050
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001051static int set_link_security(struct sock *sk, u16 index, void *data, u16 len)
1052{
1053 struct mgmt_mode *cp = data;
1054 struct pending_cmd *cmd;
1055 struct hci_dev *hdev;
1056 uint8_t val;
1057 int err;
1058
1059 BT_DBG("request for hci%u", index);
1060
1061 if (len != sizeof(*cp))
1062 return cmd_status(sk, index, MGMT_OP_SET_LINK_SECURITY,
1063 MGMT_STATUS_INVALID_PARAMS);
1064
1065 hdev = hci_dev_get(index);
1066 if (!hdev)
1067 return cmd_status(sk, index, MGMT_OP_SET_LINK_SECURITY,
1068 MGMT_STATUS_INVALID_PARAMS);
1069
1070 hci_dev_lock(hdev);
1071
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001072 if (!hdev_is_powered(hdev)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001073 bool changed = false;
1074
1075 if (!!cp->val != test_bit(HCI_LINK_SECURITY,
1076 &hdev->dev_flags)) {
1077 change_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
1078 changed = true;
1079 }
1080
1081 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1082 if (err < 0)
1083 goto failed;
1084
1085 if (changed)
1086 err = new_settings(hdev, sk);
1087
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001088 goto failed;
1089 }
1090
1091 if (mgmt_pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
1092 err = cmd_status(sk, index, MGMT_OP_SET_LINK_SECURITY,
1093 MGMT_STATUS_BUSY);
1094 goto failed;
1095 }
1096
1097 val = !!cp->val;
1098
1099 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1100 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1101 goto failed;
1102 }
1103
1104 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1105 if (!cmd) {
1106 err = -ENOMEM;
1107 goto failed;
1108 }
1109
1110 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1111 if (err < 0) {
1112 mgmt_pending_remove(cmd);
1113 goto failed;
1114 }
1115
1116failed:
1117 hci_dev_unlock(hdev);
1118 hci_dev_put(hdev);
1119
1120 return err;
1121}
1122
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001123static int set_ssp(struct sock *sk, u16 index, void *data, u16 len)
1124{
1125 struct mgmt_mode *cp = data;
1126 struct pending_cmd *cmd;
1127 struct hci_dev *hdev;
1128 uint8_t val;
1129 int err;
1130
1131 BT_DBG("request for hci%u", index);
1132
1133 if (len != sizeof(*cp))
1134 return cmd_status(sk, index, MGMT_OP_SET_SSP,
1135 MGMT_STATUS_INVALID_PARAMS);
1136
1137 hdev = hci_dev_get(index);
1138 if (!hdev)
1139 return cmd_status(sk, index, MGMT_OP_SET_SSP,
1140 MGMT_STATUS_INVALID_PARAMS);
1141
1142 hci_dev_lock(hdev);
1143
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001144 val = !!cp->val;
1145
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001146 if (!hdev_is_powered(hdev)) {
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001147 bool changed = false;
1148
1149 if (val != test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) {
1150 change_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
1151 changed = true;
1152 }
1153
1154 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1155 if (err < 0)
1156 goto failed;
1157
1158 if (changed)
1159 err = new_settings(hdev, sk);
1160
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001161 goto failed;
1162 }
1163
Johan Hedberg1e163572012-02-20 23:53:46 +02001164 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
1165 err = cmd_status(sk, index, MGMT_OP_SET_SSP,
1166 MGMT_STATUS_NOT_SUPPORTED);
1167 goto failed;
1168 }
1169
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001170 if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev)) {
1171 err = cmd_status(sk, index, MGMT_OP_SET_SSP, MGMT_STATUS_BUSY);
1172 goto failed;
1173 }
1174
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001175 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) == val) {
1176 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1177 goto failed;
1178 }
1179
1180 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1181 if (!cmd) {
1182 err = -ENOMEM;
1183 goto failed;
1184 }
1185
1186 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, sizeof(val), &val);
1187 if (err < 0) {
1188 mgmt_pending_remove(cmd);
1189 goto failed;
1190 }
1191
1192failed:
1193 hci_dev_unlock(hdev);
1194 hci_dev_put(hdev);
1195
1196 return err;
1197}
1198
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001199static int set_hs(struct sock *sk, u16 index, void *data, u16 len)
1200{
1201 struct mgmt_mode *cp = data;
1202 struct hci_dev *hdev;
1203 int err;
1204
1205 BT_DBG("request for hci%u", index);
1206
1207 if (len != sizeof(*cp))
1208 return cmd_status(sk, index, MGMT_OP_SET_HS,
1209 MGMT_STATUS_INVALID_PARAMS);
1210
1211 hdev = hci_dev_get(index);
1212 if (!hdev)
1213 return cmd_status(sk, index, MGMT_OP_SET_HS,
1214 MGMT_STATUS_INVALID_PARAMS);
1215
1216 if (!enable_hs) {
1217 err = cmd_status(sk, index, MGMT_OP_SET_HS,
1218 MGMT_STATUS_NOT_SUPPORTED);
1219 goto failed;
1220 }
1221
1222 if (cp->val)
1223 set_bit(HCI_HS_ENABLED, &hdev->dev_flags);
1224 else
1225 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
1226
1227 err = send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
1228
1229failed:
1230 hci_dev_put(hdev);
1231 return err;
1232}
1233
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001234static int add_uuid(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001235{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001236 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001237 struct hci_dev *hdev;
1238 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001239 int err;
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_ADD_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_ADD_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 uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC);
1255 if (!uuid) {
1256 err = -ENOMEM;
1257 goto failed;
1258 }
1259
1260 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001261 uuid->svc_hint = cp->svc_hint;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001262
1263 list_add(&uuid->list, &hdev->uuids);
1264
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001265 err = update_class(hdev);
1266 if (err < 0)
1267 goto failed;
1268
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001269 err = update_eir(hdev);
1270 if (err < 0)
1271 goto failed;
1272
Johan Hedbergaee9b212012-02-18 15:07:59 +02001273 err = cmd_complete(sk, index, MGMT_OP_ADD_UUID, 0, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001274
1275failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001276 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001277 hci_dev_put(hdev);
1278
1279 return err;
1280}
1281
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001282static int remove_uuid(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001283{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001284 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001285 struct list_head *p, *n;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001286 struct hci_dev *hdev;
1287 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 +02001288 int err, found;
1289
Szymon Janc4e51eae2011-02-25 19:05:48 +01001290 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001291
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001292 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001293 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
1294 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001295
Szymon Janc4e51eae2011-02-25 19:05:48 +01001296 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001297 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001298 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
1299 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001300
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001301 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001302
1303 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
1304 err = hci_uuids_clear(hdev);
1305 goto unlock;
1306 }
1307
1308 found = 0;
1309
1310 list_for_each_safe(p, n, &hdev->uuids) {
1311 struct bt_uuid *match = list_entry(p, struct bt_uuid, list);
1312
1313 if (memcmp(match->uuid, cp->uuid, 16) != 0)
1314 continue;
1315
1316 list_del(&match->list);
1317 found++;
1318 }
1319
1320 if (found == 0) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001321 err = cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
1322 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001323 goto unlock;
1324 }
1325
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001326 err = update_class(hdev);
1327 if (err < 0)
1328 goto unlock;
1329
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001330 err = update_eir(hdev);
1331 if (err < 0)
1332 goto unlock;
1333
Johan Hedbergaee9b212012-02-18 15:07:59 +02001334 err = cmd_complete(sk, index, MGMT_OP_REMOVE_UUID, 0, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001335
1336unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001337 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001338 hci_dev_put(hdev);
1339
1340 return err;
1341}
1342
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001343static int set_dev_class(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001344{
1345 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001346 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001347 int err;
1348
Szymon Janc4e51eae2011-02-25 19:05:48 +01001349 BT_DBG("request for hci%u", index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001350
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001351 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001352 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS,
1353 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001354
Szymon Janc4e51eae2011-02-25 19:05:48 +01001355 hdev = hci_dev_get(index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001356 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001357 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS,
1358 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001359
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001360 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001361
Johan Hedbergb5235a62012-02-21 14:32:24 +02001362 if (!hdev_is_powered(hdev)) {
1363 err = cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS,
1364 MGMT_STATUS_NOT_POWERED);
1365 goto unlock;
1366 }
1367
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001368 hdev->major_class = cp->major;
1369 hdev->minor_class = cp->minor;
1370
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001371 if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02001372 hci_dev_unlock(hdev);
1373 cancel_delayed_work_sync(&hdev->service_cache);
1374 hci_dev_lock(hdev);
Johan Hedberg14c0b602011-12-15 00:47:37 +02001375 update_eir(hdev);
Johan Hedberg7d785252011-12-15 00:47:39 +02001376 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02001377
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001378 err = update_class(hdev);
1379
1380 if (err == 0)
Johan Hedbergaee9b212012-02-18 15:07:59 +02001381 err = cmd_complete(sk, index, MGMT_OP_SET_DEV_CLASS, 0,
1382 NULL, 0);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001383
Johan Hedbergb5235a62012-02-21 14:32:24 +02001384unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001385 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001386 hci_dev_put(hdev);
1387
1388 return err;
1389}
1390
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001391static int load_link_keys(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001392{
1393 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001394 struct mgmt_cp_load_link_keys *cp = data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001395 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001396 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001397
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001398 if (len < sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001399 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1400 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001401
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001402 key_count = get_unaligned_le16(&cp->key_count);
1403
Johan Hedberg86742e12011-11-07 23:13:38 +02001404 expected_len = sizeof(*cp) + key_count *
1405 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001406 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001407 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001408 len, expected_len);
Johan Hedbergca69b792011-11-11 18:10:00 +02001409 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1410 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001411 }
1412
Szymon Janc4e51eae2011-02-25 19:05:48 +01001413 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001414 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001415 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1416 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001417
Szymon Janc4e51eae2011-02-25 19:05:48 +01001418 BT_DBG("hci%u debug_keys %u key_count %u", index, cp->debug_keys,
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001419 key_count);
1420
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001421 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001422
1423 hci_link_keys_clear(hdev);
1424
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001425 set_bit(HCI_LINK_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001426
1427 if (cp->debug_keys)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001428 set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001429 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001430 clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001431
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001432 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001433 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001434
Johan Hedbergd753fdc2012-02-17 14:06:34 +02001435 hci_add_link_key(hdev, NULL, 0, &key->addr.bdaddr, key->val,
1436 key->type, key->pin_len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001437 }
1438
Johan Hedbergaee9b212012-02-18 15:07:59 +02001439 cmd_complete(sk, index, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02001440
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001441 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001442 hci_dev_put(hdev);
1443
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001444 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001445}
1446
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001447static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
1448 u8 addr_type, struct sock *skip_sk)
1449{
1450 struct mgmt_ev_device_unpaired ev;
1451
1452 bacpy(&ev.addr.bdaddr, bdaddr);
1453 ev.addr.type = addr_type;
1454
1455 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
1456 skip_sk);
1457}
1458
Johan Hedberg124f6e32012-02-09 13:50:12 +02001459static int unpair_device(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001460{
1461 struct hci_dev *hdev;
Johan Hedberg124f6e32012-02-09 13:50:12 +02001462 struct mgmt_cp_unpair_device *cp = data;
1463 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001464 struct hci_cp_disconnect dc;
1465 struct pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001466 struct hci_conn *conn;
Johan Hedbergaee9b212012-02-18 15:07:59 +02001467 u8 status = 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001468 int err;
1469
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001470 if (len != sizeof(*cp))
Johan Hedberg124f6e32012-02-09 13:50:12 +02001471 return cmd_status(sk, index, MGMT_OP_UNPAIR_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02001472 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001473
Szymon Janc4e51eae2011-02-25 19:05:48 +01001474 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001475 if (!hdev)
Johan Hedberg124f6e32012-02-09 13:50:12 +02001476 return cmd_status(sk, index, MGMT_OP_UNPAIR_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02001477 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001478
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001479 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001480
Johan Hedberga8a1d192011-11-10 15:54:38 +02001481 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02001482 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1483 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001484
Johan Hedberg124f6e32012-02-09 13:50:12 +02001485 if (cp->addr.type == MGMT_ADDR_BREDR)
1486 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
1487 else
1488 err = hci_remove_ltk(hdev, &cp->addr.bdaddr);
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03001489
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001490 if (err < 0) {
Johan Hedbergaee9b212012-02-18 15:07:59 +02001491 status = MGMT_STATUS_NOT_PAIRED;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001492 goto unlock;
1493 }
1494
Johan Hedberga8a1d192011-11-10 15:54:38 +02001495 if (!test_bit(HCI_UP, &hdev->flags) || !cp->disconnect) {
Johan Hedbergaee9b212012-02-18 15:07:59 +02001496 err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE, status,
1497 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001498 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001499 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001500 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001501
Johan Hedberg124f6e32012-02-09 13:50:12 +02001502 if (cp->addr.type == MGMT_ADDR_BREDR)
1503 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
1504 &cp->addr.bdaddr);
1505 else
1506 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
1507 &cp->addr.bdaddr);
1508
Johan Hedberga8a1d192011-11-10 15:54:38 +02001509 if (!conn) {
Johan Hedbergaee9b212012-02-18 15:07:59 +02001510 err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE, status,
1511 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001512 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001513 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001514 }
1515
Johan Hedberg124f6e32012-02-09 13:50:12 +02001516 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
1517 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02001518 if (!cmd) {
1519 err = -ENOMEM;
1520 goto unlock;
1521 }
1522
1523 put_unaligned_le16(conn->handle, &dc.handle);
1524 dc.reason = 0x13; /* Remote User Terminated Connection */
1525 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1526 if (err < 0)
1527 mgmt_pending_remove(cmd);
1528
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001529unlock:
Johan Hedbergca69b792011-11-11 18:10:00 +02001530 if (err < 0)
Johan Hedbergaee9b212012-02-18 15:07:59 +02001531 err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE, status,
1532 &rp, sizeof(rp));
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001533 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001534 hci_dev_put(hdev);
1535
1536 return err;
1537}
1538
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001539static int disconnect(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02001540{
1541 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001542 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001543 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03001544 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001545 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001546 int err;
1547
1548 BT_DBG("");
1549
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001550 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001551 return cmd_status(sk, index, MGMT_OP_DISCONNECT,
1552 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001553
Szymon Janc4e51eae2011-02-25 19:05:48 +01001554 hdev = hci_dev_get(index);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001555 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001556 return cmd_status(sk, index, MGMT_OP_DISCONNECT,
1557 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001558
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001559 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001560
1561 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001562 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1563 MGMT_STATUS_NOT_POWERED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001564 goto failed;
1565 }
1566
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001567 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001568 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1569 MGMT_STATUS_BUSY);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001570 goto failed;
1571 }
1572
Johan Hedberg88c3df12012-02-09 14:27:38 +02001573 if (cp->addr.type == MGMT_ADDR_BREDR)
1574 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
1575 else
1576 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03001577
Johan Hedberg8962ee72011-01-20 12:40:27 +02001578 if (!conn) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001579 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1580 MGMT_STATUS_NOT_CONNECTED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001581 goto failed;
1582 }
1583
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001584 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001585 if (!cmd) {
1586 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001587 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001588 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001589
1590 put_unaligned_le16(conn->handle, &dc.handle);
1591 dc.reason = 0x13; /* Remote User Terminated Connection */
1592
1593 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1594 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001595 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001596
1597failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001598 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001599 hci_dev_put(hdev);
1600
1601 return err;
1602}
1603
Johan Hedberg48264f02011-11-09 13:58:58 +02001604static u8 link_to_mgmt(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02001605{
1606 switch (link_type) {
1607 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02001608 switch (addr_type) {
1609 case ADDR_LE_DEV_PUBLIC:
1610 return MGMT_ADDR_LE_PUBLIC;
1611 case ADDR_LE_DEV_RANDOM:
1612 return MGMT_ADDR_LE_RANDOM;
1613 default:
1614 return MGMT_ADDR_INVALID;
1615 }
Johan Hedberg4c659c32011-11-07 23:13:39 +02001616 case ACL_LINK:
1617 return MGMT_ADDR_BREDR;
1618 default:
1619 return MGMT_ADDR_INVALID;
1620 }
1621}
1622
Szymon Janc8ce62842011-03-01 16:55:32 +01001623static int get_connections(struct sock *sk, u16 index)
Johan Hedberg2784eb42011-01-21 13:56:35 +02001624{
Johan Hedberg2784eb42011-01-21 13:56:35 +02001625 struct mgmt_rp_get_connections *rp;
1626 struct hci_dev *hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001627 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02001628 size_t rp_len;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001629 u16 count;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001630 int i, err;
1631
1632 BT_DBG("");
1633
Szymon Janc4e51eae2011-02-25 19:05:48 +01001634 hdev = hci_dev_get(index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001635 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001636 return cmd_status(sk, index, MGMT_OP_GET_CONNECTIONS,
1637 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001638
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001639 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001640
1641 count = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02001642 list_for_each_entry(c, &hdev->conn_hash.list, list) {
1643 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
1644 count++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001645 }
1646
Johan Hedberg4c659c32011-11-07 23:13:39 +02001647 rp_len = sizeof(*rp) + (count * sizeof(struct mgmt_addr_info));
Johan Hedberga38528f2011-01-22 06:46:43 +02001648 rp = kmalloc(rp_len, GFP_ATOMIC);
1649 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02001650 err = -ENOMEM;
1651 goto unlock;
1652 }
1653
Johan Hedberg2784eb42011-01-21 13:56:35 +02001654 put_unaligned_le16(count, &rp->conn_count);
1655
Johan Hedberg2784eb42011-01-21 13:56:35 +02001656 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001657 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02001658 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
1659 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001660 bacpy(&rp->addr[i].bdaddr, &c->dst);
Johan Hedberg48264f02011-11-09 13:58:58 +02001661 rp->addr[i].type = link_to_mgmt(c->type, c->dst_type);
Johan Hedberg4c659c32011-11-07 23:13:39 +02001662 if (rp->addr[i].type == MGMT_ADDR_INVALID)
1663 continue;
1664 i++;
1665 }
1666
1667 /* Recalculate length in case of filtered SCO connections, etc */
1668 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02001669
Johan Hedbergaee9b212012-02-18 15:07:59 +02001670 err = cmd_complete(sk, index, MGMT_OP_GET_CONNECTIONS, 0, rp, rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001671
1672unlock:
Johan Hedberga38528f2011-01-22 06:46:43 +02001673 kfree(rp);
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001674 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001675 hci_dev_put(hdev);
1676 return err;
1677}
1678
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001679static int send_pin_code_neg_reply(struct sock *sk, u16 index,
1680 struct hci_dev *hdev, struct mgmt_cp_pin_code_neg_reply *cp)
1681{
1682 struct pending_cmd *cmd;
1683 int err;
1684
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001685 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001686 sizeof(*cp));
1687 if (!cmd)
1688 return -ENOMEM;
1689
Johan Hedbergd8457692012-02-17 14:24:57 +02001690 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
1691 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001692 if (err < 0)
1693 mgmt_pending_remove(cmd);
1694
1695 return err;
1696}
1697
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001698static int pin_code_reply(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001699{
1700 struct hci_dev *hdev;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001701 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001702 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001703 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03001704 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001705 int err;
1706
1707 BT_DBG("");
1708
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001709 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001710 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1711 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001712
Szymon Janc4e51eae2011-02-25 19:05:48 +01001713 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001714 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001715 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1716 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001717
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001718 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001719
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001720 if (!hdev_is_powered(hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001721 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1722 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001723 goto failed;
1724 }
1725
Johan Hedbergd8457692012-02-17 14:24:57 +02001726 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001727 if (!conn) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001728 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1729 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001730 goto failed;
1731 }
1732
1733 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02001734 struct mgmt_cp_pin_code_neg_reply ncp;
1735
1736 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001737
1738 BT_ERR("PIN code is not 16 bytes long");
1739
1740 err = send_pin_code_neg_reply(sk, index, hdev, &ncp);
1741 if (err >= 0)
1742 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001743 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001744
1745 goto failed;
1746 }
1747
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001748 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data,
1749 len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001750 if (!cmd) {
1751 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001752 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001753 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02001754
Johan Hedbergd8457692012-02-17 14:24:57 +02001755 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001756 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02001757 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02001758
1759 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
1760 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001761 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001762
1763failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001764 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001765 hci_dev_put(hdev);
1766
1767 return err;
1768}
1769
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001770static int pin_code_neg_reply(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001771{
1772 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001773 struct mgmt_cp_pin_code_neg_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001774 int err;
1775
1776 BT_DBG("");
1777
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001778 if (len != sizeof(*cp))
1779 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001780 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001781
Szymon Janc4e51eae2011-02-25 19:05:48 +01001782 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001783 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001784 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001785 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001786
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001787 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001788
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001789 if (!hdev_is_powered(hdev)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001790 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001791 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001792 goto failed;
1793 }
1794
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001795 err = send_pin_code_neg_reply(sk, index, hdev, cp);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001796
1797failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001798 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001799 hci_dev_put(hdev);
1800
1801 return err;
1802}
1803
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001804static int set_io_capability(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001805{
1806 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001807 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001808
1809 BT_DBG("");
1810
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001811 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001812 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY,
1813 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001814
Szymon Janc4e51eae2011-02-25 19:05:48 +01001815 hdev = hci_dev_get(index);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001816 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001817 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY,
1818 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001819
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001820 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001821
1822 hdev->io_capability = cp->io_capability;
1823
1824 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Szymon Jancb8534e02011-03-01 16:55:34 +01001825 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001826
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001827 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001828 hci_dev_put(hdev);
1829
Johan Hedbergaee9b212012-02-18 15:07:59 +02001830 return cmd_complete(sk, index, MGMT_OP_SET_IO_CAPABILITY, 0, NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001831}
1832
Johan Hedberge9a416b2011-02-19 12:05:56 -03001833static inline struct pending_cmd *find_pairing(struct hci_conn *conn)
1834{
1835 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001836 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001837
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001838 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03001839 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
1840 continue;
1841
Johan Hedberge9a416b2011-02-19 12:05:56 -03001842 if (cmd->user_data != conn)
1843 continue;
1844
1845 return cmd;
1846 }
1847
1848 return NULL;
1849}
1850
1851static void pairing_complete(struct pending_cmd *cmd, u8 status)
1852{
1853 struct mgmt_rp_pair_device rp;
1854 struct hci_conn *conn = cmd->user_data;
1855
Johan Hedbergba4e5642011-11-11 00:07:34 +02001856 bacpy(&rp.addr.bdaddr, &conn->dst);
1857 rp.addr.type = link_to_mgmt(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001858
Johan Hedbergaee9b212012-02-18 15:07:59 +02001859 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, status,
1860 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001861
1862 /* So we don't get further callbacks for this connection */
1863 conn->connect_cfm_cb = NULL;
1864 conn->security_cfm_cb = NULL;
1865 conn->disconn_cfm_cb = NULL;
1866
1867 hci_conn_put(conn);
1868
Johan Hedberga664b5b2011-02-19 12:06:02 -03001869 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001870}
1871
1872static void pairing_complete_cb(struct hci_conn *conn, u8 status)
1873{
1874 struct pending_cmd *cmd;
1875
1876 BT_DBG("status %u", status);
1877
Johan Hedberg56e5cb82011-11-08 20:40:16 +02001878 cmd = find_pairing(conn);
1879 if (!cmd)
1880 BT_DBG("Unable to find a pending command");
1881 else
Johan Hedberge2113262012-02-18 15:20:03 +02001882 pairing_complete(cmd, mgmt_status(status));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001883}
1884
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001885static int pair_device(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001886{
1887 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001888 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02001889 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001890 struct pending_cmd *cmd;
1891 u8 sec_level, auth_type;
1892 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001893 int err;
1894
1895 BT_DBG("");
1896
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001897 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001898 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE,
1899 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001900
Szymon Janc4e51eae2011-02-25 19:05:48 +01001901 hdev = hci_dev_get(index);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001902 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001903 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE,
1904 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001905
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001906 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001907
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001908 sec_level = BT_SECURITY_MEDIUM;
1909 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001910 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001911 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03001912 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001913
Johan Hedbergba4e5642011-11-11 00:07:34 +02001914 if (cp->addr.type == MGMT_ADDR_BREDR)
1915 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr, sec_level,
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001916 auth_type);
1917 else
Johan Hedbergba4e5642011-11-11 00:07:34 +02001918 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr, sec_level,
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001919 auth_type);
1920
Johan Hedberg1425acb2011-11-11 00:07:35 +02001921 memset(&rp, 0, sizeof(rp));
1922 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1923 rp.addr.type = cp->addr.type;
1924
Ville Tervo30e76272011-02-22 16:10:53 -03001925 if (IS_ERR(conn)) {
Johan Hedberge2113262012-02-18 15:20:03 +02001926 err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE,
1927 MGMT_STATUS_CONNECT_FAILED,
1928 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001929 goto unlock;
1930 }
1931
1932 if (conn->connect_cfm_cb) {
1933 hci_conn_put(conn);
Johan Hedberge2113262012-02-18 15:20:03 +02001934 err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE,
1935 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001936 goto unlock;
1937 }
1938
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001939 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001940 if (!cmd) {
1941 err = -ENOMEM;
1942 hci_conn_put(conn);
1943 goto unlock;
1944 }
1945
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001946 /* For LE, just connecting isn't a proof that the pairing finished */
Johan Hedbergba4e5642011-11-11 00:07:34 +02001947 if (cp->addr.type == MGMT_ADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001948 conn->connect_cfm_cb = pairing_complete_cb;
1949
Johan Hedberge9a416b2011-02-19 12:05:56 -03001950 conn->security_cfm_cb = pairing_complete_cb;
1951 conn->disconn_cfm_cb = pairing_complete_cb;
1952 conn->io_capability = cp->io_cap;
1953 cmd->user_data = conn;
1954
1955 if (conn->state == BT_CONNECTED &&
1956 hci_conn_security(conn, sec_level, auth_type))
1957 pairing_complete(cmd, 0);
1958
1959 err = 0;
1960
1961unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001962 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001963 hci_dev_put(hdev);
1964
1965 return err;
1966}
1967
Johan Hedberg28424702012-02-02 04:02:29 +02001968static int cancel_pair_device(struct sock *sk, u16 index,
1969 unsigned char *data, u16 len)
1970{
1971 struct mgmt_addr_info *addr = (void *) data;
1972 struct hci_dev *hdev;
1973 struct pending_cmd *cmd;
1974 struct hci_conn *conn;
1975 int err;
1976
1977 BT_DBG("");
1978
1979 if (len != sizeof(*addr))
1980 return cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
1981 MGMT_STATUS_INVALID_PARAMS);
1982
1983 hdev = hci_dev_get(index);
1984 if (!hdev)
1985 return cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
1986 MGMT_STATUS_INVALID_PARAMS);
1987
1988 hci_dev_lock(hdev);
1989
1990 cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
1991 if (!cmd) {
1992 err = cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
1993 MGMT_STATUS_INVALID_PARAMS);
1994 goto unlock;
1995 }
1996
1997 conn = cmd->user_data;
1998
1999 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
2000 err = cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
2001 MGMT_STATUS_INVALID_PARAMS);
2002 goto unlock;
2003 }
2004
2005 pairing_complete(cmd, MGMT_STATUS_CANCELLED);
2006
Johan Hedbergaee9b212012-02-18 15:07:59 +02002007 err = cmd_complete(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE, 0, addr,
Johan Hedberg28424702012-02-02 04:02:29 +02002008 sizeof(*addr));
2009unlock:
2010 hci_dev_unlock(hdev);
2011 hci_dev_put(hdev);
2012
2013 return err;
2014}
2015
Brian Gix0df4c182011-11-16 13:53:13 -08002016static int user_pairing_resp(struct sock *sk, u16 index, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02002017 u8 type, u16 mgmt_op, u16 hci_op,
2018 __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03002019{
Johan Hedberga5c29682011-02-19 12:05:57 -03002020 struct pending_cmd *cmd;
2021 struct hci_dev *hdev;
Brian Gix0df4c182011-11-16 13:53:13 -08002022 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03002023 int err;
2024
Szymon Janc4e51eae2011-02-25 19:05:48 +01002025 hdev = hci_dev_get(index);
Johan Hedberga5c29682011-02-19 12:05:57 -03002026 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002027 return cmd_status(sk, index, mgmt_op,
2028 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga5c29682011-02-19 12:05:57 -03002029
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002030 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02002031
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002032 if (!hdev_is_powered(hdev)) {
Brian Gix0df4c182011-11-16 13:53:13 -08002033 err = cmd_status(sk, index, mgmt_op, MGMT_STATUS_NOT_POWERED);
2034 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002035 }
2036
Johan Hedberg272d90d2012-02-09 15:26:12 +02002037 if (type == MGMT_ADDR_BREDR)
2038 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, bdaddr);
2039 else
Brian Gix47c15e22011-11-16 13:53:14 -08002040 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, bdaddr);
Brian Gix47c15e22011-11-16 13:53:14 -08002041
Johan Hedberg272d90d2012-02-09 15:26:12 +02002042 if (!conn) {
2043 err = cmd_status(sk, index, mgmt_op,
2044 MGMT_STATUS_NOT_CONNECTED);
2045 goto done;
2046 }
2047
2048 if (type == MGMT_ADDR_LE_PUBLIC || type == MGMT_ADDR_LE_RANDOM) {
Brian Gix47c15e22011-11-16 13:53:14 -08002049 /* Continue with pairing via SMP */
Brian Gix5fe57d92011-12-21 16:12:13 -08002050 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix47c15e22011-11-16 13:53:14 -08002051
Brian Gix5fe57d92011-12-21 16:12:13 -08002052 if (!err)
2053 err = cmd_status(sk, index, mgmt_op,
2054 MGMT_STATUS_SUCCESS);
2055 else
2056 err = cmd_status(sk, index, mgmt_op,
2057 MGMT_STATUS_FAILED);
2058
Brian Gix47c15e22011-11-16 13:53:14 -08002059 goto done;
2060 }
2061
Brian Gix0df4c182011-11-16 13:53:13 -08002062 cmd = mgmt_pending_add(sk, mgmt_op, hdev, bdaddr, sizeof(*bdaddr));
Johan Hedberga5c29682011-02-19 12:05:57 -03002063 if (!cmd) {
2064 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08002065 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002066 }
2067
Brian Gix0df4c182011-11-16 13:53:13 -08002068 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08002069 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
2070 struct hci_cp_user_passkey_reply cp;
2071
2072 bacpy(&cp.bdaddr, bdaddr);
2073 cp.passkey = passkey;
2074 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
2075 } else
2076 err = hci_send_cmd(hdev, hci_op, sizeof(*bdaddr), bdaddr);
2077
Johan Hedberga664b5b2011-02-19 12:06:02 -03002078 if (err < 0)
2079 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002080
Brian Gix0df4c182011-11-16 13:53:13 -08002081done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002082 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002083 hci_dev_put(hdev);
2084
2085 return err;
2086}
2087
Brian Gix0df4c182011-11-16 13:53:13 -08002088static int user_confirm_reply(struct sock *sk, u16 index, void *data, u16 len)
2089{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002090 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002091
2092 BT_DBG("");
2093
2094 if (len != sizeof(*cp))
2095 return cmd_status(sk, index, MGMT_OP_USER_CONFIRM_REPLY,
2096 MGMT_STATUS_INVALID_PARAMS);
2097
Johan Hedberg272d90d2012-02-09 15:26:12 +02002098 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
2099 MGMT_OP_USER_CONFIRM_REPLY,
2100 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002101}
2102
2103static int user_confirm_neg_reply(struct sock *sk, u16 index, void *data,
2104 u16 len)
2105{
Johan Hedbergc9c26592011-12-15 00:47:41 +02002106 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002107
2108 BT_DBG("");
2109
2110 if (len != sizeof(*cp))
2111 return cmd_status(sk, index, MGMT_OP_USER_CONFIRM_NEG_REPLY,
2112 MGMT_STATUS_INVALID_PARAMS);
2113
Johan Hedberg272d90d2012-02-09 15:26:12 +02002114 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
2115 MGMT_OP_USER_CONFIRM_NEG_REPLY,
2116 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002117}
2118
Brian Gix604086b2011-11-23 08:28:33 -08002119static int user_passkey_reply(struct sock *sk, u16 index, void *data, u16 len)
2120{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002121 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002122
2123 BT_DBG("");
2124
2125 if (len != sizeof(*cp))
2126 return cmd_status(sk, index, MGMT_OP_USER_PASSKEY_REPLY,
2127 EINVAL);
2128
Johan Hedberg272d90d2012-02-09 15:26:12 +02002129 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
2130 MGMT_OP_USER_PASSKEY_REPLY,
2131 HCI_OP_USER_PASSKEY_REPLY,
2132 cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08002133}
2134
2135static int user_passkey_neg_reply(struct sock *sk, u16 index, void *data,
2136 u16 len)
2137{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002138 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002139
2140 BT_DBG("");
2141
2142 if (len != sizeof(*cp))
2143 return cmd_status(sk, index, MGMT_OP_USER_PASSKEY_NEG_REPLY,
2144 EINVAL);
2145
Johan Hedberg272d90d2012-02-09 15:26:12 +02002146 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
2147 MGMT_OP_USER_PASSKEY_NEG_REPLY,
2148 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08002149}
2150
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002151static int set_local_name(struct sock *sk, u16 index, void *data,
Johan Hedbergb312b1612011-03-16 14:29:37 +02002152 u16 len)
2153{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002154 struct mgmt_cp_set_local_name *mgmt_cp = data;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002155 struct hci_cp_write_local_name hci_cp;
2156 struct hci_dev *hdev;
2157 struct pending_cmd *cmd;
2158 int err;
2159
2160 BT_DBG("");
2161
2162 if (len != sizeof(*mgmt_cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02002163 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME,
2164 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002165
2166 hdev = hci_dev_get(index);
2167 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002168 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME,
2169 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002170
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002171 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002172
Johan Hedbergb5235a62012-02-21 14:32:24 +02002173 if (!hdev_is_powered(hdev)) {
2174 err = cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME,
2175 MGMT_STATUS_NOT_POWERED);
2176 goto failed;
2177 }
2178
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002179 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data,
2180 len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002181 if (!cmd) {
2182 err = -ENOMEM;
2183 goto failed;
2184 }
2185
2186 memcpy(hci_cp.name, mgmt_cp->name, sizeof(hci_cp.name));
2187 err = hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(hci_cp),
2188 &hci_cp);
2189 if (err < 0)
2190 mgmt_pending_remove(cmd);
2191
2192failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002193 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002194 hci_dev_put(hdev);
2195
2196 return err;
2197}
2198
Szymon Jancc35938b2011-03-22 13:12:21 +01002199static int read_local_oob_data(struct sock *sk, u16 index)
2200{
2201 struct hci_dev *hdev;
2202 struct pending_cmd *cmd;
2203 int err;
2204
2205 BT_DBG("hci%u", index);
2206
2207 hdev = hci_dev_get(index);
2208 if (!hdev)
2209 return cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002210 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancc35938b2011-03-22 13:12:21 +01002211
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002212 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002213
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002214 if (!hdev_is_powered(hdev)) {
Szymon Jancc35938b2011-03-22 13:12:21 +01002215 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002216 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002217 goto unlock;
2218 }
2219
2220 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
2221 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002222 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002223 goto unlock;
2224 }
2225
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002226 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02002227 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2228 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01002229 goto unlock;
2230 }
2231
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002232 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01002233 if (!cmd) {
2234 err = -ENOMEM;
2235 goto unlock;
2236 }
2237
2238 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
2239 if (err < 0)
2240 mgmt_pending_remove(cmd);
2241
2242unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002243 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002244 hci_dev_put(hdev);
2245
2246 return err;
2247}
2248
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002249static int add_remote_oob_data(struct sock *sk, u16 index, void *data,
2250 u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002251{
2252 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002253 struct mgmt_cp_add_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002254 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002255 int err;
2256
2257 BT_DBG("hci%u ", index);
2258
2259 if (len != sizeof(*cp))
2260 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002261 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01002262
2263 hdev = hci_dev_get(index);
2264 if (!hdev)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002265 return cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
2266 MGMT_STATUS_INVALID_PARAMS,
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_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002270
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002271 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, cp->hash,
Szymon Janc2763eda2011-03-22 13:12:22 +01002272 cp->randomizer);
2273 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002274 status = MGMT_STATUS_FAILED;
Szymon Janc2763eda2011-03-22 13:12:22 +01002275 else
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002276 status = 0;
2277
2278 err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, status,
2279 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002280
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002281 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002282 hci_dev_put(hdev);
2283
2284 return err;
2285}
2286
2287static int remove_remote_oob_data(struct sock *sk, u16 index,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002288 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002289{
2290 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002291 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002292 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002293 int err;
2294
2295 BT_DBG("hci%u ", index);
2296
2297 if (len != sizeof(*cp))
2298 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002299 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01002300
2301 hdev = hci_dev_get(index);
2302 if (!hdev)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002303 return cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2304 MGMT_STATUS_INVALID_PARAMS,
2305 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002306
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002307 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002308
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002309 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr);
Szymon Janc2763eda2011-03-22 13:12:22 +01002310 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002311 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01002312 else
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002313 status = 0;
2314
2315 err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA, status,
2316 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002317
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002318 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002319 hci_dev_put(hdev);
2320
2321 return err;
2322}
2323
Andre Guedes5e0452c2012-02-17 20:39:38 -03002324static int discovery(struct hci_dev *hdev)
2325{
2326 int err;
2327
2328 if (lmp_host_le_capable(hdev)) {
2329 if (lmp_bredr_capable(hdev)) {
2330 err = hci_le_scan(hdev, LE_SCAN_TYPE,
2331 LE_SCAN_INT, LE_SCAN_WIN,
2332 LE_SCAN_TIMEOUT_BREDR_LE);
2333 } else {
2334 hdev->discovery.type = DISCOV_TYPE_LE;
2335 err = hci_le_scan(hdev, LE_SCAN_TYPE,
2336 LE_SCAN_INT, LE_SCAN_WIN,
2337 LE_SCAN_TIMEOUT_LE_ONLY);
2338 }
2339 } else {
2340 hdev->discovery.type = DISCOV_TYPE_BREDR;
2341 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
2342 }
2343
2344 return err;
2345}
2346
2347int mgmt_interleaved_discovery(struct hci_dev *hdev)
2348{
2349 int err;
2350
2351 BT_DBG("%s", hdev->name);
2352
2353 hci_dev_lock(hdev);
2354
2355 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR_LE);
2356 if (err < 0)
2357 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2358
2359 hci_dev_unlock(hdev);
2360
2361 return err;
2362}
2363
Johan Hedberg450dfda2011-11-12 11:58:22 +02002364static int start_discovery(struct sock *sk, u16 index,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002365 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002366{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002367 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002368 struct pending_cmd *cmd;
2369 struct hci_dev *hdev;
2370 int err;
2371
2372 BT_DBG("hci%u", index);
2373
Johan Hedberg450dfda2011-11-12 11:58:22 +02002374 if (len != sizeof(*cp))
2375 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2376 MGMT_STATUS_INVALID_PARAMS);
2377
Johan Hedberg14a53662011-04-27 10:29:56 -04002378 hdev = hci_dev_get(index);
2379 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002380 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2381 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg14a53662011-04-27 10:29:56 -04002382
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002383 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002384
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002385 if (!hdev_is_powered(hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02002386 err = cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2387 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02002388 goto failed;
2389 }
2390
Johan Hedbergff9ef572012-01-04 14:23:45 +02002391 if (hdev->discovery.state != DISCOVERY_STOPPED) {
2392 err = cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2393 MGMT_STATUS_BUSY);
2394 goto failed;
2395 }
2396
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002397 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002398 if (!cmd) {
2399 err = -ENOMEM;
2400 goto failed;
2401 }
2402
Andre Guedes4aab14e2012-02-17 20:39:36 -03002403 hdev->discovery.type = cp->type;
2404
2405 switch (hdev->discovery.type) {
Andre Guedesf39799f2012-02-17 20:39:35 -03002406 case DISCOV_TYPE_BREDR:
Andre Guedes3fd24152012-02-03 17:48:01 -03002407 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
Andre Guedesf39799f2012-02-17 20:39:35 -03002408 break;
2409
2410 case DISCOV_TYPE_LE:
Andre Guedes3fd24152012-02-03 17:48:01 -03002411 err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT,
2412 LE_SCAN_WIN, LE_SCAN_TIMEOUT_LE_ONLY);
Andre Guedesf39799f2012-02-17 20:39:35 -03002413 break;
2414
Andre Guedes5e0452c2012-02-17 20:39:38 -03002415 case DISCOV_TYPE_INTERLEAVED:
2416 err = discovery(hdev);
2417 break;
2418
Andre Guedesf39799f2012-02-17 20:39:35 -03002419 default:
Andre Guedes3fd24152012-02-03 17:48:01 -03002420 err = -EINVAL;
Andre Guedesf39799f2012-02-17 20:39:35 -03002421 }
Andre Guedes3fd24152012-02-03 17:48:01 -03002422
Johan Hedberg14a53662011-04-27 10:29:56 -04002423 if (err < 0)
2424 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002425 else
2426 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002427
2428failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002429 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002430 hci_dev_put(hdev);
2431
2432 return err;
2433}
2434
Johan Hedbergd9306502012-02-20 23:25:18 +02002435static int stop_discovery(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002436{
Johan Hedbergd9306502012-02-20 23:25:18 +02002437 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002438 struct hci_dev *hdev;
2439 struct pending_cmd *cmd;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002440 struct hci_cp_remote_name_req_cancel cp;
2441 struct inquiry_entry *e;
Johan Hedberg14a53662011-04-27 10:29:56 -04002442 int err;
2443
2444 BT_DBG("hci%u", index);
2445
Johan Hedbergd9306502012-02-20 23:25:18 +02002446 if (len != sizeof(*mgmt_cp))
2447 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY,
2448 MGMT_STATUS_INVALID_PARAMS);
2449
Johan Hedberg14a53662011-04-27 10:29:56 -04002450 hdev = hci_dev_get(index);
2451 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002452 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY,
2453 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg14a53662011-04-27 10:29:56 -04002454
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002455 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002456
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002457 if (!hci_discovery_active(hdev)) {
Johan Hedbergd9306502012-02-20 23:25:18 +02002458 err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY,
2459 MGMT_STATUS_REJECTED,
2460 &mgmt_cp->type, sizeof(mgmt_cp->type));
2461 goto unlock;
2462 }
2463
2464 if (hdev->discovery.type != mgmt_cp->type) {
2465 err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY,
2466 MGMT_STATUS_INVALID_PARAMS,
2467 &mgmt_cp->type, sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002468 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02002469 }
2470
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002471 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002472 if (!cmd) {
2473 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002474 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04002475 }
2476
Andre Guedes343f9352012-02-17 20:39:37 -03002477 if (hdev->discovery.state == DISCOVERY_FINDING) {
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002478 err = hci_cancel_inquiry(hdev);
2479 if (err < 0)
2480 mgmt_pending_remove(cmd);
2481 else
2482 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
2483 goto unlock;
2484 }
2485
2486 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY, NAME_PENDING);
2487 if (!e) {
2488 mgmt_pending_remove(cmd);
Johan Hedbergaee9b212012-02-18 15:07:59 +02002489 err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY, 0,
Johan Hedbergd9306502012-02-20 23:25:18 +02002490 &mgmt_cp->type, sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002491 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2492 goto unlock;
2493 }
2494
2495 bacpy(&cp.bdaddr, &e->data.bdaddr);
2496 err = hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ_CANCEL,
2497 sizeof(cp), &cp);
Johan Hedberg14a53662011-04-27 10:29:56 -04002498 if (err < 0)
2499 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002500 else
2501 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002502
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002503unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002504 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002505 hci_dev_put(hdev);
2506
2507 return err;
2508}
2509
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002510static int confirm_name(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02002511{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002512 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002513 struct inquiry_entry *e;
2514 struct hci_dev *hdev;
2515 int err;
2516
2517 BT_DBG("hci%u", index);
2518
2519 if (len != sizeof(*cp))
2520 return cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2521 MGMT_STATUS_INVALID_PARAMS);
2522
2523 hdev = hci_dev_get(index);
2524 if (!hdev)
2525 return cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2526 MGMT_STATUS_INVALID_PARAMS);
2527
2528 hci_dev_lock(hdev);
2529
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002530 if (!hci_discovery_active(hdev)) {
2531 err = cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2532 MGMT_STATUS_FAILED);
2533 goto failed;
2534 }
2535
Johan Hedberga198e7b2012-02-17 14:27:06 +02002536 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002537 if (!e) {
Marcel Holtmanne5f0e152012-02-22 11:59:01 +01002538 err = cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
Johan Hedberg561aafb2012-01-04 13:31:59 +02002539 MGMT_STATUS_INVALID_PARAMS);
2540 goto failed;
2541 }
2542
2543 if (cp->name_known) {
2544 e->name_state = NAME_KNOWN;
2545 list_del(&e->list);
2546 } else {
2547 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e20a2012-01-09 00:53:02 +02002548 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002549 }
2550
2551 err = 0;
2552
2553failed:
2554 hci_dev_unlock(hdev);
2555
2556 return err;
2557}
2558
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002559static int block_device(struct sock *sk, u16 index, void *data, u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002560{
2561 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002562 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002563 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03002564 int err;
2565
2566 BT_DBG("hci%u", index);
2567
Antti Julku7fbec222011-06-15 12:01:15 +03002568 if (len != sizeof(*cp))
2569 return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002570 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002571
2572 hdev = hci_dev_get(index);
2573 if (!hdev)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002574 return cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE,
2575 MGMT_STATUS_INVALID_PARAMS,
2576 &cp->addr, sizeof(cp->addr));
Antti Julku7fbec222011-06-15 12:01:15 +03002577
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002578 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002579
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002580 err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002581 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002582 status = MGMT_STATUS_FAILED;
Antti Julku7fbec222011-06-15 12:01:15 +03002583 else
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002584 status = 0;
2585
2586 err = cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE, status,
2587 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03002588
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002589 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002590 hci_dev_put(hdev);
2591
2592 return err;
2593}
2594
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002595static int unblock_device(struct sock *sk, u16 index, void *data, u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002596{
2597 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002598 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002599 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03002600 int err;
2601
2602 BT_DBG("hci%u", index);
2603
Antti Julku7fbec222011-06-15 12:01:15 +03002604 if (len != sizeof(*cp))
2605 return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002606 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002607
2608 hdev = hci_dev_get(index);
2609 if (!hdev)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002610 return cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE,
2611 MGMT_STATUS_INVALID_PARAMS,
2612 &cp->addr, sizeof(cp->addr));
Antti Julku7fbec222011-06-15 12:01:15 +03002613
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002614 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002615
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002616 err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002617 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002618 status = MGMT_STATUS_INVALID_PARAMS;
Antti Julku7fbec222011-06-15 12:01:15 +03002619 else
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002620 status = 0;
2621
2622 err = cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE, status,
2623 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03002624
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002625 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002626 hci_dev_put(hdev);
2627
2628 return err;
2629}
2630
Antti Julkuf6422ec2011-06-22 13:11:56 +03002631static int set_fast_connectable(struct sock *sk, u16 index,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002632 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03002633{
2634 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002635 struct mgmt_mode *cp = data;
Antti Julkuf6422ec2011-06-22 13:11:56 +03002636 struct hci_cp_write_page_scan_activity acp;
2637 u8 type;
2638 int err;
2639
2640 BT_DBG("hci%u", index);
2641
2642 if (len != sizeof(*cp))
2643 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002644 MGMT_STATUS_INVALID_PARAMS);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002645
2646 hdev = hci_dev_get(index);
2647 if (!hdev)
2648 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002649 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg5400c042012-02-21 16:40:33 +02002650 if (!hdev_is_powered(hdev))
2651 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
2652 MGMT_STATUS_NOT_POWERED);
2653
2654 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
2655 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
2656 MGMT_STATUS_REJECTED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002657
2658 hci_dev_lock(hdev);
2659
Johan Hedbergf7c6869ce2011-12-15 00:47:36 +02002660 if (cp->val) {
Antti Julkuf6422ec2011-06-22 13:11:56 +03002661 type = PAGE_SCAN_TYPE_INTERLACED;
2662 acp.interval = 0x0024; /* 22.5 msec page scan interval */
2663 } else {
2664 type = PAGE_SCAN_TYPE_STANDARD; /* default */
2665 acp.interval = 0x0800; /* default 1.28 sec page scan */
2666 }
2667
2668 acp.window = 0x0012; /* default 11.25 msec page scan window */
2669
2670 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
2671 sizeof(acp), &acp);
2672 if (err < 0) {
2673 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002674 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002675 goto done;
2676 }
2677
2678 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
2679 if (err < 0) {
2680 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002681 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002682 goto done;
2683 }
2684
Johan Hedbergaee9b212012-02-18 15:07:59 +02002685 err = cmd_complete(sk, index, MGMT_OP_SET_FAST_CONNECTABLE, 0,
2686 NULL, 0);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002687done:
2688 hci_dev_unlock(hdev);
2689 hci_dev_put(hdev);
2690
2691 return err;
2692}
2693
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002694static int load_long_term_keys(struct sock *sk, u16 index,
2695 void *cp_data, u16 len)
2696{
2697 struct hci_dev *hdev;
2698 struct mgmt_cp_load_long_term_keys *cp = cp_data;
2699 u16 key_count, expected_len;
2700 int i;
2701
2702 if (len < sizeof(*cp))
2703 return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS,
2704 EINVAL);
2705
2706 key_count = get_unaligned_le16(&cp->key_count);
2707
2708 expected_len = sizeof(*cp) + key_count *
2709 sizeof(struct mgmt_ltk_info);
2710 if (expected_len != len) {
2711 BT_ERR("load_keys: expected %u bytes, got %u bytes",
2712 len, expected_len);
2713 return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS,
2714 EINVAL);
2715 }
2716
2717 hdev = hci_dev_get(index);
2718 if (!hdev)
2719 return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS,
2720 ENODEV);
2721
2722 BT_DBG("hci%u key_count %u", index, key_count);
2723
2724 hci_dev_lock(hdev);
2725
2726 hci_smp_ltks_clear(hdev);
2727
2728 for (i = 0; i < key_count; i++) {
2729 struct mgmt_ltk_info *key = &cp->keys[i];
2730 u8 type;
2731
2732 if (key->master)
2733 type = HCI_SMP_LTK;
2734 else
2735 type = HCI_SMP_LTK_SLAVE;
2736
2737 hci_add_ltk(hdev, &key->addr.bdaddr, key->addr.type,
2738 type, 0, key->authenticated, key->val,
2739 key->enc_size, key->ediv, key->rand);
2740 }
2741
2742 hci_dev_unlock(hdev);
2743 hci_dev_put(hdev);
2744
2745 return 0;
2746}
2747
Johan Hedberg03811012010-12-08 00:21:06 +02002748int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
2749{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002750 void *buf;
2751 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02002752 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002753 u16 opcode, index, len;
Johan Hedberg03811012010-12-08 00:21:06 +02002754 int err;
2755
2756 BT_DBG("got %zu bytes", msglen);
2757
2758 if (msglen < sizeof(*hdr))
2759 return -EINVAL;
2760
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03002761 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02002762 if (!buf)
2763 return -ENOMEM;
2764
2765 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
2766 err = -EFAULT;
2767 goto done;
2768 }
2769
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002770 hdr = buf;
Johan Hedberg03811012010-12-08 00:21:06 +02002771 opcode = get_unaligned_le16(&hdr->opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002772 index = get_unaligned_le16(&hdr->index);
Johan Hedberg03811012010-12-08 00:21:06 +02002773 len = get_unaligned_le16(&hdr->len);
2774
2775 if (len != msglen - sizeof(*hdr)) {
2776 err = -EINVAL;
2777 goto done;
2778 }
2779
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002780 cp = buf + sizeof(*hdr);
2781
Johan Hedberg03811012010-12-08 00:21:06 +02002782 switch (opcode) {
Johan Hedberg02d98122010-12-13 21:07:04 +02002783 case MGMT_OP_READ_VERSION:
2784 err = read_version(sk);
2785 break;
Johan Hedberge70bb2e2012-02-13 16:59:33 +02002786 case MGMT_OP_READ_COMMANDS:
2787 err = read_commands(sk);
2788 break;
Johan Hedbergfaba42e2010-12-13 21:07:05 +02002789 case MGMT_OP_READ_INDEX_LIST:
2790 err = read_index_list(sk);
2791 break;
Johan Hedbergf7b64e692010-12-13 21:07:06 +02002792 case MGMT_OP_READ_INFO:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002793 err = read_controller_info(sk, index);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02002794 break;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002795 case MGMT_OP_SET_POWERED:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002796 err = set_powered(sk, index, cp, len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002797 break;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002798 case MGMT_OP_SET_DISCOVERABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002799 err = set_discoverable(sk, index, cp, len);
Johan Hedberg73f22f62010-12-29 16:00:25 +02002800 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002801 case MGMT_OP_SET_CONNECTABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002802 err = set_connectable(sk, index, cp, len);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002803 break;
Johan Hedbergf7c6869ce2011-12-15 00:47:36 +02002804 case MGMT_OP_SET_FAST_CONNECTABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002805 err = set_fast_connectable(sk, index, cp, len);
Johan Hedbergf7c6869ce2011-12-15 00:47:36 +02002806 break;
Johan Hedbergc542a062011-01-26 13:11:03 +02002807 case MGMT_OP_SET_PAIRABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002808 err = set_pairable(sk, index, cp, len);
Johan Hedbergc542a062011-01-26 13:11:03 +02002809 break;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02002810 case MGMT_OP_SET_LINK_SECURITY:
2811 err = set_link_security(sk, index, cp, len);
2812 break;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02002813 case MGMT_OP_SET_SSP:
2814 err = set_ssp(sk, index, cp, len);
2815 break;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02002816 case MGMT_OP_SET_HS:
2817 err = set_hs(sk, index, cp, len);
2818 break;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002819 case MGMT_OP_ADD_UUID:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002820 err = add_uuid(sk, index, cp, len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002821 break;
2822 case MGMT_OP_REMOVE_UUID:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002823 err = remove_uuid(sk, index, cp, len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002824 break;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002825 case MGMT_OP_SET_DEV_CLASS:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002826 err = set_dev_class(sk, index, cp, len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002827 break;
Johan Hedberg86742e12011-11-07 23:13:38 +02002828 case MGMT_OP_LOAD_LINK_KEYS:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002829 err = load_link_keys(sk, index, cp, len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002830 break;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002831 case MGMT_OP_DISCONNECT:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002832 err = disconnect(sk, index, cp, len);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002833 break;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002834 case MGMT_OP_GET_CONNECTIONS:
Szymon Janc8ce62842011-03-01 16:55:32 +01002835 err = get_connections(sk, index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002836 break;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002837 case MGMT_OP_PIN_CODE_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002838 err = pin_code_reply(sk, index, cp, len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002839 break;
2840 case MGMT_OP_PIN_CODE_NEG_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002841 err = pin_code_neg_reply(sk, index, cp, len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002842 break;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002843 case MGMT_OP_SET_IO_CAPABILITY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002844 err = set_io_capability(sk, index, cp, len);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002845 break;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002846 case MGMT_OP_PAIR_DEVICE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002847 err = pair_device(sk, index, cp, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002848 break;
Johan Hedberg28424702012-02-02 04:02:29 +02002849 case MGMT_OP_CANCEL_PAIR_DEVICE:
2850 err = cancel_pair_device(sk, index, buf + sizeof(*hdr), len);
2851 break;
Johan Hedberg124f6e32012-02-09 13:50:12 +02002852 case MGMT_OP_UNPAIR_DEVICE:
2853 err = unpair_device(sk, index, cp, len);
2854 break;
Johan Hedberga5c29682011-02-19 12:05:57 -03002855 case MGMT_OP_USER_CONFIRM_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002856 err = user_confirm_reply(sk, index, cp, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03002857 break;
2858 case MGMT_OP_USER_CONFIRM_NEG_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002859 err = user_confirm_neg_reply(sk, index, cp, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03002860 break;
Brian Gix604086b2011-11-23 08:28:33 -08002861 case MGMT_OP_USER_PASSKEY_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002862 err = user_passkey_reply(sk, index, cp, len);
Brian Gix604086b2011-11-23 08:28:33 -08002863 break;
2864 case MGMT_OP_USER_PASSKEY_NEG_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002865 err = user_passkey_neg_reply(sk, index, cp, len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002866 break;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002867 case MGMT_OP_SET_LOCAL_NAME:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002868 err = set_local_name(sk, index, cp, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002869 break;
Szymon Jancc35938b2011-03-22 13:12:21 +01002870 case MGMT_OP_READ_LOCAL_OOB_DATA:
2871 err = read_local_oob_data(sk, index);
2872 break;
Szymon Janc2763eda2011-03-22 13:12:22 +01002873 case MGMT_OP_ADD_REMOTE_OOB_DATA:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002874 err = add_remote_oob_data(sk, index, cp, len);
Szymon Janc2763eda2011-03-22 13:12:22 +01002875 break;
2876 case MGMT_OP_REMOVE_REMOTE_OOB_DATA:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002877 err = remove_remote_oob_data(sk, index, cp, len);
Szymon Janc2763eda2011-03-22 13:12:22 +01002878 break;
Johan Hedberg14a53662011-04-27 10:29:56 -04002879 case MGMT_OP_START_DISCOVERY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002880 err = start_discovery(sk, index, cp, len);
Johan Hedberg14a53662011-04-27 10:29:56 -04002881 break;
2882 case MGMT_OP_STOP_DISCOVERY:
Johan Hedbergd9306502012-02-20 23:25:18 +02002883 err = stop_discovery(sk, index, cp, len);
Johan Hedberg14a53662011-04-27 10:29:56 -04002884 break;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002885 case MGMT_OP_CONFIRM_NAME:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002886 err = confirm_name(sk, index, cp, len);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002887 break;
Antti Julku7fbec222011-06-15 12:01:15 +03002888 case MGMT_OP_BLOCK_DEVICE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002889 err = block_device(sk, index, cp, len);
Antti Julku7fbec222011-06-15 12:01:15 +03002890 break;
2891 case MGMT_OP_UNBLOCK_DEVICE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002892 err = unblock_device(sk, index, cp, len);
Antti Julku7fbec222011-06-15 12:01:15 +03002893 break;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002894 case MGMT_OP_LOAD_LONG_TERM_KEYS:
2895 err = load_long_term_keys(sk, index, cp, len);
2896 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002897 default:
Johan Hedberg72a734e2010-12-30 00:38:22 +02002898 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02002899 err = cmd_status(sk, index, opcode,
2900 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002901 break;
2902 }
Johan Hedberg72a734e2010-12-30 00:38:22 +02002903
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002904 if (err < 0)
Johan Hedberg72a734e2010-12-30 00:38:22 +02002905 goto done;
2906
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002907 err = msglen;
2908
2909done:
2910 kfree(buf);
2911 return err;
2912}
2913
Johan Hedbergb24752f2011-11-03 14:40:33 +02002914static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
2915{
2916 u8 *status = data;
2917
2918 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
2919 mgmt_pending_remove(cmd);
2920}
2921
Johan Hedberg744cf192011-11-08 20:40:14 +02002922int mgmt_index_added(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +02002923{
Johan Hedberg744cf192011-11-08 20:40:14 +02002924 return mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02002925}
2926
Johan Hedberg744cf192011-11-08 20:40:14 +02002927int mgmt_index_removed(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +02002928{
Johan Hedbergb24752f2011-11-03 14:40:33 +02002929 u8 status = ENODEV;
2930
Johan Hedberg744cf192011-11-08 20:40:14 +02002931 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002932
Johan Hedberg744cf192011-11-08 20:40:14 +02002933 return mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02002934}
2935
2936struct cmd_lookup {
Johan Hedberg03811012010-12-08 00:21:06 +02002937 struct sock *sk;
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002938 struct hci_dev *hdev;
Johan Hedberg03811012010-12-08 00:21:06 +02002939};
2940
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002941static void settings_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberg03811012010-12-08 00:21:06 +02002942{
Johan Hedberg03811012010-12-08 00:21:06 +02002943 struct cmd_lookup *match = data;
2944
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002945 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02002946
2947 list_del(&cmd->list);
2948
2949 if (match->sk == NULL) {
2950 match->sk = cmd->sk;
2951 sock_hold(match->sk);
2952 }
2953
2954 mgmt_pending_free(cmd);
2955}
2956
Johan Hedberg744cf192011-11-08 20:40:14 +02002957int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg03811012010-12-08 00:21:06 +02002958{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002959 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002960 int err;
Johan Hedberg03811012010-12-08 00:21:06 +02002961
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002962 if (!test_bit(HCI_MGMT, &hdev->dev_flags))
2963 return 0;
2964
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002965 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
Johan Hedberg03811012010-12-08 00:21:06 +02002966
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002967 if (powered) {
2968 u8 scan = 0;
2969
2970 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
2971 scan |= SCAN_PAGE;
2972 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
2973 scan |= SCAN_INQUIRY;
2974
2975 if (scan)
2976 hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
2977 } else {
Johan Hedbergb24752f2011-11-03 14:40:33 +02002978 u8 status = ENETDOWN;
Johan Hedberg744cf192011-11-08 20:40:14 +02002979 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002980 }
2981
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02002982 err = new_settings(hdev, match.sk);
Johan Hedberg03811012010-12-08 00:21:06 +02002983
2984 if (match.sk)
2985 sock_put(match.sk);
2986
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002987 return err;
Johan Hedberg03811012010-12-08 00:21:06 +02002988}
2989
Johan Hedberg744cf192011-11-08 20:40:14 +02002990int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg03811012010-12-08 00:21:06 +02002991{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002992 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002993 bool changed = false;
2994 int err = 0;
Johan Hedberg03811012010-12-08 00:21:06 +02002995
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002996 if (discoverable) {
2997 if (!test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
2998 changed = true;
2999 } else {
3000 if (test_and_clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3001 changed = true;
3002 }
Johan Hedberg03811012010-12-08 00:21:06 +02003003
Johan Hedberged9b5f22012-02-21 20:47:06 +02003004 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp,
3005 &match);
3006
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003007 if (changed)
3008 err = new_settings(hdev, match.sk);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003009
Johan Hedberg03811012010-12-08 00:21:06 +02003010 if (match.sk)
3011 sock_put(match.sk);
3012
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003013 return err;
Johan Hedberg03811012010-12-08 00:21:06 +02003014}
3015
Johan Hedberg744cf192011-11-08 20:40:14 +02003016int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg03811012010-12-08 00:21:06 +02003017{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02003018 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003019 bool changed = false;
3020 int err = 0;
Johan Hedberg03811012010-12-08 00:21:06 +02003021
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003022 if (connectable) {
3023 if (!test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3024 changed = true;
3025 } else {
3026 if (test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3027 changed = true;
3028 }
Johan Hedberg03811012010-12-08 00:21:06 +02003029
Johan Hedberged9b5f22012-02-21 20:47:06 +02003030 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev, settings_rsp,
3031 &match);
3032
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003033 if (changed)
3034 err = new_settings(hdev, match.sk);
Johan Hedberg03811012010-12-08 00:21:06 +02003035
3036 if (match.sk)
3037 sock_put(match.sk);
3038
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003039 return err;
Johan Hedberg03811012010-12-08 00:21:06 +02003040}
3041
Johan Hedberg744cf192011-11-08 20:40:14 +02003042int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003043{
Johan Hedbergca69b792011-11-11 18:10:00 +02003044 u8 mgmt_err = mgmt_status(status);
3045
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003046 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02003047 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Johan Hedbergca69b792011-11-11 18:10:00 +02003048 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003049
3050 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02003051 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Johan Hedbergca69b792011-11-11 18:10:00 +02003052 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003053
3054 return 0;
3055}
3056
Johan Hedberg744cf192011-11-08 20:40:14 +02003057int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
3058 u8 persistent)
Johan Hedberg03811012010-12-08 00:21:06 +02003059{
Johan Hedberg86742e12011-11-07 23:13:38 +02003060 struct mgmt_ev_new_link_key ev;
Johan Hedberg03811012010-12-08 00:21:06 +02003061
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003062 memset(&ev, 0, sizeof(ev));
Johan Hedberg03811012010-12-08 00:21:06 +02003063
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003064 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02003065 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
3066 ev.key.addr.type = MGMT_ADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003067 ev.key.type = key->type;
3068 memcpy(ev.key.val, key->val, 16);
3069 ev.key.pin_len = key->pin_len;
Johan Hedberg03811012010-12-08 00:21:06 +02003070
Johan Hedberg744cf192011-11-08 20:40:14 +02003071 return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02003072}
Johan Hedbergf7520542011-01-20 12:34:39 +02003073
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003074int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
3075{
3076 struct mgmt_ev_new_long_term_key ev;
3077
3078 memset(&ev, 0, sizeof(ev));
3079
3080 ev.store_hint = persistent;
3081 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
3082 ev.key.addr.type = key->bdaddr_type;
3083 ev.key.authenticated = key->authenticated;
3084 ev.key.enc_size = key->enc_size;
3085 ev.key.ediv = key->ediv;
3086
3087 if (key->type == HCI_SMP_LTK)
3088 ev.key.master = 1;
3089
3090 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
3091 memcpy(ev.key.val, key->val, sizeof(key->val));
3092
3093 return mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev,
3094 &ev, sizeof(ev), NULL);
3095}
3096
Johan Hedbergafc747a2012-01-15 18:11:07 +02003097int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Johan Hedbergb644ba32012-01-17 21:48:47 +02003098 u8 addr_type, u8 *name, u8 name_len,
3099 u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02003100{
Johan Hedbergb644ba32012-01-17 21:48:47 +02003101 char buf[512];
3102 struct mgmt_ev_device_connected *ev = (void *) buf;
3103 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02003104
Johan Hedbergb644ba32012-01-17 21:48:47 +02003105 bacpy(&ev->addr.bdaddr, bdaddr);
3106 ev->addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02003107
Johan Hedbergb644ba32012-01-17 21:48:47 +02003108 if (name_len > 0)
3109 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
3110 name, name_len);
3111
3112 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
3113 eir_len = eir_append_data(&ev->eir[eir_len], eir_len,
3114 EIR_CLASS_OF_DEV, dev_class, 3);
3115
3116 put_unaligned_le16(eir_len, &ev->eir_len);
3117
3118 return mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
3119 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02003120}
3121
Johan Hedberg8962ee72011-01-20 12:40:27 +02003122static void disconnect_rsp(struct pending_cmd *cmd, void *data)
3123{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01003124 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003125 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02003126 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003127
Johan Hedberg88c3df12012-02-09 14:27:38 +02003128 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3129 rp.addr.type = cp->addr.type;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003130
Johan Hedbergaee9b212012-02-18 15:07:59 +02003131 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, 0, &rp,
3132 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003133
3134 *sk = cmd->sk;
3135 sock_hold(*sk);
3136
Johan Hedberga664b5b2011-02-19 12:06:02 -03003137 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003138}
3139
Johan Hedberg124f6e32012-02-09 13:50:12 +02003140static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02003141{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003142 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02003143 struct mgmt_cp_unpair_device *cp = cmd->param;
3144 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02003145
3146 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02003147 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3148 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02003149
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003150 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
3151
Johan Hedbergaee9b212012-02-18 15:07:59 +02003152 cmd_complete(cmd->sk, cmd->index, cmd->opcode, 0, &rp, sizeof(rp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02003153
3154 mgmt_pending_remove(cmd);
3155}
3156
Johan Hedbergafc747a2012-01-15 18:11:07 +02003157int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
3158 u8 link_type, u8 addr_type)
Johan Hedbergf7520542011-01-20 12:34:39 +02003159{
Johan Hedberg4c659c32011-11-07 23:13:39 +02003160 struct mgmt_addr_info ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003161 struct sock *sk = NULL;
3162 int err;
3163
Johan Hedberg744cf192011-11-08 20:40:14 +02003164 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02003165
Johan Hedbergf7520542011-01-20 12:34:39 +02003166 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02003167 ev.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02003168
Johan Hedbergafc747a2012-01-15 18:11:07 +02003169 err = mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev),
3170 sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003171
3172 if (sk)
3173 sock_put(sk);
3174
Johan Hedberg124f6e32012-02-09 13:50:12 +02003175 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003176 hdev);
Johan Hedberga8a1d192011-11-10 15:54:38 +02003177
Johan Hedberg8962ee72011-01-20 12:40:27 +02003178 return err;
3179}
3180
Johan Hedberg88c3df12012-02-09 14:27:38 +02003181int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
3182 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02003183{
Johan Hedberg88c3df12012-02-09 14:27:38 +02003184 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003185 struct pending_cmd *cmd;
3186 int err;
3187
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003188 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003189 if (!cmd)
3190 return -ENOENT;
3191
Johan Hedberg88c3df12012-02-09 14:27:38 +02003192 bacpy(&rp.addr.bdaddr, bdaddr);
3193 rp.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02003194
Johan Hedberg88c3df12012-02-09 14:27:38 +02003195 err = cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
Johan Hedbergaee9b212012-02-18 15:07:59 +02003196 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003197
Johan Hedberga664b5b2011-02-19 12:06:02 -03003198 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003199
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003200 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
3201 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003202 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02003203}
Johan Hedberg17d5c042011-01-22 06:09:08 +02003204
Johan Hedberg48264f02011-11-09 13:58:58 +02003205int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
3206 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02003207{
3208 struct mgmt_ev_connect_failed ev;
3209
Johan Hedberg4c659c32011-11-07 23:13:39 +02003210 bacpy(&ev.addr.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02003211 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003212 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003213
Johan Hedberg744cf192011-11-08 20:40:14 +02003214 return mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003215}
Johan Hedberg980e1a52011-01-22 06:10:07 +02003216
Johan Hedberg744cf192011-11-08 20:40:14 +02003217int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003218{
3219 struct mgmt_ev_pin_code_request ev;
3220
Johan Hedbergd8457692012-02-17 14:24:57 +02003221 bacpy(&ev.addr.bdaddr, bdaddr);
3222 ev.addr.type = MGMT_ADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02003223 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003224
Johan Hedberg744cf192011-11-08 20:40:14 +02003225 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01003226 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003227}
3228
Johan Hedberg744cf192011-11-08 20:40:14 +02003229int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3230 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003231{
3232 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003233 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003234 int err;
3235
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003236 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003237 if (!cmd)
3238 return -ENOENT;
3239
Johan Hedbergd8457692012-02-17 14:24:57 +02003240 bacpy(&rp.addr.bdaddr, bdaddr);
3241 rp.addr.type = MGMT_ADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003242
Johan Hedbergaee9b212012-02-18 15:07:59 +02003243 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
3244 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003245
Johan Hedberga664b5b2011-02-19 12:06:02 -03003246 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003247
3248 return err;
3249}
3250
Johan Hedberg744cf192011-11-08 20:40:14 +02003251int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3252 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003253{
3254 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003255 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003256 int err;
3257
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003258 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003259 if (!cmd)
3260 return -ENOENT;
3261
Johan Hedbergd8457692012-02-17 14:24:57 +02003262 bacpy(&rp.addr.bdaddr, bdaddr);
3263 rp.addr.type = MGMT_ADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003264
Johan Hedbergaee9b212012-02-18 15:07:59 +02003265 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
3266 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003267
Johan Hedberga664b5b2011-02-19 12:06:02 -03003268 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003269
3270 return err;
3271}
Johan Hedberga5c29682011-02-19 12:05:57 -03003272
Johan Hedberg744cf192011-11-08 20:40:14 +02003273int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003274 u8 link_type, u8 addr_type, __le32 value,
3275 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03003276{
3277 struct mgmt_ev_user_confirm_request ev;
3278
Johan Hedberg744cf192011-11-08 20:40:14 +02003279 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03003280
Johan Hedberg272d90d2012-02-09 15:26:12 +02003281 bacpy(&ev.addr.bdaddr, bdaddr);
3282 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07003283 ev.confirm_hint = confirm_hint;
Johan Hedberga5c29682011-02-19 12:05:57 -03003284 put_unaligned_le32(value, &ev.value);
3285
Johan Hedberg744cf192011-11-08 20:40:14 +02003286 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01003287 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03003288}
3289
Johan Hedberg272d90d2012-02-09 15:26:12 +02003290int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
3291 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08003292{
3293 struct mgmt_ev_user_passkey_request ev;
3294
3295 BT_DBG("%s", hdev->name);
3296
Johan Hedberg272d90d2012-02-09 15:26:12 +02003297 bacpy(&ev.addr.bdaddr, bdaddr);
3298 ev.addr.type = link_to_mgmt(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08003299
3300 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
3301 NULL);
3302}
3303
Brian Gix0df4c182011-11-16 13:53:13 -08003304static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003305 u8 link_type, u8 addr_type, u8 status,
3306 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03003307{
3308 struct pending_cmd *cmd;
3309 struct mgmt_rp_user_confirm_reply rp;
3310 int err;
3311
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003312 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03003313 if (!cmd)
3314 return -ENOENT;
3315
Johan Hedberg272d90d2012-02-09 15:26:12 +02003316 bacpy(&rp.addr.bdaddr, bdaddr);
3317 rp.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergaee9b212012-02-18 15:07:59 +02003318 err = cmd_complete(cmd->sk, hdev->id, opcode, mgmt_status(status),
3319 &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03003320
Johan Hedberga664b5b2011-02-19 12:06:02 -03003321 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03003322
3323 return err;
3324}
3325
Johan Hedberg744cf192011-11-08 20:40:14 +02003326int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003327 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003328{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003329 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3330 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003331}
3332
Johan Hedberg272d90d2012-02-09 15:26:12 +02003333int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3334 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003335{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003336 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3337 status, MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003338}
Johan Hedberg2a611692011-02-19 12:06:00 -03003339
Brian Gix604086b2011-11-23 08:28:33 -08003340int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003341 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003342{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003343 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3344 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003345}
3346
Johan Hedberg272d90d2012-02-09 15:26:12 +02003347int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3348 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003349{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003350 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3351 status, MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003352}
3353
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003354int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
3355 u8 addr_type, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03003356{
3357 struct mgmt_ev_auth_failed ev;
3358
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003359 bacpy(&ev.addr.bdaddr, bdaddr);
3360 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003361 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03003362
Johan Hedberg744cf192011-11-08 20:40:14 +02003363 return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03003364}
Johan Hedbergb312b1612011-03-16 14:29:37 +02003365
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003366int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
3367{
3368 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg47990ea2012-02-22 11:58:37 +02003369 bool changed = false;
3370 int err = 0;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003371
3372 if (status) {
3373 u8 mgmt_err = mgmt_status(status);
3374 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
3375 cmd_status_rsp, &mgmt_err);
3376 return 0;
3377 }
3378
Johan Hedberg47990ea2012-02-22 11:58:37 +02003379 if (test_bit(HCI_AUTH, &hdev->flags)) {
3380 if (!test_and_set_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
3381 changed = true;
3382 } else {
3383 if (test_and_clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
3384 changed = true;
3385 }
3386
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003387 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
3388 &match);
3389
Johan Hedberg47990ea2012-02-22 11:58:37 +02003390 if (changed)
3391 err = new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003392
3393 if (match.sk)
3394 sock_put(match.sk);
3395
3396 return err;
3397}
3398
Johan Hedbergcacaf522012-02-21 00:52:42 +02003399static int clear_eir(struct hci_dev *hdev)
3400{
3401 struct hci_cp_write_eir cp;
3402
3403 if (!(hdev->features[6] & LMP_EXT_INQ))
3404 return 0;
3405
Johan Hedbergc80da272012-02-22 15:38:48 +02003406 memset(hdev->eir, 0, sizeof(hdev->eir));
3407
Johan Hedbergcacaf522012-02-21 00:52:42 +02003408 memset(&cp, 0, sizeof(cp));
3409
3410 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
3411}
3412
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003413int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003414{
3415 struct cmd_lookup match = { NULL, hdev };
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003416 bool changed = false;
3417 int err = 0;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003418
3419 if (status) {
3420 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003421
3422 if (enable && test_and_clear_bit(HCI_SSP_ENABLED,
3423 &hdev->dev_flags))
3424 err = new_settings(hdev, NULL);
3425
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003426 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev,
3427 cmd_status_rsp, &mgmt_err);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003428
3429 return err;
3430 }
3431
3432 if (enable) {
3433 if (!test_and_set_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3434 changed = true;
3435 } else {
3436 if (test_and_clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3437 changed = true;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003438 }
3439
3440 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
3441
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003442 if (changed)
3443 err = new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003444
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02003445 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003446 sock_put(match.sk);
3447
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02003448 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3449 update_eir(hdev);
3450 else
3451 clear_eir(hdev);
Johan Hedbergcacaf522012-02-21 00:52:42 +02003452
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003453 return err;
3454}
3455
Johan Hedberg744cf192011-11-08 20:40:14 +02003456int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02003457{
3458 struct pending_cmd *cmd;
3459 struct mgmt_cp_set_local_name ev;
3460 int err;
3461
3462 memset(&ev, 0, sizeof(ev));
3463 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
3464
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003465 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003466 if (!cmd)
3467 goto send_event;
3468
3469 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02003470 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
Johan Hedbergca69b792011-11-11 18:10:00 +02003471 mgmt_status(status));
Johan Hedbergb312b1612011-03-16 14:29:37 +02003472 goto failed;
3473 }
3474
Johan Hedberg744cf192011-11-08 20:40:14 +02003475 update_eir(hdev);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03003476
Johan Hedbergaee9b212012-02-18 15:07:59 +02003477 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0, &ev,
Johan Hedbergb312b1612011-03-16 14:29:37 +02003478 sizeof(ev));
3479 if (err < 0)
3480 goto failed;
3481
3482send_event:
Johan Hedberg744cf192011-11-08 20:40:14 +02003483 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
Johan Hedbergb312b1612011-03-16 14:29:37 +02003484 cmd ? cmd->sk : NULL);
3485
3486failed:
3487 if (cmd)
3488 mgmt_pending_remove(cmd);
3489 return err;
3490}
Szymon Jancc35938b2011-03-22 13:12:21 +01003491
Johan Hedberg744cf192011-11-08 20:40:14 +02003492int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
3493 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01003494{
3495 struct pending_cmd *cmd;
3496 int err;
3497
Johan Hedberg744cf192011-11-08 20:40:14 +02003498 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01003499
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003500 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003501 if (!cmd)
3502 return -ENOENT;
3503
3504 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02003505 err = cmd_status(cmd->sk, hdev->id,
Johan Hedbergca69b792011-11-11 18:10:00 +02003506 MGMT_OP_READ_LOCAL_OOB_DATA,
3507 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01003508 } else {
3509 struct mgmt_rp_read_local_oob_data rp;
3510
3511 memcpy(rp.hash, hash, sizeof(rp.hash));
3512 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
3513
Johan Hedberg744cf192011-11-08 20:40:14 +02003514 err = cmd_complete(cmd->sk, hdev->id,
3515 MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergaee9b212012-02-18 15:07:59 +02003516 0, &rp, sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01003517 }
3518
3519 mgmt_pending_remove(cmd);
3520
3521 return err;
3522}
Johan Hedberge17acd42011-03-30 23:57:16 +03003523
Johan Hedberg48264f02011-11-09 13:58:58 +02003524int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Johan Hedberg561aafb2012-01-04 13:31:59 +02003525 u8 addr_type, u8 *dev_class, s8 rssi,
Johan Hedberge319d2e2012-01-15 19:51:59 +02003526 u8 cfm_name, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03003527{
Johan Hedberge319d2e2012-01-15 19:51:59 +02003528 char buf[512];
3529 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02003530 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03003531
Johan Hedberg1dc06092012-01-15 21:01:23 +02003532 /* Leave 5 bytes for a potential CoD field */
3533 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Andre Guedes7d262f82012-01-10 18:20:49 -03003534 return -EINVAL;
3535
Johan Hedberg1dc06092012-01-15 21:01:23 +02003536 memset(buf, 0, sizeof(buf));
3537
Johan Hedberge319d2e2012-01-15 19:51:59 +02003538 bacpy(&ev->addr.bdaddr, bdaddr);
3539 ev->addr.type = link_to_mgmt(link_type, addr_type);
3540 ev->rssi = rssi;
3541 ev->confirm_name = cfm_name;
Johan Hedberge17acd42011-03-30 23:57:16 +03003542
Johan Hedberg1dc06092012-01-15 21:01:23 +02003543 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02003544 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03003545
Johan Hedberg1dc06092012-01-15 21:01:23 +02003546 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
3547 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
3548 dev_class, 3);
3549
3550 put_unaligned_le16(eir_len, &ev->eir_len);
3551
3552 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03003553
Johan Hedberge319d2e2012-01-15 19:51:59 +02003554 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03003555}
Johan Hedberga88a9652011-03-30 13:18:12 +03003556
Johan Hedbergb644ba32012-01-17 21:48:47 +02003557int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
3558 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03003559{
Johan Hedbergb644ba32012-01-17 21:48:47 +02003560 struct mgmt_ev_device_found *ev;
3561 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
3562 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03003563
Johan Hedbergb644ba32012-01-17 21:48:47 +02003564 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03003565
Johan Hedbergb644ba32012-01-17 21:48:47 +02003566 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03003567
Johan Hedbergb644ba32012-01-17 21:48:47 +02003568 bacpy(&ev->addr.bdaddr, bdaddr);
3569 ev->addr.type = link_to_mgmt(link_type, addr_type);
3570 ev->rssi = rssi;
3571
3572 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
3573 name_len);
3574
3575 put_unaligned_le16(eir_len, &ev->eir_len);
3576
Johan Hedberg053c7e02012-02-04 00:06:00 +02003577 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev,
3578 sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03003579}
Johan Hedberg314b2382011-04-27 10:29:57 -04003580
Andre Guedes7a135102011-11-09 17:14:25 -03003581int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
Johan Hedberg164a6e72011-11-01 17:06:44 +02003582{
3583 struct pending_cmd *cmd;
Johan Hedbergf808e162012-02-19 12:52:07 +02003584 u8 type;
Johan Hedberg164a6e72011-11-01 17:06:44 +02003585 int err;
3586
Andre Guedes203159d2012-02-13 15:41:01 -03003587 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3588
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003589 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003590 if (!cmd)
3591 return -ENOENT;
3592
Johan Hedbergf808e162012-02-19 12:52:07 +02003593 type = hdev->discovery.type;
3594
3595 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
3596 &type, sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02003597 mgmt_pending_remove(cmd);
3598
3599 return err;
3600}
3601
Andre Guedese6d465c2011-11-09 17:14:26 -03003602int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
3603{
3604 struct pending_cmd *cmd;
3605 int err;
3606
3607 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
3608 if (!cmd)
3609 return -ENOENT;
3610
Johan Hedbergd9306502012-02-20 23:25:18 +02003611 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
3612 &hdev->discovery.type,
3613 sizeof(hdev->discovery.type));
Johan Hedberg03811012010-12-08 00:21:06 +02003614 mgmt_pending_remove(cmd);
3615
3616 return err;
3617}
Johan Hedberg314b2382011-04-27 10:29:57 -04003618
Johan Hedberg744cf192011-11-08 20:40:14 +02003619int mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04003620{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02003621 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02003622 struct pending_cmd *cmd;
3623
Andre Guedes343fb142011-11-22 17:14:19 -03003624 BT_DBG("%s discovering %u", hdev->name, discovering);
3625
Johan Hedberg164a6e72011-11-01 17:06:44 +02003626 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003627 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003628 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003629 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003630
3631 if (cmd != NULL) {
Johan Hedbergf808e162012-02-19 12:52:07 +02003632 u8 type = hdev->discovery.type;
3633
Johan Hedbergd9306502012-02-20 23:25:18 +02003634 cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0,
Johan Hedbergf808e162012-02-19 12:52:07 +02003635 &type, sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02003636 mgmt_pending_remove(cmd);
3637 }
3638
Johan Hedbergf963e8e2012-02-20 23:30:44 +02003639 memset(&ev, 0, sizeof(ev));
3640 ev.type = hdev->discovery.type;
3641 ev.discovering = discovering;
3642
3643 return mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04003644}
Antti Julku5e762442011-08-25 16:48:02 +03003645
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003646int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003647{
3648 struct pending_cmd *cmd;
3649 struct mgmt_ev_device_blocked ev;
3650
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003651 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003652
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003653 bacpy(&ev.addr.bdaddr, bdaddr);
3654 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003655
Johan Hedberg744cf192011-11-08 20:40:14 +02003656 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
3657 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003658}
3659
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003660int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003661{
3662 struct pending_cmd *cmd;
3663 struct mgmt_ev_device_unblocked ev;
3664
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003665 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003666
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003667 bacpy(&ev.addr.bdaddr, bdaddr);
3668 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003669
Johan Hedberg744cf192011-11-08 20:40:14 +02003670 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
3671 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003672}
Marcel Holtmannd7b7e792012-02-20 21:47:49 +01003673
3674module_param(enable_hs, bool, 0644);
3675MODULE_PARM_DESC(enable_hs, "Enable High Speed support");
3676
3677module_param(enable_le, bool, 0644);
3678MODULE_PARM_DESC(enable_le, "Enable Low Energy support");