blob: cf8c8403571e3636188912f7634f11317d4788aa [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
Johan Hedberg06199cf2012-02-22 16:37:11 +0200410 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
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
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200535 if (!hdev_is_powered(hdev))
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200536 return 0;
537
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300538 if (!(hdev->features[6] & LMP_EXT_INQ))
539 return 0;
540
Johan Hedberg84bde9d2012-01-25 14:21:06 +0200541 if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300542 return 0;
543
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200544 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300545 return 0;
546
547 memset(&cp, 0, sizeof(cp));
548
549 create_eir(hdev, cp.data);
550
551 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
552 return 0;
553
554 memcpy(hdev->eir, cp.data, sizeof(cp.data));
555
556 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
557}
558
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200559static u8 get_service_classes(struct hci_dev *hdev)
560{
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300561 struct bt_uuid *uuid;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200562 u8 val = 0;
563
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300564 list_for_each_entry(uuid, &hdev->uuids, list)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200565 val |= uuid->svc_hint;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200566
567 return val;
568}
569
570static int update_class(struct hci_dev *hdev)
571{
572 u8 cod[3];
Johan Hedbergc95f0ba2012-02-23 22:54:38 +0200573 int err;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200574
575 BT_DBG("%s", hdev->name);
576
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200577 if (!hdev_is_powered(hdev))
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200578 return 0;
579
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200580 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200581 return 0;
582
583 cod[0] = hdev->minor_class;
584 cod[1] = hdev->major_class;
585 cod[2] = get_service_classes(hdev);
586
587 if (memcmp(cod, hdev->dev_class, 3) == 0)
588 return 0;
589
Johan Hedbergc95f0ba2012-02-23 22:54:38 +0200590 err = hci_send_cmd(hdev, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
591 if (err == 0)
592 set_bit(HCI_PENDING_CLASS, &hdev->dev_flags);
593
594 return err;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200595}
596
Johan Hedberg7d785252011-12-15 00:47:39 +0200597static void service_cache_off(struct work_struct *work)
598{
599 struct hci_dev *hdev = container_of(work, struct hci_dev,
600 service_cache.work);
601
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200602 if (!test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200603 return;
604
605 hci_dev_lock(hdev);
606
607 update_eir(hdev);
608 update_class(hdev);
609
610 hci_dev_unlock(hdev);
611}
612
Johan Hedberg6a919082012-02-28 06:17:26 +0200613static void mgmt_init_hdev(struct sock *sk, struct hci_dev *hdev)
Johan Hedberg7d785252011-12-15 00:47:39 +0200614{
Johan Hedberg6a919082012-02-28 06:17:26 +0200615 if (!test_and_clear_bit(HCI_PI_MGMT_INIT, &hci_pi(sk)->flags))
616 return;
617
Johan Hedberg0cbf4ed2012-02-21 17:25:22 +0200618 if (!test_and_set_bit(HCI_MGMT, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +0200619 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
620
Johan Hedberg0cbf4ed2012-02-21 17:25:22 +0200621 /* Non-mgmt controlled devices get this bit set
622 * implicitly so that pairing works for them, however
623 * for mgmt we require user-space to explicitly enable
624 * it
625 */
626 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
627 }
Johan Hedberg7d785252011-12-15 00:47:39 +0200628}
629
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200630static int read_controller_info(struct sock *sk, struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +0200631{
632 struct mgmt_rp_read_info rp;
Johan Hedberg03811012010-12-08 00:21:06 +0200633
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200634 BT_DBG("sock %p %s", sk, hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200635
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300636 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200637
Johan Hedberg03811012010-12-08 00:21:06 +0200638 memset(&rp, 0, sizeof(rp));
639
Johan Hedberg03811012010-12-08 00:21:06 +0200640 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200641
642 rp.version = hdev->hci_ver;
643
Johan Hedberg03811012010-12-08 00:21:06 +0200644 put_unaligned_le16(hdev->manufacturer, &rp.manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200645
646 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
647 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
648
649 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedberg03811012010-12-08 00:21:06 +0200650
651 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
Johan Hedberg27fcc362012-02-22 21:46:22 +0200652 memcpy(rp.short_name, hdev->short_name, sizeof(hdev->short_name));
Johan Hedberg03811012010-12-08 00:21:06 +0200653
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300654 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200655
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200656 return cmd_complete(sk, hdev->id, MGMT_OP_READ_INFO, 0, &rp,
657 sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +0200658}
659
660static void mgmt_pending_free(struct pending_cmd *cmd)
661{
662 sock_put(cmd->sk);
663 kfree(cmd->param);
664 kfree(cmd);
665}
666
667static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
668 struct hci_dev *hdev,
669 void *data, u16 len)
670{
671 struct pending_cmd *cmd;
672
673 cmd = kmalloc(sizeof(*cmd), GFP_ATOMIC);
674 if (!cmd)
675 return NULL;
676
677 cmd->opcode = opcode;
678 cmd->index = hdev->id;
679
680 cmd->param = kmalloc(len, GFP_ATOMIC);
681 if (!cmd->param) {
682 kfree(cmd);
683 return NULL;
684 }
685
686 if (data)
687 memcpy(cmd->param, data, len);
688
689 cmd->sk = sk;
690 sock_hold(sk);
691
692 list_add(&cmd->list, &hdev->mgmt_pending);
693
694 return cmd;
695}
696
697static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
698 void (*cb)(struct pending_cmd *cmd, void *data),
699 void *data)
700{
701 struct list_head *p, *n;
702
703 list_for_each_safe(p, n, &hdev->mgmt_pending) {
704 struct pending_cmd *cmd;
705
706 cmd = list_entry(p, struct pending_cmd, list);
707
708 if (opcode > 0 && cmd->opcode != opcode)
709 continue;
710
711 cb(cmd, data);
712 }
713}
714
715static struct pending_cmd *mgmt_pending_find(u16 opcode, struct hci_dev *hdev)
716{
717 struct pending_cmd *cmd;
718
719 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
720 if (cmd->opcode == opcode)
721 return cmd;
722 }
723
724 return NULL;
725}
726
727static void mgmt_pending_remove(struct pending_cmd *cmd)
728{
729 list_del(&cmd->list);
730 mgmt_pending_free(cmd);
731}
732
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200733static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +0200734{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200735 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +0200736
Johan Hedbergaee9b212012-02-18 15:07:59 +0200737 return cmd_complete(sk, hdev->id, opcode, 0, &settings,
738 sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +0200739}
740
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200741static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data,
742 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200743{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300744 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200745 struct pending_cmd *cmd;
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200746 int err;
Johan Hedberg03811012010-12-08 00:21:06 +0200747
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200748 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200749
750 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200751 return cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
Johan Hedbergca69b792011-11-11 18:10:00 +0200752 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200753
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300754 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200755
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100756 if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) {
757 cancel_delayed_work(&hdev->power_off);
758
759 if (cp->val) {
760 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
761 mgmt_powered(hdev, 1);
762 goto failed;
763 }
764 }
765
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200766 if (!!cp->val == hdev_is_powered(hdev)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200767 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200768 goto failed;
769 }
770
771 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200772 err = cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
Johan Hedbergca69b792011-11-11 18:10:00 +0200773 MGMT_STATUS_BUSY);
Johan Hedberg03811012010-12-08 00:21:06 +0200774 goto failed;
775 }
776
777 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
778 if (!cmd) {
779 err = -ENOMEM;
780 goto failed;
781 }
782
783 if (cp->val)
Gustavo F. Padovan7f971042011-12-18 12:40:32 -0200784 schedule_work(&hdev->power_on);
Johan Hedberg03811012010-12-08 00:21:06 +0200785 else
Gustavo F. Padovan80b7ab32011-12-17 14:52:27 -0200786 schedule_work(&hdev->power_off.work);
Johan Hedberg03811012010-12-08 00:21:06 +0200787
788 err = 0;
789
790failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300791 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200792 return err;
793}
794
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200795static int mgmt_event(u16 event, struct hci_dev *hdev, void *data,
796 u16 data_len, struct sock *skip_sk)
797{
798 struct sk_buff *skb;
799 struct mgmt_hdr *hdr;
800
801 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_ATOMIC);
802 if (!skb)
803 return -ENOMEM;
804
805 hdr = (void *) skb_put(skb, sizeof(*hdr));
806 hdr->opcode = cpu_to_le16(event);
807 if (hdev)
808 hdr->index = cpu_to_le16(hdev->id);
809 else
810 hdr->index = cpu_to_le16(MGMT_INDEX_NONE);
811 hdr->len = cpu_to_le16(data_len);
812
813 if (data)
814 memcpy(skb_put(skb, data_len), data, data_len);
815
Marcel Holtmann97e0bde2012-02-22 13:49:28 +0100816 /* Time stamp */
817 __net_timestamp(skb);
818
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200819 hci_send_to_control(skb, skip_sk);
820 kfree_skb(skb);
821
822 return 0;
823}
824
825static int new_settings(struct hci_dev *hdev, struct sock *skip)
826{
827 __le32 ev;
828
829 ev = cpu_to_le32(get_current_settings(hdev));
830
831 return mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), skip);
832}
833
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200834static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
835 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200836{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300837 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200838 struct pending_cmd *cmd;
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200839 u16 timeout;
Johan Hedberg03811012010-12-08 00:21:06 +0200840 u8 scan;
841 int err;
842
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200843 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200844
845 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200846 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +0200847 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200848
Marcel Holtmann24c54a92012-02-22 18:06:34 +0100849 timeout = get_unaligned_le16(&cp->timeout);
850 if (!cp->val && timeout > 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200851 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +0200852 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200853
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300854 hci_dev_lock(hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200855
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200856 if (!hdev_is_powered(hdev) && timeout > 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200857 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +0200858 MGMT_STATUS_NOT_POWERED);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200859 goto failed;
860 }
861
862 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
863 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200864 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +0200865 MGMT_STATUS_BUSY);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200866 goto failed;
867 }
868
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200869 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200870 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200871 MGMT_STATUS_REJECTED);
872 goto failed;
873 }
874
875 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200876 bool changed = false;
877
878 if (!!cp->val != test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
879 change_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
880 changed = true;
881 }
882
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200883 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200884 if (err < 0)
885 goto failed;
886
887 if (changed)
888 err = new_settings(hdev, sk);
889
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200890 goto failed;
891 }
892
893 if (!!cp->val == test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
Marcel Holtmann955638e2012-02-22 18:21:00 +0100894 if (hdev->discov_timeout > 0) {
895 cancel_delayed_work(&hdev->discov_off);
896 hdev->discov_timeout = 0;
897 }
898
899 if (cp->val && timeout > 0) {
900 hdev->discov_timeout = timeout;
901 queue_delayed_work(hdev->workqueue, &hdev->discov_off,
902 msecs_to_jiffies(hdev->discov_timeout * 1000));
903 }
904
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200905 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200906 goto failed;
907 }
908
909 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
910 if (!cmd) {
911 err = -ENOMEM;
912 goto failed;
913 }
914
915 scan = SCAN_PAGE;
916
917 if (cp->val)
918 scan |= SCAN_INQUIRY;
919 else
920 cancel_delayed_work(&hdev->discov_off);
921
922 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
923 if (err < 0)
924 mgmt_pending_remove(cmd);
925
Johan Hedberg03811012010-12-08 00:21:06 +0200926 if (cp->val)
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200927 hdev->discov_timeout = timeout;
Johan Hedberg03811012010-12-08 00:21:06 +0200928
929failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300930 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200931 return err;
932}
933
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200934static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
935 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200936{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300937 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200938 struct pending_cmd *cmd;
939 u8 scan;
940 int err;
941
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200942 BT_DBG("request for %s", hdev->name);
Johan Hedberge41d8b42010-12-13 21:07:03 +0200943
Johan Hedberg03811012010-12-08 00:21:06 +0200944 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200945 return cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +0200946 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200947
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300948 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200949
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200950 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200951 bool changed = false;
952
953 if (!!cp->val != test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
954 changed = true;
955
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +0200956 if (cp->val) {
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200957 set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +0200958 } else {
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200959 clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
960 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
961 }
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200962
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200963 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200964 if (err < 0)
965 goto failed;
966
967 if (changed)
968 err = new_settings(hdev, sk);
969
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200970 goto failed;
971 }
972
973 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
974 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200975 err = cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +0200976 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200977 goto failed;
978 }
979
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200980 if (!!cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200981 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200982 goto failed;
983 }
984
985 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
986 if (!cmd) {
987 err = -ENOMEM;
988 goto failed;
989 }
990
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +0200991 if (cp->val) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200992 scan = SCAN_PAGE;
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +0200993 } else {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200994 scan = 0;
995
Johan Hedbergdf2c6c52012-02-21 19:15:49 +0200996 if (test_bit(HCI_ISCAN, &hdev->flags) &&
997 hdev->discov_timeout > 0)
998 cancel_delayed_work(&hdev->discov_off);
999 }
1000
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001001 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1002 if (err < 0)
1003 mgmt_pending_remove(cmd);
1004
1005failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001006 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001007 return err;
1008}
1009
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001010static int set_pairable(struct sock *sk, struct hci_dev *hdev, void *data,
1011 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001012{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001013 struct mgmt_mode *cp = data;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001014 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001015
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001016 BT_DBG("request for %s", hdev->name);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001017
1018 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001019 return cmd_status(sk, hdev->id, MGMT_OP_SET_PAIRABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02001020 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001021
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001022 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001023
1024 if (cp->val)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001025 set_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001026 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001027 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001028
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001029 err = send_settings_rsp(sk, MGMT_OP_SET_PAIRABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001030 if (err < 0)
1031 goto failed;
1032
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001033 err = new_settings(hdev, sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001034
1035failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001036 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001037 return err;
1038}
Johan Hedberg72a734e2010-12-30 00:38:22 +02001039
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001040static int set_link_security(struct sock *sk, struct hci_dev *hdev,
1041 void *data, u16 len)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001042{
1043 struct mgmt_mode *cp = data;
1044 struct pending_cmd *cmd;
Johan Hedberg816a11d2012-02-26 13:04:52 +02001045 u8 val;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001046 int err;
1047
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001048 BT_DBG("request for %s", hdev->name);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001049
1050 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001051 return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001052 MGMT_STATUS_INVALID_PARAMS);
1053
1054 hci_dev_lock(hdev);
1055
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001056 if (!hdev_is_powered(hdev)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001057 bool changed = false;
1058
1059 if (!!cp->val != test_bit(HCI_LINK_SECURITY,
1060 &hdev->dev_flags)) {
1061 change_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
1062 changed = true;
1063 }
1064
1065 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1066 if (err < 0)
1067 goto failed;
1068
1069 if (changed)
1070 err = new_settings(hdev, sk);
1071
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001072 goto failed;
1073 }
1074
1075 if (mgmt_pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001076 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001077 MGMT_STATUS_BUSY);
1078 goto failed;
1079 }
1080
1081 val = !!cp->val;
1082
1083 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1084 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1085 goto failed;
1086 }
1087
1088 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1089 if (!cmd) {
1090 err = -ENOMEM;
1091 goto failed;
1092 }
1093
1094 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1095 if (err < 0) {
1096 mgmt_pending_remove(cmd);
1097 goto failed;
1098 }
1099
1100failed:
1101 hci_dev_unlock(hdev);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001102 return err;
1103}
1104
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001105static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001106{
1107 struct mgmt_mode *cp = data;
1108 struct pending_cmd *cmd;
Johan Hedberg816a11d2012-02-26 13:04:52 +02001109 u8 val;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001110 int err;
1111
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001112 BT_DBG("request for %s", hdev->name);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001113
1114 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001115 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001116 MGMT_STATUS_INVALID_PARAMS);
1117
1118 hci_dev_lock(hdev);
1119
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001120 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001121 err = cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001122 MGMT_STATUS_NOT_SUPPORTED);
1123 goto failed;
1124 }
1125
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001126 val = !!cp->val;
1127
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001128 if (!hdev_is_powered(hdev)) {
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001129 bool changed = false;
1130
1131 if (val != test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) {
1132 change_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
1133 changed = true;
1134 }
1135
1136 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1137 if (err < 0)
1138 goto failed;
1139
1140 if (changed)
1141 err = new_settings(hdev, sk);
1142
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001143 goto failed;
1144 }
1145
1146 if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001147 err = cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1148 MGMT_STATUS_BUSY);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001149 goto failed;
1150 }
1151
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001152 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) == val) {
1153 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1154 goto failed;
1155 }
1156
1157 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1158 if (!cmd) {
1159 err = -ENOMEM;
1160 goto failed;
1161 }
1162
1163 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, sizeof(val), &val);
1164 if (err < 0) {
1165 mgmt_pending_remove(cmd);
1166 goto failed;
1167 }
1168
1169failed:
1170 hci_dev_unlock(hdev);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001171 return err;
1172}
1173
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001174static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001175{
1176 struct mgmt_mode *cp = data;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001177
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001178 BT_DBG("request for %s", hdev->name);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001179
1180 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001181 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001182 MGMT_STATUS_INVALID_PARAMS);
1183
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001184 if (!enable_hs)
1185 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1186 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001187
1188 if (cp->val)
1189 set_bit(HCI_HS_ENABLED, &hdev->dev_flags);
1190 else
1191 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
1192
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001193 return send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001194}
1195
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001196static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001197{
1198 struct mgmt_mode *cp = data;
1199 struct hci_cp_write_le_host_supported hci_cp;
1200 struct pending_cmd *cmd;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001201 int err;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001202 u8 val, enabled;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001203
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001204 BT_DBG("request for %s", hdev->name);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001205
1206 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001207 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
Johan Hedberg06199cf2012-02-22 16:37:11 +02001208 MGMT_STATUS_INVALID_PARAMS);
1209
Johan Hedberg1de028c2012-02-29 19:55:35 -08001210 hci_dev_lock(hdev);
1211
Johan Hedberg06199cf2012-02-22 16:37:11 +02001212 if (!enable_le || !(hdev->features[4] & LMP_LE)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001213 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
Johan Hedberg06199cf2012-02-22 16:37:11 +02001214 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001215 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001216 }
1217
1218 val = !!cp->val;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001219 enabled = !!(hdev->host_features[0] & LMP_HOST_LE);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001220
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001221 if (!hdev_is_powered(hdev) || val == enabled) {
Johan Hedberg06199cf2012-02-22 16:37:11 +02001222 bool changed = false;
1223
1224 if (val != test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
1225 change_bit(HCI_LE_ENABLED, &hdev->dev_flags);
1226 changed = true;
1227 }
1228
1229 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1230 if (err < 0)
Johan Hedberg1de028c2012-02-29 19:55:35 -08001231 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001232
1233 if (changed)
1234 err = new_settings(hdev, sk);
1235
Johan Hedberg1de028c2012-02-29 19:55:35 -08001236 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001237 }
1238
1239 if (mgmt_pending_find(MGMT_OP_SET_LE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001240 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1241 MGMT_STATUS_BUSY);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001242 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001243 }
1244
1245 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
1246 if (!cmd) {
1247 err = -ENOMEM;
Johan Hedberg1de028c2012-02-29 19:55:35 -08001248 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001249 }
1250
1251 memset(&hci_cp, 0, sizeof(hci_cp));
1252
1253 if (val) {
1254 hci_cp.le = val;
1255 hci_cp.simul = !!(hdev->features[6] & LMP_SIMUL_LE_BR);
1256 }
1257
1258 err = hci_send_cmd(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED,
1259 sizeof(hci_cp), &hci_cp);
1260 if (err < 0) {
1261 mgmt_pending_remove(cmd);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001262 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001263 }
1264
Johan Hedberg1de028c2012-02-29 19:55:35 -08001265unlock:
1266 hci_dev_unlock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001267 return err;
1268}
1269
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001270static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001271{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001272 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001273 struct pending_cmd *cmd;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001274 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001275 int err;
1276
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001277 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001278
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001279 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001280 return cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID,
Johan Hedbergca69b792011-11-11 18:10:00 +02001281 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001282
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001283 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001284
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001285 if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001286 err = cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID,
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001287 MGMT_STATUS_BUSY);
1288 goto failed;
1289 }
1290
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001291 uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC);
1292 if (!uuid) {
1293 err = -ENOMEM;
1294 goto failed;
1295 }
1296
1297 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001298 uuid->svc_hint = cp->svc_hint;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001299
1300 list_add(&uuid->list, &hdev->uuids);
1301
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001302 err = update_class(hdev);
1303 if (err < 0)
1304 goto failed;
1305
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001306 err = update_eir(hdev);
1307 if (err < 0)
1308 goto failed;
1309
Johan Hedberg90e70452012-02-23 23:09:40 +02001310 if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001311 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0,
Johan Hedberg90e70452012-02-23 23:09:40 +02001312 hdev->dev_class, 3);
1313 goto failed;
1314 }
1315
1316 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len);
1317 if (!cmd) {
1318 err = -ENOMEM;
1319 goto failed;
1320 }
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001321
1322failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001323 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001324 return err;
1325}
1326
Johan Hedberg24b78d02012-02-23 23:24:30 +02001327static bool enable_service_cache(struct hci_dev *hdev)
1328{
1329 if (!hdev_is_powered(hdev))
1330 return false;
1331
1332 if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
1333 schedule_delayed_work(&hdev->service_cache,
1334 msecs_to_jiffies(SERVICE_CACHE_TIMEOUT));
1335 return true;
1336 }
1337
1338 return false;
1339}
1340
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001341static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
1342 u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001343{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001344 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001345 struct pending_cmd *cmd;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001346 struct list_head *p, *n;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001347 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 +02001348 int err, found;
1349
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001350 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001351
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001352 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001353 return cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Johan Hedbergca69b792011-11-11 18:10:00 +02001354 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001355
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001356 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001357
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001358 if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001359 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001360 MGMT_STATUS_BUSY);
1361 goto unlock;
1362 }
1363
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001364 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
1365 err = hci_uuids_clear(hdev);
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001366
Johan Hedberg24b78d02012-02-23 23:24:30 +02001367 if (enable_service_cache(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001368 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID,
1369 0, hdev->dev_class, 3);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001370 goto unlock;
1371 }
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001372
Johan Hedberg9246a862012-02-23 21:33:16 +02001373 goto update_class;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001374 }
1375
1376 found = 0;
1377
1378 list_for_each_safe(p, n, &hdev->uuids) {
1379 struct bt_uuid *match = list_entry(p, struct bt_uuid, list);
1380
1381 if (memcmp(match->uuid, cp->uuid, 16) != 0)
1382 continue;
1383
1384 list_del(&match->list);
1385 found++;
1386 }
1387
1388 if (found == 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001389 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Johan Hedbergca69b792011-11-11 18:10:00 +02001390 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001391 goto unlock;
1392 }
1393
Johan Hedberg9246a862012-02-23 21:33:16 +02001394update_class:
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001395 err = update_class(hdev);
1396 if (err < 0)
1397 goto unlock;
1398
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001399 err = update_eir(hdev);
1400 if (err < 0)
1401 goto unlock;
1402
Johan Hedberg90e70452012-02-23 23:09:40 +02001403 if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001404 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0,
Johan Hedberg9997a532012-02-23 15:57:46 +02001405 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001406 goto unlock;
1407 }
1408
1409 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
1410 if (!cmd) {
1411 err = -ENOMEM;
1412 goto unlock;
1413 }
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001414
1415unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001416 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001417 return err;
1418}
1419
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001420static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
1421 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001422{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001423 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001424 struct pending_cmd *cmd;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001425 int err;
1426
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001427 BT_DBG("request for %s", hdev->name);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001428
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001429 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001430 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
Johan Hedbergca69b792011-11-11 18:10:00 +02001431 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001432
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001433 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001434
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001435 if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001436 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001437 MGMT_STATUS_BUSY);
1438 goto unlock;
1439 }
1440
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001441 hdev->major_class = cp->major;
1442 hdev->minor_class = cp->minor;
1443
Johan Hedberg932f5ff2012-02-22 22:11:32 +02001444 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001445 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Johan Hedberg932f5ff2012-02-22 22:11:32 +02001446 hdev->dev_class, 3);
1447 goto unlock;
1448 }
1449
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001450 if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02001451 hci_dev_unlock(hdev);
1452 cancel_delayed_work_sync(&hdev->service_cache);
1453 hci_dev_lock(hdev);
Johan Hedberg14c0b602011-12-15 00:47:37 +02001454 update_eir(hdev);
Johan Hedberg7d785252011-12-15 00:47:39 +02001455 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02001456
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001457 err = update_class(hdev);
Johan Hedberg90e70452012-02-23 23:09:40 +02001458 if (err < 0)
1459 goto unlock;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001460
Johan Hedberg90e70452012-02-23 23:09:40 +02001461 if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001462 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Johan Hedberg8ec37032012-02-22 22:02:50 +02001463 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001464 goto unlock;
1465 }
1466
1467 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
1468 if (!cmd) {
1469 err = -ENOMEM;
1470 goto unlock;
1471 }
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001472
Johan Hedbergb5235a62012-02-21 14:32:24 +02001473unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001474 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001475 return err;
1476}
1477
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001478static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
1479 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001480{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001481 struct mgmt_cp_load_link_keys *cp = data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001482 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001483 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001484
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001485 if (len < sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001486 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
Johan Hedbergca69b792011-11-11 18:10:00 +02001487 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001488
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001489 key_count = get_unaligned_le16(&cp->key_count);
1490
Johan Hedberg86742e12011-11-07 23:13:38 +02001491 expected_len = sizeof(*cp) + key_count *
1492 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001493 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001494 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001495 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001496 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
Johan Hedbergca69b792011-11-11 18:10:00 +02001497 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001498 }
1499
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001500 BT_DBG("%s debug_keys %u key_count %u", hdev->name, cp->debug_keys,
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001501 key_count);
1502
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001503 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001504
1505 hci_link_keys_clear(hdev);
1506
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001507 set_bit(HCI_LINK_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001508
1509 if (cp->debug_keys)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001510 set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001511 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001512 clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001513
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001514 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001515 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001516
Johan Hedbergd753fdc2012-02-17 14:06:34 +02001517 hci_add_link_key(hdev, NULL, 0, &key->addr.bdaddr, key->val,
1518 key->type, key->pin_len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001519 }
1520
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001521 cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02001522
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001523 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001524
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001525 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001526}
1527
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001528static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
1529 u8 addr_type, struct sock *skip_sk)
1530{
1531 struct mgmt_ev_device_unpaired ev;
1532
1533 bacpy(&ev.addr.bdaddr, bdaddr);
1534 ev.addr.type = addr_type;
1535
1536 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
1537 skip_sk);
1538}
1539
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001540static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
1541 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001542{
Johan Hedberg124f6e32012-02-09 13:50:12 +02001543 struct mgmt_cp_unpair_device *cp = data;
1544 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001545 struct hci_cp_disconnect dc;
1546 struct pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001547 struct hci_conn *conn;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001548 int err;
1549
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001550 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001551 return cmd_status(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02001552 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001553
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001554 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001555
Johan Hedberga8a1d192011-11-10 15:54:38 +02001556 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02001557 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1558 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001559
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001560 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001561 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001562 MGMT_STATUS_NOT_POWERED,
1563 &rp, sizeof(rp));
1564 goto unlock;
1565 }
1566
Johan Hedberg124f6e32012-02-09 13:50:12 +02001567 if (cp->addr.type == MGMT_ADDR_BREDR)
1568 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
1569 else
1570 err = hci_remove_ltk(hdev, &cp->addr.bdaddr);
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03001571
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001572 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001573 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001574 MGMT_STATUS_NOT_PAIRED,
1575 &rp, sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001576 goto unlock;
1577 }
1578
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001579 if (cp->disconnect) {
1580 if (cp->addr.type == MGMT_ADDR_BREDR)
1581 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
1582 &cp->addr.bdaddr);
1583 else
1584 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
1585 &cp->addr.bdaddr);
1586 } else {
1587 conn = NULL;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001588 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001589
Johan Hedberga8a1d192011-11-10 15:54:38 +02001590 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001591 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0,
Johan Hedbergaee9b212012-02-18 15:07:59 +02001592 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001593 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001594 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001595 }
1596
Johan Hedberg124f6e32012-02-09 13:50:12 +02001597 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
1598 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02001599 if (!cmd) {
1600 err = -ENOMEM;
1601 goto unlock;
1602 }
1603
1604 put_unaligned_le16(conn->handle, &dc.handle);
1605 dc.reason = 0x13; /* Remote User Terminated Connection */
1606 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1607 if (err < 0)
1608 mgmt_pending_remove(cmd);
1609
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001610unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001611 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001612 return err;
1613}
1614
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001615static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
1616 u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02001617{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001618 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001619 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03001620 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001621 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001622 int err;
1623
1624 BT_DBG("");
1625
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001626 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001627 return cmd_status(sk, hdev->id, MGMT_OP_DISCONNECT,
Johan Hedbergca69b792011-11-11 18:10:00 +02001628 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001629
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001630 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001631
1632 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001633 err = cmd_status(sk, hdev->id, MGMT_OP_DISCONNECT,
Johan Hedbergca69b792011-11-11 18:10:00 +02001634 MGMT_STATUS_NOT_POWERED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001635 goto failed;
1636 }
1637
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001638 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001639 err = cmd_status(sk, hdev->id, MGMT_OP_DISCONNECT,
Johan Hedbergca69b792011-11-11 18:10:00 +02001640 MGMT_STATUS_BUSY);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001641 goto failed;
1642 }
1643
Johan Hedberg88c3df12012-02-09 14:27:38 +02001644 if (cp->addr.type == MGMT_ADDR_BREDR)
1645 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
1646 else
1647 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03001648
Johan Hedberg8962ee72011-01-20 12:40:27 +02001649 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001650 err = cmd_status(sk, hdev->id, MGMT_OP_DISCONNECT,
Johan Hedbergca69b792011-11-11 18:10:00 +02001651 MGMT_STATUS_NOT_CONNECTED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001652 goto failed;
1653 }
1654
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001655 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001656 if (!cmd) {
1657 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001658 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001659 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001660
1661 put_unaligned_le16(conn->handle, &dc.handle);
1662 dc.reason = 0x13; /* Remote User Terminated Connection */
1663
1664 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1665 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001666 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001667
1668failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001669 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001670 return err;
1671}
1672
Johan Hedberg48264f02011-11-09 13:58:58 +02001673static u8 link_to_mgmt(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02001674{
1675 switch (link_type) {
1676 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02001677 switch (addr_type) {
1678 case ADDR_LE_DEV_PUBLIC:
1679 return MGMT_ADDR_LE_PUBLIC;
1680 case ADDR_LE_DEV_RANDOM:
1681 return MGMT_ADDR_LE_RANDOM;
1682 default:
1683 return MGMT_ADDR_INVALID;
1684 }
Johan Hedberg4c659c32011-11-07 23:13:39 +02001685 case ACL_LINK:
1686 return MGMT_ADDR_BREDR;
1687 default:
1688 return MGMT_ADDR_INVALID;
1689 }
1690}
1691
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001692static int get_connections(struct sock *sk, struct hci_dev *hdev)
Johan Hedberg2784eb42011-01-21 13:56:35 +02001693{
Johan Hedberg2784eb42011-01-21 13:56:35 +02001694 struct mgmt_rp_get_connections *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001695 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02001696 size_t rp_len;
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001697 int err;
1698 u16 i;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001699
1700 BT_DBG("");
1701
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001702 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001703
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001704 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001705 err = cmd_status(sk, hdev->id, MGMT_OP_GET_CONNECTIONS,
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001706 MGMT_STATUS_NOT_POWERED);
1707 goto unlock;
1708 }
1709
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001710 i = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02001711 list_for_each_entry(c, &hdev->conn_hash.list, list) {
1712 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001713 i++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001714 }
1715
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001716 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberga38528f2011-01-22 06:46:43 +02001717 rp = kmalloc(rp_len, GFP_ATOMIC);
1718 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02001719 err = -ENOMEM;
1720 goto unlock;
1721 }
1722
Johan Hedberg2784eb42011-01-21 13:56:35 +02001723 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001724 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02001725 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
1726 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001727 bacpy(&rp->addr[i].bdaddr, &c->dst);
Johan Hedberg48264f02011-11-09 13:58:58 +02001728 rp->addr[i].type = link_to_mgmt(c->type, c->dst_type);
Johan Hedberg4c659c32011-11-07 23:13:39 +02001729 if (rp->addr[i].type == MGMT_ADDR_INVALID)
1730 continue;
1731 i++;
1732 }
1733
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001734 put_unaligned_le16(i, &rp->conn_count);
1735
Johan Hedberg4c659c32011-11-07 23:13:39 +02001736 /* Recalculate length in case of filtered SCO connections, etc */
1737 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02001738
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001739 err = cmd_complete(sk, hdev->id, MGMT_OP_GET_CONNECTIONS, 0, rp,
1740 rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001741
Johan Hedberga38528f2011-01-22 06:46:43 +02001742 kfree(rp);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001743
1744unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001745 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001746 return err;
1747}
1748
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001749static int send_pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
1750 struct mgmt_cp_pin_code_neg_reply *cp)
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001751{
1752 struct pending_cmd *cmd;
1753 int err;
1754
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001755 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001756 sizeof(*cp));
1757 if (!cmd)
1758 return -ENOMEM;
1759
Johan Hedbergd8457692012-02-17 14:24:57 +02001760 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
1761 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001762 if (err < 0)
1763 mgmt_pending_remove(cmd);
1764
1765 return err;
1766}
1767
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001768static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data,
1769 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001770{
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001771 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001772 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001773 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03001774 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001775 int err;
1776
1777 BT_DBG("");
1778
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001779 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001780 return cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001781 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001782
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001783 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001784
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001785 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001786 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001787 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001788 goto failed;
1789 }
1790
Johan Hedbergd8457692012-02-17 14:24:57 +02001791 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001792 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001793 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001794 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001795 goto failed;
1796 }
1797
1798 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02001799 struct mgmt_cp_pin_code_neg_reply ncp;
1800
1801 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001802
1803 BT_ERR("PIN code is not 16 bytes long");
1804
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001805 err = send_pin_code_neg_reply(sk, hdev, &ncp);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001806 if (err >= 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001807 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001808 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001809
1810 goto failed;
1811 }
1812
Gustavo F. Padovan00abfe42012-03-01 00:37:10 -03001813 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001814 if (!cmd) {
1815 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001816 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001817 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02001818
Johan Hedbergd8457692012-02-17 14:24:57 +02001819 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001820 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02001821 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02001822
1823 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
1824 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001825 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001826
1827failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001828 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001829 return err;
1830}
1831
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001832static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
1833 void *data, u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001834{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001835 struct mgmt_cp_pin_code_neg_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001836 int err;
1837
1838 BT_DBG("");
1839
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001840 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001841 return cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001842 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001843
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001844 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001845
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001846 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001847 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001848 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001849 goto failed;
1850 }
1851
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001852 err = send_pin_code_neg_reply(sk, hdev, cp);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001853
1854failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001855 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001856 return err;
1857}
1858
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001859static int set_io_capability(struct sock *sk, struct hci_dev *hdev,
1860 void *data, u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001861{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001862 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001863
1864 BT_DBG("");
1865
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001866 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001867 return cmd_status(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001868 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001869
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001870 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001871
1872 hdev->io_capability = cp->io_capability;
1873
1874 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Szymon Jancb8534e02011-03-01 16:55:34 +01001875 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001876
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001877 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001878
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001879 return cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, 0,
1880 NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001881}
1882
Johan Hedberge9a416b2011-02-19 12:05:56 -03001883static inline struct pending_cmd *find_pairing(struct hci_conn *conn)
1884{
1885 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001886 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001887
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001888 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03001889 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
1890 continue;
1891
Johan Hedberge9a416b2011-02-19 12:05:56 -03001892 if (cmd->user_data != conn)
1893 continue;
1894
1895 return cmd;
1896 }
1897
1898 return NULL;
1899}
1900
1901static void pairing_complete(struct pending_cmd *cmd, u8 status)
1902{
1903 struct mgmt_rp_pair_device rp;
1904 struct hci_conn *conn = cmd->user_data;
1905
Johan Hedbergba4e5642011-11-11 00:07:34 +02001906 bacpy(&rp.addr.bdaddr, &conn->dst);
1907 rp.addr.type = link_to_mgmt(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001908
Johan Hedbergaee9b212012-02-18 15:07:59 +02001909 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, status,
1910 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001911
1912 /* So we don't get further callbacks for this connection */
1913 conn->connect_cfm_cb = NULL;
1914 conn->security_cfm_cb = NULL;
1915 conn->disconn_cfm_cb = NULL;
1916
1917 hci_conn_put(conn);
1918
Johan Hedberga664b5b2011-02-19 12:06:02 -03001919 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001920}
1921
1922static void pairing_complete_cb(struct hci_conn *conn, u8 status)
1923{
1924 struct pending_cmd *cmd;
1925
1926 BT_DBG("status %u", status);
1927
Johan Hedberg56e5cb82011-11-08 20:40:16 +02001928 cmd = find_pairing(conn);
1929 if (!cmd)
1930 BT_DBG("Unable to find a pending command");
1931 else
Johan Hedberge2113262012-02-18 15:20:03 +02001932 pairing_complete(cmd, mgmt_status(status));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001933}
1934
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001935static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
1936 u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001937{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001938 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02001939 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001940 struct pending_cmd *cmd;
1941 u8 sec_level, auth_type;
1942 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001943 int err;
1944
1945 BT_DBG("");
1946
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001947 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001948 return cmd_status(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02001949 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001950
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001951 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001952
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001953 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001954 err = cmd_status(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001955 MGMT_STATUS_NOT_POWERED);
1956 goto unlock;
1957 }
1958
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001959 sec_level = BT_SECURITY_MEDIUM;
1960 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001961 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001962 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03001963 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001964
Johan Hedbergba4e5642011-11-11 00:07:34 +02001965 if (cp->addr.type == MGMT_ADDR_BREDR)
1966 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr, sec_level,
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001967 auth_type);
1968 else
Johan Hedbergba4e5642011-11-11 00:07:34 +02001969 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr, sec_level,
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001970 auth_type);
1971
Johan Hedberg1425acb2011-11-11 00:07:35 +02001972 memset(&rp, 0, sizeof(rp));
1973 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1974 rp.addr.type = cp->addr.type;
1975
Ville Tervo30e76272011-02-22 16:10:53 -03001976 if (IS_ERR(conn)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001977 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Johan Hedberge2113262012-02-18 15:20:03 +02001978 MGMT_STATUS_CONNECT_FAILED,
1979 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001980 goto unlock;
1981 }
1982
1983 if (conn->connect_cfm_cb) {
1984 hci_conn_put(conn);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001985 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Johan Hedberge2113262012-02-18 15:20:03 +02001986 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001987 goto unlock;
1988 }
1989
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001990 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001991 if (!cmd) {
1992 err = -ENOMEM;
1993 hci_conn_put(conn);
1994 goto unlock;
1995 }
1996
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001997 /* For LE, just connecting isn't a proof that the pairing finished */
Johan Hedbergba4e5642011-11-11 00:07:34 +02001998 if (cp->addr.type == MGMT_ADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001999 conn->connect_cfm_cb = pairing_complete_cb;
2000
Johan Hedberge9a416b2011-02-19 12:05:56 -03002001 conn->security_cfm_cb = pairing_complete_cb;
2002 conn->disconn_cfm_cb = pairing_complete_cb;
2003 conn->io_capability = cp->io_cap;
2004 cmd->user_data = conn;
2005
2006 if (conn->state == BT_CONNECTED &&
2007 hci_conn_security(conn, sec_level, auth_type))
2008 pairing_complete(cmd, 0);
2009
2010 err = 0;
2011
2012unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002013 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002014 return err;
2015}
2016
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002017static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev,
Johan Hedberg28424702012-02-02 04:02:29 +02002018 unsigned char *data, u16 len)
2019{
2020 struct mgmt_addr_info *addr = (void *) data;
Johan Hedberg28424702012-02-02 04:02:29 +02002021 struct pending_cmd *cmd;
2022 struct hci_conn *conn;
2023 int err;
2024
2025 BT_DBG("");
2026
2027 if (len != sizeof(*addr))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002028 return cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Johan Hedberg28424702012-02-02 04:02:29 +02002029 MGMT_STATUS_INVALID_PARAMS);
2030
2031 hci_dev_lock(hdev);
2032
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002033 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002034 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002035 MGMT_STATUS_NOT_POWERED);
2036 goto unlock;
2037 }
2038
Johan Hedberg28424702012-02-02 04:02:29 +02002039 cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
2040 if (!cmd) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002041 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Johan Hedberg28424702012-02-02 04:02:29 +02002042 MGMT_STATUS_INVALID_PARAMS);
2043 goto unlock;
2044 }
2045
2046 conn = cmd->user_data;
2047
2048 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002049 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Johan Hedberg28424702012-02-02 04:02:29 +02002050 MGMT_STATUS_INVALID_PARAMS);
2051 goto unlock;
2052 }
2053
2054 pairing_complete(cmd, MGMT_STATUS_CANCELLED);
2055
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002056 err = cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0,
2057 addr, sizeof(*addr));
Johan Hedberg28424702012-02-02 04:02:29 +02002058unlock:
2059 hci_dev_unlock(hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02002060 return err;
2061}
2062
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002063static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
2064 bdaddr_t *bdaddr, u8 type, u16 mgmt_op,
2065 u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03002066{
Johan Hedberga5c29682011-02-19 12:05:57 -03002067 struct pending_cmd *cmd;
Brian Gix0df4c182011-11-16 13:53:13 -08002068 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03002069 int err;
2070
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002071 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02002072
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002073 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002074 err = cmd_status(sk, hdev->id, mgmt_op,
2075 MGMT_STATUS_NOT_POWERED);
Brian Gix0df4c182011-11-16 13:53:13 -08002076 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002077 }
2078
Johan Hedberg272d90d2012-02-09 15:26:12 +02002079 if (type == MGMT_ADDR_BREDR)
2080 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, bdaddr);
2081 else
Brian Gix47c15e22011-11-16 13:53:14 -08002082 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, bdaddr);
Brian Gix47c15e22011-11-16 13:53:14 -08002083
Johan Hedberg272d90d2012-02-09 15:26:12 +02002084 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002085 err = cmd_status(sk, hdev->id, mgmt_op,
Johan Hedberg272d90d2012-02-09 15:26:12 +02002086 MGMT_STATUS_NOT_CONNECTED);
2087 goto done;
2088 }
2089
2090 if (type == MGMT_ADDR_LE_PUBLIC || type == MGMT_ADDR_LE_RANDOM) {
Brian Gix47c15e22011-11-16 13:53:14 -08002091 /* Continue with pairing via SMP */
Brian Gix5fe57d92011-12-21 16:12:13 -08002092 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix47c15e22011-11-16 13:53:14 -08002093
Brian Gix5fe57d92011-12-21 16:12:13 -08002094 if (!err)
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002095 err = cmd_status(sk, hdev->id, mgmt_op,
Brian Gix5fe57d92011-12-21 16:12:13 -08002096 MGMT_STATUS_SUCCESS);
2097 else
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002098 err = cmd_status(sk, hdev->id, mgmt_op,
Brian Gix5fe57d92011-12-21 16:12:13 -08002099 MGMT_STATUS_FAILED);
2100
Brian Gix47c15e22011-11-16 13:53:14 -08002101 goto done;
2102 }
2103
Brian Gix0df4c182011-11-16 13:53:13 -08002104 cmd = mgmt_pending_add(sk, mgmt_op, hdev, bdaddr, sizeof(*bdaddr));
Johan Hedberga5c29682011-02-19 12:05:57 -03002105 if (!cmd) {
2106 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08002107 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002108 }
2109
Brian Gix0df4c182011-11-16 13:53:13 -08002110 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08002111 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
2112 struct hci_cp_user_passkey_reply cp;
2113
2114 bacpy(&cp.bdaddr, bdaddr);
2115 cp.passkey = passkey;
2116 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
2117 } else
2118 err = hci_send_cmd(hdev, hci_op, sizeof(*bdaddr), bdaddr);
2119
Johan Hedberga664b5b2011-02-19 12:06:02 -03002120 if (err < 0)
2121 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002122
Brian Gix0df4c182011-11-16 13:53:13 -08002123done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002124 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002125 return err;
2126}
2127
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002128static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev,
2129 void *data, u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002130{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002131 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002132
2133 BT_DBG("");
2134
2135 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002136 return cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY,
Brian Gix0df4c182011-11-16 13:53:13 -08002137 MGMT_STATUS_INVALID_PARAMS);
2138
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002139 return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
Johan Hedberg272d90d2012-02-09 15:26:12 +02002140 MGMT_OP_USER_CONFIRM_REPLY,
2141 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002142}
2143
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002144static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev,
2145 void *data, u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002146{
Johan Hedbergc9c26592011-12-15 00:47:41 +02002147 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002148
2149 BT_DBG("");
2150
2151 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002152 return cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_NEG_REPLY,
Brian Gix0df4c182011-11-16 13:53:13 -08002153 MGMT_STATUS_INVALID_PARAMS);
2154
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002155 return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
Johan Hedberg272d90d2012-02-09 15:26:12 +02002156 MGMT_OP_USER_CONFIRM_NEG_REPLY,
2157 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002158}
2159
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002160static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev,
2161 void *data, u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002162{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002163 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002164
2165 BT_DBG("");
2166
2167 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002168 return cmd_status(sk, hdev->id, MGMT_OP_USER_PASSKEY_REPLY,
Brian Gix604086b2011-11-23 08:28:33 -08002169 EINVAL);
2170
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002171 return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
Johan Hedberg272d90d2012-02-09 15:26:12 +02002172 MGMT_OP_USER_PASSKEY_REPLY,
2173 HCI_OP_USER_PASSKEY_REPLY,
2174 cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08002175}
2176
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002177static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
2178 void *data, u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002179{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002180 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002181
2182 BT_DBG("");
2183
2184 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002185 return cmd_status(sk, hdev->id, MGMT_OP_USER_PASSKEY_NEG_REPLY,
2186 EINVAL);
Brian Gix604086b2011-11-23 08:28:33 -08002187
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002188 return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
Johan Hedberg272d90d2012-02-09 15:26:12 +02002189 MGMT_OP_USER_PASSKEY_NEG_REPLY,
2190 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08002191}
2192
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002193static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
Johan Hedbergb312b1612011-03-16 14:29:37 +02002194 u16 len)
2195{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002196 struct mgmt_cp_set_local_name *mgmt_cp = data;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002197 struct hci_cp_write_local_name hci_cp;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002198 struct pending_cmd *cmd;
2199 int err;
2200
2201 BT_DBG("");
2202
2203 if (len != sizeof(*mgmt_cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002204 return cmd_status(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
Johan Hedbergca69b792011-11-11 18:10:00 +02002205 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002206
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002207 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002208
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002209 memcpy(hdev->short_name, mgmt_cp->short_name,
2210 sizeof(hdev->short_name));
2211
Johan Hedbergb5235a62012-02-21 14:32:24 +02002212 if (!hdev_is_powered(hdev)) {
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002213 memcpy(hdev->dev_name, mgmt_cp->name, sizeof(hdev->dev_name));
2214
2215 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
2216 data, len);
2217 if (err < 0)
2218 goto failed;
2219
2220 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data, len,
2221 sk);
2222
Johan Hedbergb5235a62012-02-21 14:32:24 +02002223 goto failed;
2224 }
2225
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002226 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002227 if (!cmd) {
2228 err = -ENOMEM;
2229 goto failed;
2230 }
2231
2232 memcpy(hci_cp.name, mgmt_cp->name, sizeof(hci_cp.name));
2233 err = hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(hci_cp),
2234 &hci_cp);
2235 if (err < 0)
2236 mgmt_pending_remove(cmd);
2237
2238failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002239 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002240 return err;
2241}
2242
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002243static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev)
Szymon Jancc35938b2011-03-22 13:12:21 +01002244{
Szymon Jancc35938b2011-03-22 13:12:21 +01002245 struct pending_cmd *cmd;
2246 int err;
2247
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002248 BT_DBG("%s", hdev->name);
Szymon Jancc35938b2011-03-22 13:12:21 +01002249
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002250 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002251
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002252 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002253 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002254 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002255 goto unlock;
2256 }
2257
2258 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002259 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002260 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002261 goto unlock;
2262 }
2263
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002264 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002265 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002266 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01002267 goto unlock;
2268 }
2269
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002270 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01002271 if (!cmd) {
2272 err = -ENOMEM;
2273 goto unlock;
2274 }
2275
2276 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
2277 if (err < 0)
2278 mgmt_pending_remove(cmd);
2279
2280unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002281 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002282 return err;
2283}
2284
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002285static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
2286 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002287{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002288 struct mgmt_cp_add_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002289 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002290 int err;
2291
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002292 BT_DBG("%s ", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01002293
2294 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002295 return cmd_status(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002296 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01002297
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002298 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002299
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002300 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002301 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA,
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002302 MGMT_STATUS_NOT_POWERED,
2303 &cp->addr, sizeof(cp->addr));
2304 goto unlock;
2305 }
2306
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002307 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, cp->hash,
Szymon Janc2763eda2011-03-22 13:12:22 +01002308 cp->randomizer);
2309 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002310 status = MGMT_STATUS_FAILED;
Szymon Janc2763eda2011-03-22 13:12:22 +01002311 else
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002312 status = 0;
2313
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002314 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA, status,
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002315 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002316
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002317unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002318 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002319 return err;
2320}
2321
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002322static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002323 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002324{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002325 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002326 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002327 int err;
2328
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002329 BT_DBG("%s", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01002330
2331 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002332 return cmd_status(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002333 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01002334
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002335 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002336
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002337 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002338 err = cmd_complete(sk, hdev->id,
2339 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2340 MGMT_STATUS_NOT_POWERED,
2341 &cp->addr, sizeof(cp->addr));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002342 goto unlock;
2343 }
2344
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002345 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr);
Szymon Janc2763eda2011-03-22 13:12:22 +01002346 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002347 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01002348 else
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002349 status = 0;
2350
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002351 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2352 status, &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002353
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002354unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002355 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002356 return err;
2357}
2358
Andre Guedes5e0452c2012-02-17 20:39:38 -03002359int mgmt_interleaved_discovery(struct hci_dev *hdev)
2360{
2361 int err;
2362
2363 BT_DBG("%s", hdev->name);
2364
2365 hci_dev_lock(hdev);
2366
2367 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR_LE);
2368 if (err < 0)
2369 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2370
2371 hci_dev_unlock(hdev);
2372
2373 return err;
2374}
2375
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002376static int start_discovery(struct sock *sk, struct hci_dev *hdev,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002377 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002378{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002379 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002380 struct pending_cmd *cmd;
Johan Hedberg14a53662011-04-27 10:29:56 -04002381 int err;
2382
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002383 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04002384
Johan Hedberg450dfda2011-11-12 11:58:22 +02002385 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002386 return cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Johan Hedbergca69b792011-11-11 18:10:00 +02002387 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg14a53662011-04-27 10:29:56 -04002388
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002389 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002390
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002391 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002392 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Johan Hedbergca69b792011-11-11 18:10:00 +02002393 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02002394 goto failed;
2395 }
2396
Johan Hedbergff9ef572012-01-04 14:23:45 +02002397 if (hdev->discovery.state != DISCOVERY_STOPPED) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002398 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2399 MGMT_STATUS_BUSY);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002400 goto failed;
2401 }
2402
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002403 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002404 if (!cmd) {
2405 err = -ENOMEM;
2406 goto failed;
2407 }
2408
Andre Guedes4aab14e2012-02-17 20:39:36 -03002409 hdev->discovery.type = cp->type;
2410
2411 switch (hdev->discovery.type) {
Andre Guedesf39799f2012-02-17 20:39:35 -03002412 case DISCOV_TYPE_BREDR:
Andre Guedes8b901292012-02-23 18:09:27 -03002413 if (lmp_bredr_capable(hdev))
2414 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
2415 else
2416 err = -ENOTSUPP;
Andre Guedesf39799f2012-02-17 20:39:35 -03002417 break;
2418
2419 case DISCOV_TYPE_LE:
Andre Guedes8b901292012-02-23 18:09:27 -03002420 if (lmp_host_le_capable(hdev))
2421 err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT,
Andre Guedes3fd24152012-02-03 17:48:01 -03002422 LE_SCAN_WIN, LE_SCAN_TIMEOUT_LE_ONLY);
Andre Guedes8b901292012-02-23 18:09:27 -03002423 else
2424 err = -ENOTSUPP;
Andre Guedesf39799f2012-02-17 20:39:35 -03002425 break;
2426
Andre Guedes5e0452c2012-02-17 20:39:38 -03002427 case DISCOV_TYPE_INTERLEAVED:
Andre Guedes426c1892012-02-24 11:41:04 -03002428 if (lmp_host_le_capable(hdev) && lmp_bredr_capable(hdev))
2429 err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT,
2430 LE_SCAN_WIN, LE_SCAN_TIMEOUT_BREDR_LE);
2431 else
2432 err = -ENOTSUPP;
Andre Guedes5e0452c2012-02-17 20:39:38 -03002433 break;
2434
Andre Guedesf39799f2012-02-17 20:39:35 -03002435 default:
Andre Guedes3fd24152012-02-03 17:48:01 -03002436 err = -EINVAL;
Andre Guedesf39799f2012-02-17 20:39:35 -03002437 }
Andre Guedes3fd24152012-02-03 17:48:01 -03002438
Johan Hedberg14a53662011-04-27 10:29:56 -04002439 if (err < 0)
2440 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002441 else
2442 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002443
2444failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002445 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002446 return err;
2447}
2448
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002449static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
2450 u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002451{
Johan Hedbergd9306502012-02-20 23:25:18 +02002452 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002453 struct pending_cmd *cmd;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002454 struct hci_cp_remote_name_req_cancel cp;
2455 struct inquiry_entry *e;
Johan Hedberg14a53662011-04-27 10:29:56 -04002456 int err;
2457
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002458 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04002459
Johan Hedbergd9306502012-02-20 23:25:18 +02002460 if (len != sizeof(*mgmt_cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002461 return cmd_status(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Johan Hedbergca69b792011-11-11 18:10:00 +02002462 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg14a53662011-04-27 10:29:56 -04002463
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002464 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002465
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002466 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002467 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Johan Hedbergd9306502012-02-20 23:25:18 +02002468 MGMT_STATUS_REJECTED,
2469 &mgmt_cp->type, sizeof(mgmt_cp->type));
2470 goto unlock;
2471 }
2472
2473 if (hdev->discovery.type != mgmt_cp->type) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002474 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Johan Hedbergd9306502012-02-20 23:25:18 +02002475 MGMT_STATUS_INVALID_PARAMS,
2476 &mgmt_cp->type, sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002477 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02002478 }
2479
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002480 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002481 if (!cmd) {
2482 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002483 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04002484 }
2485
Andre Guedes343f9352012-02-17 20:39:37 -03002486 if (hdev->discovery.state == DISCOVERY_FINDING) {
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002487 err = hci_cancel_inquiry(hdev);
2488 if (err < 0)
2489 mgmt_pending_remove(cmd);
2490 else
2491 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
2492 goto unlock;
2493 }
2494
2495 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY, NAME_PENDING);
2496 if (!e) {
2497 mgmt_pending_remove(cmd);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002498 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY, 0,
Johan Hedbergd9306502012-02-20 23:25:18 +02002499 &mgmt_cp->type, sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002500 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2501 goto unlock;
2502 }
2503
2504 bacpy(&cp.bdaddr, &e->data.bdaddr);
2505 err = hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ_CANCEL,
2506 sizeof(cp), &cp);
Johan Hedberg14a53662011-04-27 10:29:56 -04002507 if (err < 0)
2508 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002509 else
2510 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002511
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002512unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002513 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002514 return err;
2515}
2516
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002517static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
2518 u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02002519{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002520 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002521 struct inquiry_entry *e;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002522 int err;
2523
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002524 BT_DBG("%s", hdev->name);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002525
2526 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002527 return cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
2528 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002529
2530 hci_dev_lock(hdev);
2531
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002532 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002533 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002534 MGMT_STATUS_FAILED);
2535 goto failed;
2536 }
2537
Johan Hedberga198e7b2012-02-17 14:27:06 +02002538 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002539 if (!e) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002540 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
2541 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002542 goto failed;
2543 }
2544
2545 if (cp->name_known) {
2546 e->name_state = NAME_KNOWN;
2547 list_del(&e->list);
2548 } else {
2549 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e20a2012-01-09 00:53:02 +02002550 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002551 }
2552
2553 err = 0;
2554
2555failed:
2556 hci_dev_unlock(hdev);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002557 return err;
2558}
2559
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002560static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
2561 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002562{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002563 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002564 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03002565 int err;
2566
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002567 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03002568
Antti Julku7fbec222011-06-15 12:01:15 +03002569 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002570 return cmd_status(sk, hdev->id, MGMT_OP_BLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002571 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002572
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002573 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002574
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002575 err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002576 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002577 status = MGMT_STATUS_FAILED;
Antti Julku7fbec222011-06-15 12:01:15 +03002578 else
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002579 status = 0;
2580
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002581 err = cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status,
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002582 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03002583
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002584 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002585
2586 return err;
2587}
2588
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002589static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
2590 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002591{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002592 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002593 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03002594 int err;
2595
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002596 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03002597
Antti Julku7fbec222011-06-15 12:01:15 +03002598 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002599 return cmd_status(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002600 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002601
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002602 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002603
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002604 err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002605 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002606 status = MGMT_STATUS_INVALID_PARAMS;
Antti Julku7fbec222011-06-15 12:01:15 +03002607 else
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002608 status = 0;
2609
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002610 err = cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status,
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002611 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03002612
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002613 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002614
2615 return err;
2616}
2617
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002618static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
2619 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03002620{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002621 struct mgmt_mode *cp = data;
Antti Julkuf6422ec2011-06-22 13:11:56 +03002622 struct hci_cp_write_page_scan_activity acp;
2623 u8 type;
2624 int err;
2625
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002626 BT_DBG("%s", hdev->name);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002627
2628 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002629 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002630 MGMT_STATUS_INVALID_PARAMS);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002631
Johan Hedberg5400c042012-02-21 16:40:33 +02002632 if (!hdev_is_powered(hdev))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002633 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedberg5400c042012-02-21 16:40:33 +02002634 MGMT_STATUS_NOT_POWERED);
2635
2636 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002637 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
2638 MGMT_STATUS_REJECTED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002639
2640 hci_dev_lock(hdev);
2641
Johan Hedbergf7c6869ce2011-12-15 00:47:36 +02002642 if (cp->val) {
Antti Julkuf6422ec2011-06-22 13:11:56 +03002643 type = PAGE_SCAN_TYPE_INTERLACED;
2644 acp.interval = 0x0024; /* 22.5 msec page scan interval */
2645 } else {
2646 type = PAGE_SCAN_TYPE_STANDARD; /* default */
2647 acp.interval = 0x0800; /* default 1.28 sec page scan */
2648 }
2649
2650 acp.window = 0x0012; /* default 11.25 msec page scan window */
2651
2652 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
2653 sizeof(acp), &acp);
2654 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002655 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
2656 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002657 goto done;
2658 }
2659
2660 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
2661 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002662 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
2663 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002664 goto done;
2665 }
2666
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002667 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE, 0,
Johan Hedbergaee9b212012-02-18 15:07:59 +02002668 NULL, 0);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002669done:
2670 hci_dev_unlock(hdev);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002671 return err;
2672}
2673
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002674static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002675 void *cp_data, u16 len)
2676{
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002677 struct mgmt_cp_load_long_term_keys *cp = cp_data;
2678 u16 key_count, expected_len;
2679 int i;
2680
2681 if (len < sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002682 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002683 EINVAL);
2684
2685 key_count = get_unaligned_le16(&cp->key_count);
2686
2687 expected_len = sizeof(*cp) + key_count *
2688 sizeof(struct mgmt_ltk_info);
2689 if (expected_len != len) {
2690 BT_ERR("load_keys: expected %u bytes, got %u bytes",
2691 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002692 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002693 EINVAL);
2694 }
2695
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002696 BT_DBG("%s key_count %u", hdev->name, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002697
2698 hci_dev_lock(hdev);
2699
2700 hci_smp_ltks_clear(hdev);
2701
2702 for (i = 0; i < key_count; i++) {
2703 struct mgmt_ltk_info *key = &cp->keys[i];
2704 u8 type;
2705
2706 if (key->master)
2707 type = HCI_SMP_LTK;
2708 else
2709 type = HCI_SMP_LTK_SLAVE;
2710
2711 hci_add_ltk(hdev, &key->addr.bdaddr, key->addr.type,
2712 type, 0, key->authenticated, key->val,
2713 key->enc_size, key->ediv, key->rand);
2714 }
2715
2716 hci_dev_unlock(hdev);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002717
2718 return 0;
2719}
2720
Johan Hedberg03811012010-12-08 00:21:06 +02002721int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
2722{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002723 void *buf;
2724 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02002725 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002726 u16 opcode, index, len;
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002727 struct hci_dev *hdev = NULL;
Johan Hedberg03811012010-12-08 00:21:06 +02002728 int err;
2729
2730 BT_DBG("got %zu bytes", msglen);
2731
2732 if (msglen < sizeof(*hdr))
2733 return -EINVAL;
2734
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03002735 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02002736 if (!buf)
2737 return -ENOMEM;
2738
2739 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
2740 err = -EFAULT;
2741 goto done;
2742 }
2743
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002744 hdr = buf;
Johan Hedberg03811012010-12-08 00:21:06 +02002745 opcode = get_unaligned_le16(&hdr->opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002746 index = get_unaligned_le16(&hdr->index);
Johan Hedberg03811012010-12-08 00:21:06 +02002747 len = get_unaligned_le16(&hdr->len);
2748
2749 if (len != msglen - sizeof(*hdr)) {
2750 err = -EINVAL;
2751 goto done;
2752 }
2753
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002754 if (opcode < MGMT_OP_READ_INFO) {
2755 if (index != MGMT_INDEX_NONE) {
2756 err = cmd_status(sk, index, opcode,
2757 MGMT_STATUS_INVALID_PARAMS);
2758 goto done;
2759 }
2760 } else {
2761 hdev = hci_dev_get(index);
2762 if (!hdev) {
2763 err = cmd_status(sk, index, opcode,
2764 MGMT_STATUS_INVALID_PARAMS);
2765 goto done;
2766 }
Johan Hedberg6a919082012-02-28 06:17:26 +02002767
2768 mgmt_init_hdev(sk, hdev);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002769 }
2770
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002771 cp = buf + sizeof(*hdr);
2772
Johan Hedberg03811012010-12-08 00:21:06 +02002773 switch (opcode) {
Johan Hedberg02d98122010-12-13 21:07:04 +02002774 case MGMT_OP_READ_VERSION:
2775 err = read_version(sk);
2776 break;
Johan Hedberge70bb2e2012-02-13 16:59:33 +02002777 case MGMT_OP_READ_COMMANDS:
2778 err = read_commands(sk);
2779 break;
Johan Hedbergfaba42e2010-12-13 21:07:05 +02002780 case MGMT_OP_READ_INDEX_LIST:
2781 err = read_index_list(sk);
2782 break;
Johan Hedbergf7b64e692010-12-13 21:07:06 +02002783 case MGMT_OP_READ_INFO:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002784 err = read_controller_info(sk, hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02002785 break;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002786 case MGMT_OP_SET_POWERED:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002787 err = set_powered(sk, hdev, cp, len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002788 break;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002789 case MGMT_OP_SET_DISCOVERABLE:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002790 err = set_discoverable(sk, hdev, cp, len);
Johan Hedberg73f22f62010-12-29 16:00:25 +02002791 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002792 case MGMT_OP_SET_CONNECTABLE:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002793 err = set_connectable(sk, hdev, cp, len);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002794 break;
Johan Hedbergf7c6869ce2011-12-15 00:47:36 +02002795 case MGMT_OP_SET_FAST_CONNECTABLE:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002796 err = set_fast_connectable(sk, hdev, cp, len);
Johan Hedbergf7c6869ce2011-12-15 00:47:36 +02002797 break;
Johan Hedbergc542a062011-01-26 13:11:03 +02002798 case MGMT_OP_SET_PAIRABLE:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002799 err = set_pairable(sk, hdev, cp, len);
Johan Hedbergc542a062011-01-26 13:11:03 +02002800 break;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02002801 case MGMT_OP_SET_LINK_SECURITY:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002802 err = set_link_security(sk, hdev, cp, len);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02002803 break;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02002804 case MGMT_OP_SET_SSP:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002805 err = set_ssp(sk, hdev, cp, len);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02002806 break;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02002807 case MGMT_OP_SET_HS:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002808 err = set_hs(sk, hdev, cp, len);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02002809 break;
Johan Hedberg06199cf2012-02-22 16:37:11 +02002810 case MGMT_OP_SET_LE:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002811 err = set_le(sk, hdev, cp, len);
Johan Hedberg06199cf2012-02-22 16:37:11 +02002812 break;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002813 case MGMT_OP_ADD_UUID:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002814 err = add_uuid(sk, hdev, cp, len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002815 break;
2816 case MGMT_OP_REMOVE_UUID:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002817 err = remove_uuid(sk, hdev, cp, len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002818 break;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002819 case MGMT_OP_SET_DEV_CLASS:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002820 err = set_dev_class(sk, hdev, cp, len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002821 break;
Johan Hedberg86742e12011-11-07 23:13:38 +02002822 case MGMT_OP_LOAD_LINK_KEYS:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002823 err = load_link_keys(sk, hdev, cp, len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002824 break;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002825 case MGMT_OP_DISCONNECT:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002826 err = disconnect(sk, hdev, cp, len);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002827 break;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002828 case MGMT_OP_GET_CONNECTIONS:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002829 err = get_connections(sk, hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002830 break;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002831 case MGMT_OP_PIN_CODE_REPLY:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002832 err = pin_code_reply(sk, hdev, cp, len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002833 break;
2834 case MGMT_OP_PIN_CODE_NEG_REPLY:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002835 err = pin_code_neg_reply(sk, hdev, cp, len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002836 break;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002837 case MGMT_OP_SET_IO_CAPABILITY:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002838 err = set_io_capability(sk, hdev, cp, len);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002839 break;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002840 case MGMT_OP_PAIR_DEVICE:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002841 err = pair_device(sk, hdev, cp, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002842 break;
Johan Hedberg28424702012-02-02 04:02:29 +02002843 case MGMT_OP_CANCEL_PAIR_DEVICE:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002844 err = cancel_pair_device(sk, hdev, buf + sizeof(*hdr), len);
Johan Hedberg28424702012-02-02 04:02:29 +02002845 break;
Johan Hedberg124f6e32012-02-09 13:50:12 +02002846 case MGMT_OP_UNPAIR_DEVICE:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002847 err = unpair_device(sk, hdev, cp, len);
Johan Hedberg124f6e32012-02-09 13:50:12 +02002848 break;
Johan Hedberga5c29682011-02-19 12:05:57 -03002849 case MGMT_OP_USER_CONFIRM_REPLY:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002850 err = user_confirm_reply(sk, hdev, cp, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03002851 break;
2852 case MGMT_OP_USER_CONFIRM_NEG_REPLY:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002853 err = user_confirm_neg_reply(sk, hdev, cp, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03002854 break;
Brian Gix604086b2011-11-23 08:28:33 -08002855 case MGMT_OP_USER_PASSKEY_REPLY:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002856 err = user_passkey_reply(sk, hdev, cp, len);
Brian Gix604086b2011-11-23 08:28:33 -08002857 break;
2858 case MGMT_OP_USER_PASSKEY_NEG_REPLY:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002859 err = user_passkey_neg_reply(sk, hdev, cp, len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002860 break;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002861 case MGMT_OP_SET_LOCAL_NAME:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002862 err = set_local_name(sk, hdev, cp, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002863 break;
Szymon Jancc35938b2011-03-22 13:12:21 +01002864 case MGMT_OP_READ_LOCAL_OOB_DATA:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002865 err = read_local_oob_data(sk, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002866 break;
Szymon Janc2763eda2011-03-22 13:12:22 +01002867 case MGMT_OP_ADD_REMOTE_OOB_DATA:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002868 err = add_remote_oob_data(sk, hdev, cp, len);
Szymon Janc2763eda2011-03-22 13:12:22 +01002869 break;
2870 case MGMT_OP_REMOVE_REMOTE_OOB_DATA:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002871 err = remove_remote_oob_data(sk, hdev, cp, len);
Szymon Janc2763eda2011-03-22 13:12:22 +01002872 break;
Johan Hedberg14a53662011-04-27 10:29:56 -04002873 case MGMT_OP_START_DISCOVERY:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002874 err = start_discovery(sk, hdev, cp, len);
Johan Hedberg14a53662011-04-27 10:29:56 -04002875 break;
2876 case MGMT_OP_STOP_DISCOVERY:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002877 err = stop_discovery(sk, hdev, cp, len);
Johan Hedberg14a53662011-04-27 10:29:56 -04002878 break;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002879 case MGMT_OP_CONFIRM_NAME:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002880 err = confirm_name(sk, hdev, cp, len);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002881 break;
Antti Julku7fbec222011-06-15 12:01:15 +03002882 case MGMT_OP_BLOCK_DEVICE:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002883 err = block_device(sk, hdev, cp, len);
Antti Julku7fbec222011-06-15 12:01:15 +03002884 break;
2885 case MGMT_OP_UNBLOCK_DEVICE:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002886 err = unblock_device(sk, hdev, cp, len);
Antti Julku7fbec222011-06-15 12:01:15 +03002887 break;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002888 case MGMT_OP_LOAD_LONG_TERM_KEYS:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002889 err = load_long_term_keys(sk, hdev, cp, len);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002890 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002891 default:
Johan Hedberg72a734e2010-12-30 00:38:22 +02002892 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02002893 err = cmd_status(sk, index, opcode,
2894 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002895 break;
2896 }
Johan Hedberg72a734e2010-12-30 00:38:22 +02002897
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002898 if (err < 0)
Johan Hedberg72a734e2010-12-30 00:38:22 +02002899 goto done;
2900
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002901 err = msglen;
2902
2903done:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002904 if (hdev)
2905 hci_dev_put(hdev);
2906
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002907 kfree(buf);
2908 return err;
2909}
2910
Johan Hedbergb24752f2011-11-03 14:40:33 +02002911static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
2912{
2913 u8 *status = data;
2914
2915 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
2916 mgmt_pending_remove(cmd);
2917}
2918
Johan Hedberg744cf192011-11-08 20:40:14 +02002919int mgmt_index_added(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +02002920{
Johan Hedberg744cf192011-11-08 20:40:14 +02002921 return mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02002922}
2923
Johan Hedberg744cf192011-11-08 20:40:14 +02002924int mgmt_index_removed(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +02002925{
Johan Hedbergb24752f2011-11-03 14:40:33 +02002926 u8 status = ENODEV;
2927
Johan Hedberg744cf192011-11-08 20:40:14 +02002928 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002929
Johan Hedberg744cf192011-11-08 20:40:14 +02002930 return mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02002931}
2932
2933struct cmd_lookup {
Johan Hedberg03811012010-12-08 00:21:06 +02002934 struct sock *sk;
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002935 struct hci_dev *hdev;
Johan Hedberg90e70452012-02-23 23:09:40 +02002936 u8 mgmt_status;
Johan Hedberg03811012010-12-08 00:21:06 +02002937};
2938
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002939static void settings_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberg03811012010-12-08 00:21:06 +02002940{
Johan Hedberg03811012010-12-08 00:21:06 +02002941 struct cmd_lookup *match = data;
2942
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002943 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02002944
2945 list_del(&cmd->list);
2946
2947 if (match->sk == NULL) {
2948 match->sk = cmd->sk;
2949 sock_hold(match->sk);
2950 }
2951
2952 mgmt_pending_free(cmd);
2953}
2954
Johan Hedberg744cf192011-11-08 20:40:14 +02002955int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg03811012010-12-08 00:21:06 +02002956{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002957 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002958 int err;
Johan Hedberg03811012010-12-08 00:21:06 +02002959
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002960 if (!test_bit(HCI_MGMT, &hdev->dev_flags))
2961 return 0;
2962
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002963 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
Johan Hedberg03811012010-12-08 00:21:06 +02002964
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002965 if (powered) {
2966 u8 scan = 0;
2967
2968 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
2969 scan |= SCAN_PAGE;
2970 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
2971 scan |= SCAN_INQUIRY;
2972
2973 if (scan)
2974 hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
Johan Hedberg504c8dc2012-02-23 13:30:41 +02002975
2976 update_class(hdev);
2977 update_eir(hdev);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002978 } else {
Johan Hedbergb24752f2011-11-03 14:40:33 +02002979 u8 status = ENETDOWN;
Johan Hedberg744cf192011-11-08 20:40:14 +02002980 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002981 }
2982
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02002983 err = new_settings(hdev, match.sk);
Johan Hedberg03811012010-12-08 00:21:06 +02002984
2985 if (match.sk)
2986 sock_put(match.sk);
2987
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002988 return err;
Johan Hedberg03811012010-12-08 00:21:06 +02002989}
2990
Johan Hedberg744cf192011-11-08 20:40:14 +02002991int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg03811012010-12-08 00:21:06 +02002992{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002993 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002994 bool changed = false;
2995 int err = 0;
Johan Hedberg03811012010-12-08 00:21:06 +02002996
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002997 if (discoverable) {
2998 if (!test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
2999 changed = true;
3000 } else {
3001 if (test_and_clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3002 changed = true;
3003 }
Johan Hedberg03811012010-12-08 00:21:06 +02003004
Johan Hedberged9b5f22012-02-21 20:47:06 +02003005 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp,
3006 &match);
3007
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003008 if (changed)
3009 err = new_settings(hdev, match.sk);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003010
Johan Hedberg03811012010-12-08 00:21:06 +02003011 if (match.sk)
3012 sock_put(match.sk);
3013
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003014 return err;
Johan Hedberg03811012010-12-08 00:21:06 +02003015}
3016
Johan Hedberg744cf192011-11-08 20:40:14 +02003017int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg03811012010-12-08 00:21:06 +02003018{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02003019 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003020 bool changed = false;
3021 int err = 0;
Johan Hedberg03811012010-12-08 00:21:06 +02003022
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003023 if (connectable) {
3024 if (!test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3025 changed = true;
3026 } else {
3027 if (test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3028 changed = true;
3029 }
Johan Hedberg03811012010-12-08 00:21:06 +02003030
Johan Hedberged9b5f22012-02-21 20:47:06 +02003031 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev, settings_rsp,
3032 &match);
3033
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003034 if (changed)
3035 err = new_settings(hdev, match.sk);
Johan Hedberg03811012010-12-08 00:21:06 +02003036
3037 if (match.sk)
3038 sock_put(match.sk);
3039
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003040 return err;
Johan Hedberg03811012010-12-08 00:21:06 +02003041}
3042
Johan Hedberg744cf192011-11-08 20:40:14 +02003043int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003044{
Johan Hedbergca69b792011-11-11 18:10:00 +02003045 u8 mgmt_err = mgmt_status(status);
3046
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003047 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02003048 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Johan Hedbergca69b792011-11-11 18:10:00 +02003049 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003050
3051 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02003052 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Johan Hedbergca69b792011-11-11 18:10:00 +02003053 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003054
3055 return 0;
3056}
3057
Johan Hedberg744cf192011-11-08 20:40:14 +02003058int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
3059 u8 persistent)
Johan Hedberg03811012010-12-08 00:21:06 +02003060{
Johan Hedberg86742e12011-11-07 23:13:38 +02003061 struct mgmt_ev_new_link_key ev;
Johan Hedberg03811012010-12-08 00:21:06 +02003062
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003063 memset(&ev, 0, sizeof(ev));
Johan Hedberg03811012010-12-08 00:21:06 +02003064
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003065 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02003066 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
3067 ev.key.addr.type = MGMT_ADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003068 ev.key.type = key->type;
3069 memcpy(ev.key.val, key->val, 16);
3070 ev.key.pin_len = key->pin_len;
Johan Hedberg03811012010-12-08 00:21:06 +02003071
Johan Hedberg744cf192011-11-08 20:40:14 +02003072 return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02003073}
Johan Hedbergf7520542011-01-20 12:34:39 +02003074
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003075int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
3076{
3077 struct mgmt_ev_new_long_term_key ev;
3078
3079 memset(&ev, 0, sizeof(ev));
3080
3081 ev.store_hint = persistent;
3082 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
3083 ev.key.addr.type = key->bdaddr_type;
3084 ev.key.authenticated = key->authenticated;
3085 ev.key.enc_size = key->enc_size;
3086 ev.key.ediv = key->ediv;
3087
3088 if (key->type == HCI_SMP_LTK)
3089 ev.key.master = 1;
3090
3091 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
3092 memcpy(ev.key.val, key->val, sizeof(key->val));
3093
3094 return mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev,
3095 &ev, sizeof(ev), NULL);
3096}
3097
Johan Hedbergafc747a2012-01-15 18:11:07 +02003098int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Johan Hedberg08c79b62012-02-23 22:31:51 +02003099 u8 addr_type, u32 flags, u8 *name,
3100 u8 name_len, u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02003101{
Johan Hedbergb644ba32012-01-17 21:48:47 +02003102 char buf[512];
3103 struct mgmt_ev_device_connected *ev = (void *) buf;
3104 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02003105
Johan Hedbergb644ba32012-01-17 21:48:47 +02003106 bacpy(&ev->addr.bdaddr, bdaddr);
3107 ev->addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02003108
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02003109 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02003110
Johan Hedbergb644ba32012-01-17 21:48:47 +02003111 if (name_len > 0)
3112 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
3113 name, name_len);
3114
3115 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
3116 eir_len = eir_append_data(&ev->eir[eir_len], eir_len,
3117 EIR_CLASS_OF_DEV, dev_class, 3);
3118
3119 put_unaligned_le16(eir_len, &ev->eir_len);
3120
3121 return mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
3122 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02003123}
3124
Johan Hedberg8962ee72011-01-20 12:40:27 +02003125static void disconnect_rsp(struct pending_cmd *cmd, void *data)
3126{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01003127 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003128 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02003129 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003130
Johan Hedberg88c3df12012-02-09 14:27:38 +02003131 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3132 rp.addr.type = cp->addr.type;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003133
Johan Hedbergaee9b212012-02-18 15:07:59 +02003134 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, 0, &rp,
3135 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003136
3137 *sk = cmd->sk;
3138 sock_hold(*sk);
3139
Johan Hedberga664b5b2011-02-19 12:06:02 -03003140 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003141}
3142
Johan Hedberg124f6e32012-02-09 13:50:12 +02003143static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02003144{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003145 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02003146 struct mgmt_cp_unpair_device *cp = cmd->param;
3147 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02003148
3149 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02003150 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3151 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02003152
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003153 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
3154
Johan Hedbergaee9b212012-02-18 15:07:59 +02003155 cmd_complete(cmd->sk, cmd->index, cmd->opcode, 0, &rp, sizeof(rp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02003156
3157 mgmt_pending_remove(cmd);
3158}
3159
Johan Hedbergafc747a2012-01-15 18:11:07 +02003160int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
3161 u8 link_type, u8 addr_type)
Johan Hedbergf7520542011-01-20 12:34:39 +02003162{
Johan Hedberg4c659c32011-11-07 23:13:39 +02003163 struct mgmt_addr_info ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003164 struct sock *sk = NULL;
3165 int err;
3166
Johan Hedberg744cf192011-11-08 20:40:14 +02003167 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02003168
Johan Hedbergf7520542011-01-20 12:34:39 +02003169 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02003170 ev.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02003171
Johan Hedbergafc747a2012-01-15 18:11:07 +02003172 err = mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev),
3173 sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003174
3175 if (sk)
3176 sock_put(sk);
3177
Johan Hedberg124f6e32012-02-09 13:50:12 +02003178 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003179 hdev);
Johan Hedberga8a1d192011-11-10 15:54:38 +02003180
Johan Hedberg8962ee72011-01-20 12:40:27 +02003181 return err;
3182}
3183
Johan Hedberg88c3df12012-02-09 14:27:38 +02003184int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
3185 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02003186{
Johan Hedberg88c3df12012-02-09 14:27:38 +02003187 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003188 struct pending_cmd *cmd;
3189 int err;
3190
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003191 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003192 if (!cmd)
3193 return -ENOENT;
3194
Johan Hedberg88c3df12012-02-09 14:27:38 +02003195 bacpy(&rp.addr.bdaddr, bdaddr);
3196 rp.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02003197
Johan Hedberg88c3df12012-02-09 14:27:38 +02003198 err = cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
Johan Hedbergaee9b212012-02-18 15:07:59 +02003199 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003200
Johan Hedberga664b5b2011-02-19 12:06:02 -03003201 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003202
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003203 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
3204 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003205 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02003206}
Johan Hedberg17d5c042011-01-22 06:09:08 +02003207
Johan Hedberg48264f02011-11-09 13:58:58 +02003208int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
3209 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02003210{
3211 struct mgmt_ev_connect_failed ev;
3212
Johan Hedberg4c659c32011-11-07 23:13:39 +02003213 bacpy(&ev.addr.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02003214 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003215 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003216
Johan Hedberg744cf192011-11-08 20:40:14 +02003217 return mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003218}
Johan Hedberg980e1a52011-01-22 06:10:07 +02003219
Johan Hedberg744cf192011-11-08 20:40:14 +02003220int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003221{
3222 struct mgmt_ev_pin_code_request ev;
3223
Johan Hedbergd8457692012-02-17 14:24:57 +02003224 bacpy(&ev.addr.bdaddr, bdaddr);
3225 ev.addr.type = MGMT_ADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02003226 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003227
Johan Hedberg744cf192011-11-08 20:40:14 +02003228 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01003229 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003230}
3231
Johan Hedberg744cf192011-11-08 20:40:14 +02003232int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3233 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003234{
3235 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003236 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003237 int err;
3238
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003239 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003240 if (!cmd)
3241 return -ENOENT;
3242
Johan Hedbergd8457692012-02-17 14:24:57 +02003243 bacpy(&rp.addr.bdaddr, bdaddr);
3244 rp.addr.type = MGMT_ADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003245
Johan Hedbergaee9b212012-02-18 15:07:59 +02003246 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
3247 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003248
Johan Hedberga664b5b2011-02-19 12:06:02 -03003249 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003250
3251 return err;
3252}
3253
Johan Hedberg744cf192011-11-08 20:40:14 +02003254int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3255 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003256{
3257 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003258 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003259 int err;
3260
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003261 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003262 if (!cmd)
3263 return -ENOENT;
3264
Johan Hedbergd8457692012-02-17 14:24:57 +02003265 bacpy(&rp.addr.bdaddr, bdaddr);
3266 rp.addr.type = MGMT_ADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003267
Johan Hedbergaee9b212012-02-18 15:07:59 +02003268 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
3269 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003270
Johan Hedberga664b5b2011-02-19 12:06:02 -03003271 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003272
3273 return err;
3274}
Johan Hedberga5c29682011-02-19 12:05:57 -03003275
Johan Hedberg744cf192011-11-08 20:40:14 +02003276int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003277 u8 link_type, u8 addr_type, __le32 value,
3278 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03003279{
3280 struct mgmt_ev_user_confirm_request ev;
3281
Johan Hedberg744cf192011-11-08 20:40:14 +02003282 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03003283
Johan Hedberg272d90d2012-02-09 15:26:12 +02003284 bacpy(&ev.addr.bdaddr, bdaddr);
3285 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07003286 ev.confirm_hint = confirm_hint;
Johan Hedberga5c29682011-02-19 12:05:57 -03003287 put_unaligned_le32(value, &ev.value);
3288
Johan Hedberg744cf192011-11-08 20:40:14 +02003289 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01003290 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03003291}
3292
Johan Hedberg272d90d2012-02-09 15:26:12 +02003293int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
3294 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08003295{
3296 struct mgmt_ev_user_passkey_request ev;
3297
3298 BT_DBG("%s", hdev->name);
3299
Johan Hedberg272d90d2012-02-09 15:26:12 +02003300 bacpy(&ev.addr.bdaddr, bdaddr);
3301 ev.addr.type = link_to_mgmt(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08003302
3303 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
3304 NULL);
3305}
3306
Brian Gix0df4c182011-11-16 13:53:13 -08003307static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003308 u8 link_type, u8 addr_type, u8 status,
3309 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03003310{
3311 struct pending_cmd *cmd;
3312 struct mgmt_rp_user_confirm_reply rp;
3313 int err;
3314
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003315 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03003316 if (!cmd)
3317 return -ENOENT;
3318
Johan Hedberg272d90d2012-02-09 15:26:12 +02003319 bacpy(&rp.addr.bdaddr, bdaddr);
3320 rp.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergaee9b212012-02-18 15:07:59 +02003321 err = cmd_complete(cmd->sk, hdev->id, opcode, mgmt_status(status),
3322 &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03003323
Johan Hedberga664b5b2011-02-19 12:06:02 -03003324 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03003325
3326 return err;
3327}
3328
Johan Hedberg744cf192011-11-08 20:40:14 +02003329int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003330 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003331{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003332 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3333 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003334}
3335
Johan Hedberg272d90d2012-02-09 15:26:12 +02003336int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3337 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003338{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003339 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3340 status, MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003341}
Johan Hedberg2a611692011-02-19 12:06:00 -03003342
Brian Gix604086b2011-11-23 08:28:33 -08003343int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003344 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003345{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003346 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3347 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003348}
3349
Johan Hedberg272d90d2012-02-09 15:26:12 +02003350int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3351 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003352{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003353 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3354 status, MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003355}
3356
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003357int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
3358 u8 addr_type, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03003359{
3360 struct mgmt_ev_auth_failed ev;
3361
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003362 bacpy(&ev.addr.bdaddr, bdaddr);
3363 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003364 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03003365
Johan Hedberg744cf192011-11-08 20:40:14 +02003366 return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03003367}
Johan Hedbergb312b1612011-03-16 14:29:37 +02003368
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003369int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
3370{
3371 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg47990ea2012-02-22 11:58:37 +02003372 bool changed = false;
3373 int err = 0;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003374
3375 if (status) {
3376 u8 mgmt_err = mgmt_status(status);
3377 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
3378 cmd_status_rsp, &mgmt_err);
3379 return 0;
3380 }
3381
Johan Hedberg47990ea2012-02-22 11:58:37 +02003382 if (test_bit(HCI_AUTH, &hdev->flags)) {
3383 if (!test_and_set_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
3384 changed = true;
3385 } else {
3386 if (test_and_clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
3387 changed = true;
3388 }
3389
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003390 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
3391 &match);
3392
Johan Hedberg47990ea2012-02-22 11:58:37 +02003393 if (changed)
3394 err = new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003395
3396 if (match.sk)
3397 sock_put(match.sk);
3398
3399 return err;
3400}
3401
Johan Hedbergcacaf522012-02-21 00:52:42 +02003402static int clear_eir(struct hci_dev *hdev)
3403{
3404 struct hci_cp_write_eir cp;
3405
3406 if (!(hdev->features[6] & LMP_EXT_INQ))
3407 return 0;
3408
Johan Hedbergc80da272012-02-22 15:38:48 +02003409 memset(hdev->eir, 0, sizeof(hdev->eir));
3410
Johan Hedbergcacaf522012-02-21 00:52:42 +02003411 memset(&cp, 0, sizeof(cp));
3412
3413 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
3414}
3415
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003416int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003417{
3418 struct cmd_lookup match = { NULL, hdev };
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003419 bool changed = false;
3420 int err = 0;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003421
3422 if (status) {
3423 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003424
3425 if (enable && test_and_clear_bit(HCI_SSP_ENABLED,
3426 &hdev->dev_flags))
3427 err = new_settings(hdev, NULL);
3428
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003429 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev,
3430 cmd_status_rsp, &mgmt_err);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003431
3432 return err;
3433 }
3434
3435 if (enable) {
3436 if (!test_and_set_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3437 changed = true;
3438 } else {
3439 if (test_and_clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3440 changed = true;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003441 }
3442
3443 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
3444
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003445 if (changed)
3446 err = new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003447
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02003448 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003449 sock_put(match.sk);
3450
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02003451 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3452 update_eir(hdev);
3453 else
3454 clear_eir(hdev);
Johan Hedbergcacaf522012-02-21 00:52:42 +02003455
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003456 return err;
3457}
3458
Johan Hedberg90e70452012-02-23 23:09:40 +02003459static void class_rsp(struct pending_cmd *cmd, void *data)
3460{
3461 struct cmd_lookup *match = data;
3462
3463 cmd_complete(cmd->sk, cmd->index, cmd->opcode, match->mgmt_status,
3464 match->hdev->dev_class, 3);
3465
3466 list_del(&cmd->list);
3467
3468 if (match->sk == NULL) {
3469 match->sk = cmd->sk;
3470 sock_hold(match->sk);
3471 }
3472
3473 mgmt_pending_free(cmd);
3474}
3475
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003476int mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
3477 u8 status)
3478{
Johan Hedberg90e70452012-02-23 23:09:40 +02003479 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
3480 int err = 0;
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003481
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02003482 clear_bit(HCI_PENDING_CLASS, &hdev->dev_flags);
3483
Johan Hedberg90e70452012-02-23 23:09:40 +02003484 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, class_rsp, &match);
3485 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, class_rsp, &match);
3486 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, class_rsp, &match);
3487
3488 if (!status)
3489 err = mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
3490 dev_class, 3, NULL);
3491
3492 if (match.sk)
3493 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003494
3495 return err;
3496}
3497
Johan Hedberg744cf192011-11-08 20:40:14 +02003498int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02003499{
3500 struct pending_cmd *cmd;
3501 struct mgmt_cp_set_local_name ev;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003502 bool changed = false;
3503 int err = 0;
3504
3505 if (memcmp(name, hdev->dev_name, sizeof(hdev->dev_name)) != 0) {
3506 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
3507 changed = true;
3508 }
Johan Hedbergb312b1612011-03-16 14:29:37 +02003509
3510 memset(&ev, 0, sizeof(ev));
3511 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003512 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003513
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003514 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003515 if (!cmd)
3516 goto send_event;
3517
Johan Hedberg7bdaae42012-02-22 21:39:58 +02003518 /* Always assume that either the short or the complete name has
3519 * changed if there was a pending mgmt command */
3520 changed = true;
3521
Johan Hedbergb312b1612011-03-16 14:29:37 +02003522 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02003523 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
Johan Hedbergca69b792011-11-11 18:10:00 +02003524 mgmt_status(status));
Johan Hedbergb312b1612011-03-16 14:29:37 +02003525 goto failed;
3526 }
3527
Johan Hedbergaee9b212012-02-18 15:07:59 +02003528 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0, &ev,
Johan Hedbergb312b1612011-03-16 14:29:37 +02003529 sizeof(ev));
3530 if (err < 0)
3531 goto failed;
3532
3533send_event:
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003534 if (changed)
3535 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev,
3536 sizeof(ev), cmd ? cmd->sk : NULL);
3537
Johan Hedbergf51d5b22012-02-22 18:17:32 +02003538 update_eir(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003539
3540failed:
3541 if (cmd)
3542 mgmt_pending_remove(cmd);
3543 return err;
3544}
Szymon Jancc35938b2011-03-22 13:12:21 +01003545
Johan Hedberg744cf192011-11-08 20:40:14 +02003546int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
3547 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01003548{
3549 struct pending_cmd *cmd;
3550 int err;
3551
Johan Hedberg744cf192011-11-08 20:40:14 +02003552 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01003553
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003554 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003555 if (!cmd)
3556 return -ENOENT;
3557
3558 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02003559 err = cmd_status(cmd->sk, hdev->id,
Johan Hedbergca69b792011-11-11 18:10:00 +02003560 MGMT_OP_READ_LOCAL_OOB_DATA,
3561 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01003562 } else {
3563 struct mgmt_rp_read_local_oob_data rp;
3564
3565 memcpy(rp.hash, hash, sizeof(rp.hash));
3566 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
3567
Johan Hedberg744cf192011-11-08 20:40:14 +02003568 err = cmd_complete(cmd->sk, hdev->id,
3569 MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergaee9b212012-02-18 15:07:59 +02003570 0, &rp, sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01003571 }
3572
3573 mgmt_pending_remove(cmd);
3574
3575 return err;
3576}
Johan Hedberge17acd42011-03-30 23:57:16 +03003577
Johan Hedberg06199cf2012-02-22 16:37:11 +02003578int mgmt_le_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
3579{
3580 struct cmd_lookup match = { NULL, hdev };
3581 bool changed = false;
3582 int err = 0;
3583
3584 if (status) {
3585 u8 mgmt_err = mgmt_status(status);
3586
3587 if (enable && test_and_clear_bit(HCI_LE_ENABLED,
3588 &hdev->dev_flags))
3589 err = new_settings(hdev, NULL);
3590
3591 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev,
3592 cmd_status_rsp, &mgmt_err);
3593
3594 return err;
3595 }
3596
3597 if (enable) {
3598 if (!test_and_set_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3599 changed = true;
3600 } else {
3601 if (test_and_clear_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3602 changed = true;
3603 }
3604
3605 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
3606
3607 if (changed)
3608 err = new_settings(hdev, match.sk);
3609
3610 if (match.sk)
3611 sock_put(match.sk);
3612
3613 return err;
3614}
3615
Johan Hedberg48264f02011-11-09 13:58:58 +02003616int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Johan Hedberg561aafb2012-01-04 13:31:59 +02003617 u8 addr_type, u8 *dev_class, s8 rssi,
Johan Hedberg388fc8f2012-02-23 00:38:59 +02003618 u8 cfm_name, u8 ssp, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03003619{
Johan Hedberge319d2e2012-01-15 19:51:59 +02003620 char buf[512];
3621 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02003622 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03003623
Johan Hedberg1dc06092012-01-15 21:01:23 +02003624 /* Leave 5 bytes for a potential CoD field */
3625 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Andre Guedes7d262f82012-01-10 18:20:49 -03003626 return -EINVAL;
3627
Johan Hedberg1dc06092012-01-15 21:01:23 +02003628 memset(buf, 0, sizeof(buf));
3629
Johan Hedberge319d2e2012-01-15 19:51:59 +02003630 bacpy(&ev->addr.bdaddr, bdaddr);
3631 ev->addr.type = link_to_mgmt(link_type, addr_type);
3632 ev->rssi = rssi;
Johan Hedberg9a395a82012-02-23 00:00:32 +02003633 if (cfm_name)
3634 ev->flags[0] |= MGMT_DEV_FOUND_CONFIRM_NAME;
Johan Hedberg388fc8f2012-02-23 00:38:59 +02003635 if (!ssp)
3636 ev->flags[0] |= MGMT_DEV_FOUND_LEGACY_PAIRING;
Johan Hedberge17acd42011-03-30 23:57:16 +03003637
Johan Hedberg1dc06092012-01-15 21:01:23 +02003638 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02003639 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03003640
Johan Hedberg1dc06092012-01-15 21:01:23 +02003641 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
3642 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
3643 dev_class, 3);
3644
3645 put_unaligned_le16(eir_len, &ev->eir_len);
3646
3647 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03003648
Johan Hedberge319d2e2012-01-15 19:51:59 +02003649 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03003650}
Johan Hedberga88a9652011-03-30 13:18:12 +03003651
Johan Hedbergb644ba32012-01-17 21:48:47 +02003652int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
3653 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03003654{
Johan Hedbergb644ba32012-01-17 21:48:47 +02003655 struct mgmt_ev_device_found *ev;
3656 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
3657 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03003658
Johan Hedbergb644ba32012-01-17 21:48:47 +02003659 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03003660
Johan Hedbergb644ba32012-01-17 21:48:47 +02003661 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03003662
Johan Hedbergb644ba32012-01-17 21:48:47 +02003663 bacpy(&ev->addr.bdaddr, bdaddr);
3664 ev->addr.type = link_to_mgmt(link_type, addr_type);
3665 ev->rssi = rssi;
3666
3667 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
3668 name_len);
3669
3670 put_unaligned_le16(eir_len, &ev->eir_len);
3671
Johan Hedberg053c7e02012-02-04 00:06:00 +02003672 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev,
3673 sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03003674}
Johan Hedberg314b2382011-04-27 10:29:57 -04003675
Andre Guedes7a135102011-11-09 17:14:25 -03003676int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
Johan Hedberg164a6e72011-11-01 17:06:44 +02003677{
3678 struct pending_cmd *cmd;
Johan Hedbergf808e162012-02-19 12:52:07 +02003679 u8 type;
Johan Hedberg164a6e72011-11-01 17:06:44 +02003680 int err;
3681
Andre Guedes203159d2012-02-13 15:41:01 -03003682 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3683
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003684 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003685 if (!cmd)
3686 return -ENOENT;
3687
Johan Hedbergf808e162012-02-19 12:52:07 +02003688 type = hdev->discovery.type;
3689
3690 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
3691 &type, sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02003692 mgmt_pending_remove(cmd);
3693
3694 return err;
3695}
3696
Andre Guedese6d465c2011-11-09 17:14:26 -03003697int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
3698{
3699 struct pending_cmd *cmd;
3700 int err;
3701
3702 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
3703 if (!cmd)
3704 return -ENOENT;
3705
Johan Hedbergd9306502012-02-20 23:25:18 +02003706 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
3707 &hdev->discovery.type,
3708 sizeof(hdev->discovery.type));
Johan Hedberg03811012010-12-08 00:21:06 +02003709 mgmt_pending_remove(cmd);
3710
3711 return err;
3712}
Johan Hedberg314b2382011-04-27 10:29:57 -04003713
Johan Hedberg744cf192011-11-08 20:40:14 +02003714int mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04003715{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02003716 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02003717 struct pending_cmd *cmd;
3718
Andre Guedes343fb142011-11-22 17:14:19 -03003719 BT_DBG("%s discovering %u", hdev->name, discovering);
3720
Johan Hedberg164a6e72011-11-01 17:06:44 +02003721 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003722 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003723 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003724 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003725
3726 if (cmd != NULL) {
Johan Hedbergf808e162012-02-19 12:52:07 +02003727 u8 type = hdev->discovery.type;
3728
Johan Hedbergd9306502012-02-20 23:25:18 +02003729 cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0,
Johan Hedbergf808e162012-02-19 12:52:07 +02003730 &type, sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02003731 mgmt_pending_remove(cmd);
3732 }
3733
Johan Hedbergf963e8e2012-02-20 23:30:44 +02003734 memset(&ev, 0, sizeof(ev));
3735 ev.type = hdev->discovery.type;
3736 ev.discovering = discovering;
3737
3738 return mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04003739}
Antti Julku5e762442011-08-25 16:48:02 +03003740
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003741int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003742{
3743 struct pending_cmd *cmd;
3744 struct mgmt_ev_device_blocked ev;
3745
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003746 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003747
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003748 bacpy(&ev.addr.bdaddr, bdaddr);
3749 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003750
Johan Hedberg744cf192011-11-08 20:40:14 +02003751 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
3752 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003753}
3754
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003755int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003756{
3757 struct pending_cmd *cmd;
3758 struct mgmt_ev_device_unblocked ev;
3759
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003760 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003761
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003762 bacpy(&ev.addr.bdaddr, bdaddr);
3763 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003764
Johan Hedberg744cf192011-11-08 20:40:14 +02003765 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
3766 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003767}
Marcel Holtmannd7b7e792012-02-20 21:47:49 +01003768
3769module_param(enable_hs, bool, 0644);
3770MODULE_PARM_DESC(enable_hs, "Enable High Speed support");
3771
3772module_param(enable_le, bool, 0644);
3773MODULE_PARM_DESC(enable_le, "Enable Low Energy support");