blob: 69d4e1a699a3fb0300f7322f6132bbfa25df3668 [file] [log] [blame]
Johan Hedberg03811012010-12-08 00:21:06 +02001/*
2 BlueZ - Bluetooth protocol stack for Linux
Johan Hedbergea585ab2012-02-17 14:50:39 +02003
Johan Hedberg03811012010-12-08 00:21:06 +02004 Copyright (C) 2010 Nokia Corporation
Johan Hedbergea585ab2012-02-17 14:50:39 +02005 Copyright (C) 2011-2012 Intel Corporation
Johan Hedberg03811012010-12-08 00:21:06 +02006
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License version 2 as
9 published by the Free Software Foundation;
10
11 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
12 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
13 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
14 IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
15 CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
16 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19
20 ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
21 COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
22 SOFTWARE IS DISCLAIMED.
23*/
24
25/* Bluetooth HCI Management interface */
26
Johan Hedbergca69b792011-11-11 18:10:00 +020027#include <linux/kernel.h>
Szymon Janc72359752011-02-17 14:16:32 +010028#include <linux/uaccess.h>
Paul Gortmaker3a9a2312011-05-27 09:12:25 -040029#include <linux/module.h>
Johan Hedberg03811012010-12-08 00:21:06 +020030#include <asm/unaligned.h>
31
32#include <net/bluetooth/bluetooth.h>
33#include <net/bluetooth/hci_core.h>
34#include <net/bluetooth/mgmt.h>
Brian Gix5fe57d92011-12-21 16:12:13 -080035#include <net/bluetooth/smp.h>
Johan Hedberg03811012010-12-08 00:21:06 +020036
Marcel Holtmannd7b7e792012-02-20 21:47:49 +010037bool enable_hs;
38bool enable_le;
39
Johan Hedberg2da9c552012-02-17 14:39:28 +020040#define MGMT_VERSION 1
41#define MGMT_REVISION 0
Johan Hedberg02d98122010-12-13 21:07:04 +020042
Johan Hedberge70bb2e2012-02-13 16:59:33 +020043static const u16 mgmt_commands[] = {
44 MGMT_OP_READ_INDEX_LIST,
45 MGMT_OP_READ_INFO,
46 MGMT_OP_SET_POWERED,
47 MGMT_OP_SET_DISCOVERABLE,
48 MGMT_OP_SET_CONNECTABLE,
49 MGMT_OP_SET_FAST_CONNECTABLE,
50 MGMT_OP_SET_PAIRABLE,
51 MGMT_OP_SET_LINK_SECURITY,
52 MGMT_OP_SET_SSP,
53 MGMT_OP_SET_HS,
54 MGMT_OP_SET_LE,
55 MGMT_OP_SET_DEV_CLASS,
56 MGMT_OP_SET_LOCAL_NAME,
57 MGMT_OP_ADD_UUID,
58 MGMT_OP_REMOVE_UUID,
59 MGMT_OP_LOAD_LINK_KEYS,
60 MGMT_OP_LOAD_LONG_TERM_KEYS,
61 MGMT_OP_DISCONNECT,
62 MGMT_OP_GET_CONNECTIONS,
63 MGMT_OP_PIN_CODE_REPLY,
64 MGMT_OP_PIN_CODE_NEG_REPLY,
65 MGMT_OP_SET_IO_CAPABILITY,
66 MGMT_OP_PAIR_DEVICE,
67 MGMT_OP_CANCEL_PAIR_DEVICE,
68 MGMT_OP_UNPAIR_DEVICE,
69 MGMT_OP_USER_CONFIRM_REPLY,
70 MGMT_OP_USER_CONFIRM_NEG_REPLY,
71 MGMT_OP_USER_PASSKEY_REPLY,
72 MGMT_OP_USER_PASSKEY_NEG_REPLY,
73 MGMT_OP_READ_LOCAL_OOB_DATA,
74 MGMT_OP_ADD_REMOTE_OOB_DATA,
75 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
76 MGMT_OP_START_DISCOVERY,
77 MGMT_OP_STOP_DISCOVERY,
78 MGMT_OP_CONFIRM_NAME,
79 MGMT_OP_BLOCK_DEVICE,
80 MGMT_OP_UNBLOCK_DEVICE,
81};
82
83static const u16 mgmt_events[] = {
84 MGMT_EV_CONTROLLER_ERROR,
85 MGMT_EV_INDEX_ADDED,
86 MGMT_EV_INDEX_REMOVED,
87 MGMT_EV_NEW_SETTINGS,
88 MGMT_EV_CLASS_OF_DEV_CHANGED,
89 MGMT_EV_LOCAL_NAME_CHANGED,
90 MGMT_EV_NEW_LINK_KEY,
91 MGMT_EV_NEW_LONG_TERM_KEY,
92 MGMT_EV_DEVICE_CONNECTED,
93 MGMT_EV_DEVICE_DISCONNECTED,
94 MGMT_EV_CONNECT_FAILED,
95 MGMT_EV_PIN_CODE_REQUEST,
96 MGMT_EV_USER_CONFIRM_REQUEST,
97 MGMT_EV_USER_PASSKEY_REQUEST,
98 MGMT_EV_AUTH_FAILED,
99 MGMT_EV_DEVICE_FOUND,
100 MGMT_EV_DISCOVERING,
101 MGMT_EV_DEVICE_BLOCKED,
102 MGMT_EV_DEVICE_UNBLOCKED,
103 MGMT_EV_DEVICE_UNPAIRED,
104};
105
Andre Guedes3fd24152012-02-03 17:48:01 -0300106/*
107 * These LE scan and inquiry parameters were chosen according to LE General
108 * Discovery Procedure specification.
109 */
110#define LE_SCAN_TYPE 0x01
111#define LE_SCAN_WIN 0x12
112#define LE_SCAN_INT 0x12
113#define LE_SCAN_TIMEOUT_LE_ONLY 10240 /* TGAP(gen_disc_scan_min) */
Andre Guedes5e0452c2012-02-17 20:39:38 -0300114#define LE_SCAN_TIMEOUT_BREDR_LE 5120 /* TGAP(100)/2 */
Andre Guedes3fd24152012-02-03 17:48:01 -0300115
Andre Guedese8777522012-02-03 17:48:02 -0300116#define INQUIRY_LEN_BREDR 0x08 /* TGAP(100) */
Andre Guedes5e0452c2012-02-17 20:39:38 -0300117#define INQUIRY_LEN_BREDR_LE 0x04 /* TGAP(100)/2 */
Andre Guedes2519a1f2011-11-07 11:45:24 -0300118
Johan Hedberg7d785252011-12-15 00:47:39 +0200119#define SERVICE_CACHE_TIMEOUT (5 * 1000)
120
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200121#define hdev_is_powered(hdev) (test_bit(HCI_UP, &hdev->flags) && \
122 !test_bit(HCI_AUTO_OFF, &hdev->dev_flags))
123
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200124struct pending_cmd {
125 struct list_head list;
Johan Hedbergfc2f4b12011-11-09 13:58:56 +0200126 u16 opcode;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200127 int index;
Szymon Jancc68fb7f2011-03-22 13:12:19 +0100128 void *param;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200129 struct sock *sk;
Johan Hedberge9a416b2011-02-19 12:05:56 -0300130 void *user_data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200131};
132
Johan Hedbergca69b792011-11-11 18:10:00 +0200133/* HCI to MGMT error code conversion table */
134static u8 mgmt_status_table[] = {
135 MGMT_STATUS_SUCCESS,
136 MGMT_STATUS_UNKNOWN_COMMAND, /* Unknown Command */
137 MGMT_STATUS_NOT_CONNECTED, /* No Connection */
138 MGMT_STATUS_FAILED, /* Hardware Failure */
139 MGMT_STATUS_CONNECT_FAILED, /* Page Timeout */
140 MGMT_STATUS_AUTH_FAILED, /* Authentication Failed */
141 MGMT_STATUS_NOT_PAIRED, /* PIN or Key Missing */
142 MGMT_STATUS_NO_RESOURCES, /* Memory Full */
143 MGMT_STATUS_TIMEOUT, /* Connection Timeout */
144 MGMT_STATUS_NO_RESOURCES, /* Max Number of Connections */
145 MGMT_STATUS_NO_RESOURCES, /* Max Number of SCO Connections */
146 MGMT_STATUS_ALREADY_CONNECTED, /* ACL Connection Exists */
147 MGMT_STATUS_BUSY, /* Command Disallowed */
148 MGMT_STATUS_NO_RESOURCES, /* Rejected Limited Resources */
149 MGMT_STATUS_REJECTED, /* Rejected Security */
150 MGMT_STATUS_REJECTED, /* Rejected Personal */
151 MGMT_STATUS_TIMEOUT, /* Host Timeout */
152 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Feature */
153 MGMT_STATUS_INVALID_PARAMS, /* Invalid Parameters */
154 MGMT_STATUS_DISCONNECTED, /* OE User Ended Connection */
155 MGMT_STATUS_NO_RESOURCES, /* OE Low Resources */
156 MGMT_STATUS_DISCONNECTED, /* OE Power Off */
157 MGMT_STATUS_DISCONNECTED, /* Connection Terminated */
158 MGMT_STATUS_BUSY, /* Repeated Attempts */
159 MGMT_STATUS_REJECTED, /* Pairing Not Allowed */
160 MGMT_STATUS_FAILED, /* Unknown LMP PDU */
161 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Remote Feature */
162 MGMT_STATUS_REJECTED, /* SCO Offset Rejected */
163 MGMT_STATUS_REJECTED, /* SCO Interval Rejected */
164 MGMT_STATUS_REJECTED, /* Air Mode Rejected */
165 MGMT_STATUS_INVALID_PARAMS, /* Invalid LMP Parameters */
166 MGMT_STATUS_FAILED, /* Unspecified Error */
167 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported LMP Parameter Value */
168 MGMT_STATUS_FAILED, /* Role Change Not Allowed */
169 MGMT_STATUS_TIMEOUT, /* LMP Response Timeout */
170 MGMT_STATUS_FAILED, /* LMP Error Transaction Collision */
171 MGMT_STATUS_FAILED, /* LMP PDU Not Allowed */
172 MGMT_STATUS_REJECTED, /* Encryption Mode Not Accepted */
173 MGMT_STATUS_FAILED, /* Unit Link Key Used */
174 MGMT_STATUS_NOT_SUPPORTED, /* QoS Not Supported */
175 MGMT_STATUS_TIMEOUT, /* Instant Passed */
176 MGMT_STATUS_NOT_SUPPORTED, /* Pairing Not Supported */
177 MGMT_STATUS_FAILED, /* Transaction Collision */
178 MGMT_STATUS_INVALID_PARAMS, /* Unacceptable Parameter */
179 MGMT_STATUS_REJECTED, /* QoS Rejected */
180 MGMT_STATUS_NOT_SUPPORTED, /* Classification Not Supported */
181 MGMT_STATUS_REJECTED, /* Insufficient Security */
182 MGMT_STATUS_INVALID_PARAMS, /* Parameter Out Of Range */
183 MGMT_STATUS_BUSY, /* Role Switch Pending */
184 MGMT_STATUS_FAILED, /* Slot Violation */
185 MGMT_STATUS_FAILED, /* Role Switch Failed */
186 MGMT_STATUS_INVALID_PARAMS, /* EIR Too Large */
187 MGMT_STATUS_NOT_SUPPORTED, /* Simple Pairing Not Supported */
188 MGMT_STATUS_BUSY, /* Host Busy Pairing */
189 MGMT_STATUS_REJECTED, /* Rejected, No Suitable Channel */
190 MGMT_STATUS_BUSY, /* Controller Busy */
191 MGMT_STATUS_INVALID_PARAMS, /* Unsuitable Connection Interval */
192 MGMT_STATUS_TIMEOUT, /* Directed Advertising Timeout */
193 MGMT_STATUS_AUTH_FAILED, /* Terminated Due to MIC Failure */
194 MGMT_STATUS_CONNECT_FAILED, /* Connection Establishment Failed */
195 MGMT_STATUS_CONNECT_FAILED, /* MAC Connection Failed */
196};
197
198static u8 mgmt_status(u8 hci_status)
199{
200 if (hci_status < ARRAY_SIZE(mgmt_status_table))
201 return mgmt_status_table[hci_status];
202
203 return MGMT_STATUS_FAILED;
204}
205
Szymon Janc4e51eae2011-02-25 19:05:48 +0100206static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200207{
208 struct sk_buff *skb;
209 struct mgmt_hdr *hdr;
210 struct mgmt_ev_cmd_status *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300211 int err;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200212
Szymon Janc34eb5252011-02-28 14:10:08 +0100213 BT_DBG("sock %p, index %u, cmd %u, status %u", sk, index, cmd, status);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200214
215 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_ATOMIC);
216 if (!skb)
217 return -ENOMEM;
218
219 hdr = (void *) skb_put(skb, sizeof(*hdr));
220
221 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_STATUS);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100222 hdr->index = cpu_to_le16(index);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200223 hdr->len = cpu_to_le16(sizeof(*ev));
224
225 ev = (void *) skb_put(skb, sizeof(*ev));
226 ev->status = status;
227 put_unaligned_le16(cmd, &ev->opcode);
228
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300229 err = sock_queue_rcv_skb(sk, skb);
230 if (err < 0)
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200231 kfree_skb(skb);
232
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300233 return err;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200234}
235
Johan Hedbergaee9b2182012-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 Hedbergaee9b2182012-02-18 15:07:59 +0200258 ev->status = status;
Szymon Janc8020c162011-02-28 14:09:50 +0100259
260 if (rp)
261 memcpy(ev->data, rp, rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200262
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300263 err = sock_queue_rcv_skb(sk, skb);
264 if (err < 0)
Johan Hedberg02d98122010-12-13 21:07:04 +0200265 kfree_skb(skb);
266
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300267 return err;;
Johan Hedberg02d98122010-12-13 21:07:04 +0200268}
269
Johan Hedberga38528f2011-01-22 06:46:43 +0200270static int read_version(struct sock *sk)
271{
272 struct mgmt_rp_read_version rp;
273
274 BT_DBG("sock %p", sk);
275
276 rp.version = MGMT_VERSION;
277 put_unaligned_le16(MGMT_REVISION, &rp.revision);
278
Johan Hedbergaee9b2182012-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 Hedbergaee9b2182012-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 Hedbergaee9b2182012-02-18 15:07:59 +0200354 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST, 0, rp,
Szymon Janc4e51eae2011-02-25 19:05:48 +0100355 rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200356
Johan Hedberga38528f2011-01-22 06:46:43 +0200357 kfree(rp);
358
359 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200360}
361
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200362static u32 get_supported_settings(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +0200363{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200364 u32 settings = 0;
Johan Hedberg03811012010-12-08 00:21:06 +0200365
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200366 settings |= MGMT_SETTING_POWERED;
367 settings |= MGMT_SETTING_CONNECTABLE;
368 settings |= MGMT_SETTING_FAST_CONNECTABLE;
369 settings |= MGMT_SETTING_DISCOVERABLE;
370 settings |= MGMT_SETTING_PAIRABLE;
Johan Hedberg03811012010-12-08 00:21:06 +0200371
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200372 if (hdev->features[6] & LMP_SIMPLE_PAIR)
373 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200374
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200375 if (!(hdev->features[4] & LMP_NO_BREDR)) {
376 settings |= MGMT_SETTING_BREDR;
377 settings |= MGMT_SETTING_LINK_SECURITY;
378 }
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200379
Marcel Holtmannd7b7e792012-02-20 21:47:49 +0100380 if (enable_hs)
381 settings |= MGMT_SETTING_HS;
382
383 if (enable_le) {
384 if (hdev->features[4] & LMP_LE)
385 settings |= MGMT_SETTING_LE;
386 }
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200387
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200388 return settings;
389}
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200390
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200391static u32 get_current_settings(struct hci_dev *hdev)
392{
393 u32 settings = 0;
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200394
Johan Hedbergf1f0eb02012-02-21 17:15:41 +0200395 if (hdev_is_powered(hdev))
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100396 settings |= MGMT_SETTING_POWERED;
397
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200398 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200399 settings |= MGMT_SETTING_CONNECTABLE;
400
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200401 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200402 settings |= MGMT_SETTING_DISCOVERABLE;
403
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200404 if (test_bit(HCI_PAIRABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200405 settings |= MGMT_SETTING_PAIRABLE;
406
407 if (!(hdev->features[4] & LMP_NO_BREDR))
408 settings |= MGMT_SETTING_BREDR;
409
Andre Guedes59e29402011-12-30 10:34:03 -0300410 if (hdev->host_features[0] & LMP_HOST_LE)
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200411 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200412
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 Hedbergf7b64e62010-12-13 21:07:06 +0200415
Johan Hedberg84bde9d2012-01-25 14:21:06 +0200416 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200417 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200418
Johan Hedberg6d80dfd2012-02-20 23:50:38 +0200419 if (test_bit(HCI_HS_ENABLED, &hdev->dev_flags))
420 settings |= MGMT_SETTING_HS;
421
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200422 return settings;
Johan Hedbergc542a062011-01-26 13:11:03 +0200423}
424
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300425#define PNP_INFO_SVCLASS_ID 0x1200
426
427static u8 bluetooth_base_uuid[] = {
428 0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80,
429 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
430};
431
432static u16 get_uuid16(u8 *uuid128)
433{
434 u32 val;
435 int i;
436
437 for (i = 0; i < 12; i++) {
438 if (bluetooth_base_uuid[i] != uuid128[i])
439 return 0;
440 }
441
442 memcpy(&val, &uuid128[12], 4);
443
444 val = le32_to_cpu(val);
445 if (val > 0xffff)
446 return 0;
447
448 return (u16) val;
449}
450
451static void create_eir(struct hci_dev *hdev, u8 *data)
452{
453 u8 *ptr = data;
454 u16 eir_len = 0;
455 u16 uuid16_list[HCI_MAX_EIR_LENGTH / sizeof(u16)];
456 int i, truncated = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200457 struct bt_uuid *uuid;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300458 size_t name_len;
459
460 name_len = strlen(hdev->dev_name);
461
462 if (name_len > 0) {
463 /* EIR Data type */
464 if (name_len > 48) {
465 name_len = 48;
466 ptr[1] = EIR_NAME_SHORT;
467 } else
468 ptr[1] = EIR_NAME_COMPLETE;
469
470 /* EIR Data length */
471 ptr[0] = name_len + 1;
472
473 memcpy(ptr + 2, hdev->dev_name, name_len);
474
475 eir_len += (name_len + 2);
476 ptr += (name_len + 2);
477 }
478
479 memset(uuid16_list, 0, sizeof(uuid16_list));
480
481 /* Group all UUID16 types */
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200482 list_for_each_entry(uuid, &hdev->uuids, list) {
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300483 u16 uuid16;
484
485 uuid16 = get_uuid16(uuid->uuid);
486 if (uuid16 == 0)
487 return;
488
489 if (uuid16 < 0x1100)
490 continue;
491
492 if (uuid16 == PNP_INFO_SVCLASS_ID)
493 continue;
494
495 /* Stop if not enough space to put next UUID */
496 if (eir_len + 2 + sizeof(u16) > HCI_MAX_EIR_LENGTH) {
497 truncated = 1;
498 break;
499 }
500
501 /* Check for duplicates */
502 for (i = 0; uuid16_list[i] != 0; i++)
503 if (uuid16_list[i] == uuid16)
504 break;
505
506 if (uuid16_list[i] == 0) {
507 uuid16_list[i] = uuid16;
508 eir_len += sizeof(u16);
509 }
510 }
511
512 if (uuid16_list[0] != 0) {
513 u8 *length = ptr;
514
515 /* EIR Data type */
516 ptr[1] = truncated ? EIR_UUID16_SOME : EIR_UUID16_ALL;
517
518 ptr += 2;
519 eir_len += 2;
520
521 for (i = 0; uuid16_list[i] != 0; i++) {
522 *ptr++ = (uuid16_list[i] & 0x00ff);
523 *ptr++ = (uuid16_list[i] & 0xff00) >> 8;
524 }
525
526 /* EIR Data length */
527 *length = (i * sizeof(u16)) + 1;
528 }
529}
530
531static int update_eir(struct hci_dev *hdev)
532{
533 struct hci_cp_write_eir cp;
534
535 if (!(hdev->features[6] & LMP_EXT_INQ))
536 return 0;
537
Johan Hedberg84bde9d2012-01-25 14:21:06 +0200538 if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300539 return 0;
540
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200541 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300542 return 0;
543
544 memset(&cp, 0, sizeof(cp));
545
546 create_eir(hdev, cp.data);
547
548 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
549 return 0;
550
551 memcpy(hdev->eir, cp.data, sizeof(cp.data));
552
553 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
554}
555
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200556static u8 get_service_classes(struct hci_dev *hdev)
557{
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300558 struct bt_uuid *uuid;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200559 u8 val = 0;
560
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300561 list_for_each_entry(uuid, &hdev->uuids, list)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200562 val |= uuid->svc_hint;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200563
564 return val;
565}
566
567static int update_class(struct hci_dev *hdev)
568{
569 u8 cod[3];
570
571 BT_DBG("%s", hdev->name);
572
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200573 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200574 return 0;
575
576 cod[0] = hdev->minor_class;
577 cod[1] = hdev->major_class;
578 cod[2] = get_service_classes(hdev);
579
580 if (memcmp(cod, hdev->dev_class, 3) == 0)
581 return 0;
582
583 return hci_send_cmd(hdev, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
584}
585
Johan Hedberg7d785252011-12-15 00:47:39 +0200586static void service_cache_off(struct work_struct *work)
587{
588 struct hci_dev *hdev = container_of(work, struct hci_dev,
589 service_cache.work);
590
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200591 if (!test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200592 return;
593
594 hci_dev_lock(hdev);
595
596 update_eir(hdev);
597 update_class(hdev);
598
599 hci_dev_unlock(hdev);
600}
601
602static void mgmt_init_hdev(struct hci_dev *hdev)
603{
Johan Hedberg0cbf4ed62012-02-21 17:25:22 +0200604 if (!test_and_set_bit(HCI_MGMT, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +0200605 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
606
Johan Hedberg0cbf4ed62012-02-21 17:25:22 +0200607 /* Non-mgmt controlled devices get this bit set
608 * implicitly so that pairing works for them, however
609 * for mgmt we require user-space to explicitly enable
610 * it
611 */
612 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
613 }
614
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200615 if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200616 schedule_delayed_work(&hdev->service_cache,
617 msecs_to_jiffies(SERVICE_CACHE_TIMEOUT));
618}
619
Johan Hedberg03811012010-12-08 00:21:06 +0200620static int read_controller_info(struct sock *sk, u16 index)
621{
622 struct mgmt_rp_read_info rp;
623 struct hci_dev *hdev;
624
625 BT_DBG("sock %p hci%u", sk, index);
626
627 hdev = hci_dev_get(index);
628 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200629 return cmd_status(sk, index, MGMT_OP_READ_INFO,
630 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200631
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300632 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200633
Johan Hedberg7d785252011-12-15 00:47:39 +0200634 if (test_and_clear_bit(HCI_PI_MGMT_INIT, &hci_pi(sk)->flags))
635 mgmt_init_hdev(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200636
637 memset(&rp, 0, sizeof(rp));
638
Johan Hedberg03811012010-12-08 00:21:06 +0200639 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200640
641 rp.version = hdev->hci_ver;
642
Johan Hedberg03811012010-12-08 00:21:06 +0200643 put_unaligned_le16(hdev->manufacturer, &rp.manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200644
645 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
646 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
647
648 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedberg03811012010-12-08 00:21:06 +0200649
650 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
651
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300652 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200653 hci_dev_put(hdev);
654
Johan Hedbergaee9b2182012-02-18 15:07:59 +0200655 return cmd_complete(sk, index, MGMT_OP_READ_INFO, 0, &rp, sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +0200656}
657
658static void mgmt_pending_free(struct pending_cmd *cmd)
659{
660 sock_put(cmd->sk);
661 kfree(cmd->param);
662 kfree(cmd);
663}
664
665static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
666 struct hci_dev *hdev,
667 void *data, u16 len)
668{
669 struct pending_cmd *cmd;
670
671 cmd = kmalloc(sizeof(*cmd), GFP_ATOMIC);
672 if (!cmd)
673 return NULL;
674
675 cmd->opcode = opcode;
676 cmd->index = hdev->id;
677
678 cmd->param = kmalloc(len, GFP_ATOMIC);
679 if (!cmd->param) {
680 kfree(cmd);
681 return NULL;
682 }
683
684 if (data)
685 memcpy(cmd->param, data, len);
686
687 cmd->sk = sk;
688 sock_hold(sk);
689
690 list_add(&cmd->list, &hdev->mgmt_pending);
691
692 return cmd;
693}
694
695static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
696 void (*cb)(struct pending_cmd *cmd, void *data),
697 void *data)
698{
699 struct list_head *p, *n;
700
701 list_for_each_safe(p, n, &hdev->mgmt_pending) {
702 struct pending_cmd *cmd;
703
704 cmd = list_entry(p, struct pending_cmd, list);
705
706 if (opcode > 0 && cmd->opcode != opcode)
707 continue;
708
709 cb(cmd, data);
710 }
711}
712
713static struct pending_cmd *mgmt_pending_find(u16 opcode, struct hci_dev *hdev)
714{
715 struct pending_cmd *cmd;
716
717 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
718 if (cmd->opcode == opcode)
719 return cmd;
720 }
721
722 return NULL;
723}
724
725static void mgmt_pending_remove(struct pending_cmd *cmd)
726{
727 list_del(&cmd->list);
728 mgmt_pending_free(cmd);
729}
730
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200731static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +0200732{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200733 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +0200734
Johan Hedbergaee9b2182012-02-18 15:07:59 +0200735 return cmd_complete(sk, hdev->id, opcode, 0, &settings,
736 sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +0200737}
738
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300739static int set_powered(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200740{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300741 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200742 struct hci_dev *hdev;
743 struct pending_cmd *cmd;
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200744 int err;
Johan Hedberg03811012010-12-08 00:21:06 +0200745
Johan Hedberg03811012010-12-08 00:21:06 +0200746 BT_DBG("request for hci%u", index);
747
748 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200749 return cmd_status(sk, index, MGMT_OP_SET_POWERED,
750 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200751
752 hdev = hci_dev_get(index);
753 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200754 return cmd_status(sk, index, MGMT_OP_SET_POWERED,
755 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200756
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300757 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200758
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100759 if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) {
760 cancel_delayed_work(&hdev->power_off);
761
762 if (cp->val) {
763 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
764 mgmt_powered(hdev, 1);
765 goto failed;
766 }
767 }
768
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200769 if (!!cp->val == hdev_is_powered(hdev)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200770 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200771 goto failed;
772 }
773
774 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200775 err = cmd_status(sk, index, MGMT_OP_SET_POWERED,
776 MGMT_STATUS_BUSY);
Johan Hedberg03811012010-12-08 00:21:06 +0200777 goto failed;
778 }
779
780 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
781 if (!cmd) {
782 err = -ENOMEM;
783 goto failed;
784 }
785
786 if (cp->val)
Gustavo F. Padovan7f971042011-12-18 12:40:32 -0200787 schedule_work(&hdev->power_on);
Johan Hedberg03811012010-12-08 00:21:06 +0200788 else
Gustavo F. Padovan80b7ab32011-12-17 14:52:27 -0200789 schedule_work(&hdev->power_off.work);
Johan Hedberg03811012010-12-08 00:21:06 +0200790
791 err = 0;
792
793failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300794 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200795 hci_dev_put(hdev);
796 return err;
797}
798
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200799static int mgmt_event(u16 event, struct hci_dev *hdev, void *data,
800 u16 data_len, struct sock *skip_sk)
801{
802 struct sk_buff *skb;
803 struct mgmt_hdr *hdr;
804
805 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_ATOMIC);
806 if (!skb)
807 return -ENOMEM;
808
809 hdr = (void *) skb_put(skb, sizeof(*hdr));
810 hdr->opcode = cpu_to_le16(event);
811 if (hdev)
812 hdr->index = cpu_to_le16(hdev->id);
813 else
814 hdr->index = cpu_to_le16(MGMT_INDEX_NONE);
815 hdr->len = cpu_to_le16(data_len);
816
817 if (data)
818 memcpy(skb_put(skb, data_len), data, data_len);
819
820 hci_send_to_control(skb, skip_sk);
821 kfree_skb(skb);
822
823 return 0;
824}
825
826static int new_settings(struct hci_dev *hdev, struct sock *skip)
827{
828 __le32 ev;
829
830 ev = cpu_to_le32(get_current_settings(hdev));
831
832 return mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), skip);
833}
834
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300835static int set_discoverable(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200836{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300837 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberge41d8b42010-12-13 21:07:03 +0200838 struct hci_dev *hdev;
Johan Hedberg03811012010-12-08 00:21:06 +0200839 struct pending_cmd *cmd;
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200840 u16 timeout;
Johan Hedberg03811012010-12-08 00:21:06 +0200841 u8 scan;
842 int err;
843
Johan Hedberg03811012010-12-08 00:21:06 +0200844 BT_DBG("request for hci%u", index);
845
846 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200847 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
848 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200849
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200850 hdev = hci_dev_get(index);
851 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200852 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
853 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200854
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200855 timeout = get_unaligned_le16(&cp->timeout);
856
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300857 hci_dev_lock(hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200858
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200859 if (!hdev_is_powered(hdev) && timeout > 0) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200860 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
861 MGMT_STATUS_NOT_POWERED);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200862 goto failed;
863 }
864
865 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
866 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200867 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
868 MGMT_STATUS_BUSY);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200869 goto failed;
870 }
871
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200872 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) {
873 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
874 MGMT_STATUS_REJECTED);
875 goto failed;
876 }
877
878 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200879 bool changed = false;
880
881 if (!!cp->val != test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
882 change_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
883 changed = true;
884 }
885
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200886 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200887 if (err < 0)
888 goto failed;
889
890 if (changed)
891 err = new_settings(hdev, sk);
892
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200893 goto failed;
894 }
895
896 if (!!cp->val == test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200897 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200898 goto failed;
899 }
900
901 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
902 if (!cmd) {
903 err = -ENOMEM;
904 goto failed;
905 }
906
907 scan = SCAN_PAGE;
908
909 if (cp->val)
910 scan |= SCAN_INQUIRY;
911 else
912 cancel_delayed_work(&hdev->discov_off);
913
914 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
915 if (err < 0)
916 mgmt_pending_remove(cmd);
917
Johan Hedberg03811012010-12-08 00:21:06 +0200918 if (cp->val)
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200919 hdev->discov_timeout = timeout;
Johan Hedberg03811012010-12-08 00:21:06 +0200920
921failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300922 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200923 hci_dev_put(hdev);
924
925 return err;
926}
927
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300928static int set_connectable(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200929{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300930 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200931 struct hci_dev *hdev;
932 struct pending_cmd *cmd;
933 u8 scan;
934 int err;
935
Johan Hedberge41d8b42010-12-13 21:07:03 +0200936 BT_DBG("request for hci%u", index);
937
Johan Hedberg03811012010-12-08 00:21:06 +0200938 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200939 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
940 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200941
942 hdev = hci_dev_get(index);
943 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200944 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
945 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200946
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300947 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200948
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200949 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200950 bool changed = false;
951
952 if (!!cp->val != test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
953 changed = true;
954
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200955 if (cp->val)
956 set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
957 else {
958 clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
959 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
960 }
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200961
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200962 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200963 if (err < 0)
964 goto failed;
965
966 if (changed)
967 err = new_settings(hdev, sk);
968
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200969 goto failed;
970 }
971
972 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
973 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200974 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
975 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200976 goto failed;
977 }
978
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200979 if (!!cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200980 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200981 goto failed;
982 }
983
984 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
985 if (!cmd) {
986 err = -ENOMEM;
987 goto failed;
988 }
989
990 if (cp->val)
991 scan = SCAN_PAGE;
Johan Hedbergdf2c6c52012-02-21 19:15:49 +0200992 else {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200993 scan = 0;
994
Johan Hedbergdf2c6c52012-02-21 19:15:49 +0200995 if (test_bit(HCI_ISCAN, &hdev->flags) &&
996 hdev->discov_timeout > 0)
997 cancel_delayed_work(&hdev->discov_off);
998 }
999
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001000 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1001 if (err < 0)
1002 mgmt_pending_remove(cmd);
1003
1004failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001005 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001006 hci_dev_put(hdev);
1007
1008 return err;
1009}
1010
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001011static int set_pairable(struct sock *sk, u16 index, void *data, 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 struct hci_dev *hdev;
1015 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001016
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001017 BT_DBG("request for hci%u", index);
1018
1019 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001020 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE,
1021 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001022
1023 hdev = hci_dev_get(index);
1024 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001025 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE,
1026 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001027
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001028 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001029
1030 if (cp->val)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001031 set_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001032 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001033 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001034
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001035 err = send_settings_rsp(sk, MGMT_OP_SET_PAIRABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001036 if (err < 0)
1037 goto failed;
1038
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001039 err = new_settings(hdev, sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001040
1041failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001042 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001043 hci_dev_put(hdev);
1044
1045 return err;
1046}
Johan Hedberg72a734e2010-12-30 00:38:22 +02001047
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001048static int set_link_security(struct sock *sk, u16 index, void *data, u16 len)
1049{
1050 struct mgmt_mode *cp = data;
1051 struct pending_cmd *cmd;
1052 struct hci_dev *hdev;
1053 uint8_t val;
1054 int err;
1055
1056 BT_DBG("request for hci%u", index);
1057
1058 if (len != sizeof(*cp))
1059 return cmd_status(sk, index, MGMT_OP_SET_LINK_SECURITY,
1060 MGMT_STATUS_INVALID_PARAMS);
1061
1062 hdev = hci_dev_get(index);
1063 if (!hdev)
1064 return cmd_status(sk, index, MGMT_OP_SET_LINK_SECURITY,
1065 MGMT_STATUS_INVALID_PARAMS);
1066
1067 hci_dev_lock(hdev);
1068
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001069 if (!hdev_is_powered(hdev)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001070 bool changed = false;
1071
1072 if (!!cp->val != test_bit(HCI_LINK_SECURITY,
1073 &hdev->dev_flags)) {
1074 change_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
1075 changed = true;
1076 }
1077
1078 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1079 if (err < 0)
1080 goto failed;
1081
1082 if (changed)
1083 err = new_settings(hdev, sk);
1084
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001085 goto failed;
1086 }
1087
1088 if (mgmt_pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
1089 err = cmd_status(sk, index, MGMT_OP_SET_LINK_SECURITY,
1090 MGMT_STATUS_BUSY);
1091 goto failed;
1092 }
1093
1094 val = !!cp->val;
1095
1096 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1097 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1098 goto failed;
1099 }
1100
1101 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1102 if (!cmd) {
1103 err = -ENOMEM;
1104 goto failed;
1105 }
1106
1107 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1108 if (err < 0) {
1109 mgmt_pending_remove(cmd);
1110 goto failed;
1111 }
1112
1113failed:
1114 hci_dev_unlock(hdev);
1115 hci_dev_put(hdev);
1116
1117 return err;
1118}
1119
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001120static int set_ssp(struct sock *sk, u16 index, void *data, u16 len)
1121{
1122 struct mgmt_mode *cp = data;
1123 struct pending_cmd *cmd;
1124 struct hci_dev *hdev;
1125 uint8_t val;
1126 int err;
1127
1128 BT_DBG("request for hci%u", index);
1129
1130 if (len != sizeof(*cp))
1131 return cmd_status(sk, index, MGMT_OP_SET_SSP,
1132 MGMT_STATUS_INVALID_PARAMS);
1133
1134 hdev = hci_dev_get(index);
1135 if (!hdev)
1136 return cmd_status(sk, index, MGMT_OP_SET_SSP,
1137 MGMT_STATUS_INVALID_PARAMS);
1138
1139 hci_dev_lock(hdev);
1140
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001141 if (!hdev_is_powered(hdev)) {
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001142 err = cmd_status(sk, index, MGMT_OP_SET_SSP,
1143 MGMT_STATUS_NOT_POWERED);
1144 goto failed;
1145 }
1146
Johan Hedberg1e163572012-02-20 23:53:46 +02001147 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
1148 err = cmd_status(sk, index, MGMT_OP_SET_SSP,
1149 MGMT_STATUS_NOT_SUPPORTED);
1150 goto failed;
1151 }
1152
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001153 if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev)) {
1154 err = cmd_status(sk, index, MGMT_OP_SET_SSP, MGMT_STATUS_BUSY);
1155 goto failed;
1156 }
1157
1158 val = !!cp->val;
1159
1160 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) == val) {
1161 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1162 goto failed;
1163 }
1164
1165 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1166 if (!cmd) {
1167 err = -ENOMEM;
1168 goto failed;
1169 }
1170
1171 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, sizeof(val), &val);
1172 if (err < 0) {
1173 mgmt_pending_remove(cmd);
1174 goto failed;
1175 }
1176
1177failed:
1178 hci_dev_unlock(hdev);
1179 hci_dev_put(hdev);
1180
1181 return err;
1182}
1183
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001184static int set_hs(struct sock *sk, u16 index, void *data, u16 len)
1185{
1186 struct mgmt_mode *cp = data;
1187 struct hci_dev *hdev;
1188 int err;
1189
1190 BT_DBG("request for hci%u", index);
1191
1192 if (len != sizeof(*cp))
1193 return cmd_status(sk, index, MGMT_OP_SET_HS,
1194 MGMT_STATUS_INVALID_PARAMS);
1195
1196 hdev = hci_dev_get(index);
1197 if (!hdev)
1198 return cmd_status(sk, index, MGMT_OP_SET_HS,
1199 MGMT_STATUS_INVALID_PARAMS);
1200
1201 if (!enable_hs) {
1202 err = cmd_status(sk, index, MGMT_OP_SET_HS,
1203 MGMT_STATUS_NOT_SUPPORTED);
1204 goto failed;
1205 }
1206
1207 if (cp->val)
1208 set_bit(HCI_HS_ENABLED, &hdev->dev_flags);
1209 else
1210 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
1211
1212 err = send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
1213
1214failed:
1215 hci_dev_put(hdev);
1216 return err;
1217}
1218
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001219static int add_uuid(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001220{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001221 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001222 struct hci_dev *hdev;
1223 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001224 int err;
1225
Szymon Janc4e51eae2011-02-25 19:05:48 +01001226 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001227
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001228 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001229 return cmd_status(sk, index, MGMT_OP_ADD_UUID,
1230 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001231
Szymon Janc4e51eae2011-02-25 19:05:48 +01001232 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001233 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001234 return cmd_status(sk, index, MGMT_OP_ADD_UUID,
1235 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001236
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001237 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001238
1239 uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC);
1240 if (!uuid) {
1241 err = -ENOMEM;
1242 goto failed;
1243 }
1244
1245 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001246 uuid->svc_hint = cp->svc_hint;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001247
1248 list_add(&uuid->list, &hdev->uuids);
1249
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001250 err = update_class(hdev);
1251 if (err < 0)
1252 goto failed;
1253
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001254 err = update_eir(hdev);
1255 if (err < 0)
1256 goto failed;
1257
Johan Hedbergaee9b2182012-02-18 15:07:59 +02001258 err = cmd_complete(sk, index, MGMT_OP_ADD_UUID, 0, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001259
1260failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001261 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001262 hci_dev_put(hdev);
1263
1264 return err;
1265}
1266
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001267static int remove_uuid(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001268{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001269 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001270 struct list_head *p, *n;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001271 struct hci_dev *hdev;
1272 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 +02001273 int err, found;
1274
Szymon Janc4e51eae2011-02-25 19:05:48 +01001275 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001276
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001277 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001278 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
1279 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001280
Szymon Janc4e51eae2011-02-25 19:05:48 +01001281 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001282 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001283 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
1284 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001285
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001286 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001287
1288 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
1289 err = hci_uuids_clear(hdev);
1290 goto unlock;
1291 }
1292
1293 found = 0;
1294
1295 list_for_each_safe(p, n, &hdev->uuids) {
1296 struct bt_uuid *match = list_entry(p, struct bt_uuid, list);
1297
1298 if (memcmp(match->uuid, cp->uuid, 16) != 0)
1299 continue;
1300
1301 list_del(&match->list);
1302 found++;
1303 }
1304
1305 if (found == 0) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001306 err = cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
1307 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001308 goto unlock;
1309 }
1310
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001311 err = update_class(hdev);
1312 if (err < 0)
1313 goto unlock;
1314
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001315 err = update_eir(hdev);
1316 if (err < 0)
1317 goto unlock;
1318
Johan Hedbergaee9b2182012-02-18 15:07:59 +02001319 err = cmd_complete(sk, index, MGMT_OP_REMOVE_UUID, 0, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001320
1321unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001322 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001323 hci_dev_put(hdev);
1324
1325 return err;
1326}
1327
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001328static int set_dev_class(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001329{
1330 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001331 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001332 int err;
1333
Szymon Janc4e51eae2011-02-25 19:05:48 +01001334 BT_DBG("request for hci%u", index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001335
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001336 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001337 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS,
1338 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001339
Szymon Janc4e51eae2011-02-25 19:05:48 +01001340 hdev = hci_dev_get(index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001341 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001342 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS,
1343 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001344
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001345 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001346
Johan Hedbergb5235a62012-02-21 14:32:24 +02001347 if (!hdev_is_powered(hdev)) {
1348 err = cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS,
1349 MGMT_STATUS_NOT_POWERED);
1350 goto unlock;
1351 }
1352
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001353 hdev->major_class = cp->major;
1354 hdev->minor_class = cp->minor;
1355
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001356 if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02001357 hci_dev_unlock(hdev);
1358 cancel_delayed_work_sync(&hdev->service_cache);
1359 hci_dev_lock(hdev);
Johan Hedberg14c0b602011-12-15 00:47:37 +02001360 update_eir(hdev);
Johan Hedberg7d785252011-12-15 00:47:39 +02001361 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02001362
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001363 err = update_class(hdev);
1364
1365 if (err == 0)
Johan Hedbergaee9b2182012-02-18 15:07:59 +02001366 err = cmd_complete(sk, index, MGMT_OP_SET_DEV_CLASS, 0,
1367 NULL, 0);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001368
Johan Hedbergb5235a62012-02-21 14:32:24 +02001369unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001370 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001371 hci_dev_put(hdev);
1372
1373 return err;
1374}
1375
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001376static int load_link_keys(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001377{
1378 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001379 struct mgmt_cp_load_link_keys *cp = data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001380 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001381 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001382
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001383 if (len < sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001384 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1385 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001386
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001387 key_count = get_unaligned_le16(&cp->key_count);
1388
Johan Hedberg86742e12011-11-07 23:13:38 +02001389 expected_len = sizeof(*cp) + key_count *
1390 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001391 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001392 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001393 len, expected_len);
Johan Hedbergca69b792011-11-11 18:10:00 +02001394 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1395 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001396 }
1397
Szymon Janc4e51eae2011-02-25 19:05:48 +01001398 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001399 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001400 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1401 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001402
Szymon Janc4e51eae2011-02-25 19:05:48 +01001403 BT_DBG("hci%u debug_keys %u key_count %u", index, cp->debug_keys,
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001404 key_count);
1405
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001406 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001407
1408 hci_link_keys_clear(hdev);
1409
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001410 set_bit(HCI_LINK_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001411
1412 if (cp->debug_keys)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001413 set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001414 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001415 clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001416
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001417 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001418 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001419
Johan Hedbergd753fdc2012-02-17 14:06:34 +02001420 hci_add_link_key(hdev, NULL, 0, &key->addr.bdaddr, key->val,
1421 key->type, key->pin_len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001422 }
1423
Johan Hedbergaee9b2182012-02-18 15:07:59 +02001424 cmd_complete(sk, index, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02001425
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001426 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001427 hci_dev_put(hdev);
1428
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001429 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001430}
1431
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001432static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
1433 u8 addr_type, struct sock *skip_sk)
1434{
1435 struct mgmt_ev_device_unpaired ev;
1436
1437 bacpy(&ev.addr.bdaddr, bdaddr);
1438 ev.addr.type = addr_type;
1439
1440 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
1441 skip_sk);
1442}
1443
Johan Hedberg124f6e32012-02-09 13:50:12 +02001444static int unpair_device(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001445{
1446 struct hci_dev *hdev;
Johan Hedberg124f6e32012-02-09 13:50:12 +02001447 struct mgmt_cp_unpair_device *cp = data;
1448 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001449 struct hci_cp_disconnect dc;
1450 struct pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001451 struct hci_conn *conn;
Johan Hedbergaee9b2182012-02-18 15:07:59 +02001452 u8 status = 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001453 int err;
1454
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001455 if (len != sizeof(*cp))
Johan Hedberg124f6e32012-02-09 13:50:12 +02001456 return cmd_status(sk, index, MGMT_OP_UNPAIR_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02001457 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001458
Szymon Janc4e51eae2011-02-25 19:05:48 +01001459 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001460 if (!hdev)
Johan Hedberg124f6e32012-02-09 13:50:12 +02001461 return cmd_status(sk, index, MGMT_OP_UNPAIR_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02001462 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001463
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001464 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001465
Johan Hedberga8a1d192011-11-10 15:54:38 +02001466 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02001467 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1468 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001469
Johan Hedberg124f6e32012-02-09 13:50:12 +02001470 if (cp->addr.type == MGMT_ADDR_BREDR)
1471 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
1472 else
1473 err = hci_remove_ltk(hdev, &cp->addr.bdaddr);
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03001474
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001475 if (err < 0) {
Johan Hedbergaee9b2182012-02-18 15:07:59 +02001476 status = MGMT_STATUS_NOT_PAIRED;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001477 goto unlock;
1478 }
1479
Johan Hedberga8a1d192011-11-10 15:54:38 +02001480 if (!test_bit(HCI_UP, &hdev->flags) || !cp->disconnect) {
Johan Hedbergaee9b2182012-02-18 15:07:59 +02001481 err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE, status,
1482 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001483 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001484 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001485 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001486
Johan Hedberg124f6e32012-02-09 13:50:12 +02001487 if (cp->addr.type == MGMT_ADDR_BREDR)
1488 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
1489 &cp->addr.bdaddr);
1490 else
1491 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
1492 &cp->addr.bdaddr);
1493
Johan Hedberga8a1d192011-11-10 15:54:38 +02001494 if (!conn) {
Johan Hedbergaee9b2182012-02-18 15:07:59 +02001495 err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE, status,
1496 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001497 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001498 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001499 }
1500
Johan Hedberg124f6e32012-02-09 13:50:12 +02001501 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
1502 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02001503 if (!cmd) {
1504 err = -ENOMEM;
1505 goto unlock;
1506 }
1507
1508 put_unaligned_le16(conn->handle, &dc.handle);
1509 dc.reason = 0x13; /* Remote User Terminated Connection */
1510 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1511 if (err < 0)
1512 mgmt_pending_remove(cmd);
1513
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001514unlock:
Johan Hedbergca69b792011-11-11 18:10:00 +02001515 if (err < 0)
Johan Hedbergaee9b2182012-02-18 15:07:59 +02001516 err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE, status,
1517 &rp, sizeof(rp));
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001518 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001519 hci_dev_put(hdev);
1520
1521 return err;
1522}
1523
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001524static int disconnect(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02001525{
1526 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001527 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001528 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03001529 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001530 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001531 int err;
1532
1533 BT_DBG("");
1534
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001535 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001536 return cmd_status(sk, index, MGMT_OP_DISCONNECT,
1537 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001538
Szymon Janc4e51eae2011-02-25 19:05:48 +01001539 hdev = hci_dev_get(index);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001540 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001541 return cmd_status(sk, index, MGMT_OP_DISCONNECT,
1542 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001543
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001544 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001545
1546 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001547 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1548 MGMT_STATUS_NOT_POWERED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001549 goto failed;
1550 }
1551
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001552 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001553 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1554 MGMT_STATUS_BUSY);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001555 goto failed;
1556 }
1557
Johan Hedberg88c3df12012-02-09 14:27:38 +02001558 if (cp->addr.type == MGMT_ADDR_BREDR)
1559 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
1560 else
1561 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03001562
Johan Hedberg8962ee72011-01-20 12:40:27 +02001563 if (!conn) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001564 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1565 MGMT_STATUS_NOT_CONNECTED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001566 goto failed;
1567 }
1568
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001569 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001570 if (!cmd) {
1571 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001572 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001573 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001574
1575 put_unaligned_le16(conn->handle, &dc.handle);
1576 dc.reason = 0x13; /* Remote User Terminated Connection */
1577
1578 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1579 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001580 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001581
1582failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001583 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001584 hci_dev_put(hdev);
1585
1586 return err;
1587}
1588
Johan Hedberg48264f02011-11-09 13:58:58 +02001589static u8 link_to_mgmt(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02001590{
1591 switch (link_type) {
1592 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02001593 switch (addr_type) {
1594 case ADDR_LE_DEV_PUBLIC:
1595 return MGMT_ADDR_LE_PUBLIC;
1596 case ADDR_LE_DEV_RANDOM:
1597 return MGMT_ADDR_LE_RANDOM;
1598 default:
1599 return MGMT_ADDR_INVALID;
1600 }
Johan Hedberg4c659c32011-11-07 23:13:39 +02001601 case ACL_LINK:
1602 return MGMT_ADDR_BREDR;
1603 default:
1604 return MGMT_ADDR_INVALID;
1605 }
1606}
1607
Szymon Janc8ce62842011-03-01 16:55:32 +01001608static int get_connections(struct sock *sk, u16 index)
Johan Hedberg2784eb42011-01-21 13:56:35 +02001609{
Johan Hedberg2784eb42011-01-21 13:56:35 +02001610 struct mgmt_rp_get_connections *rp;
1611 struct hci_dev *hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001612 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02001613 size_t rp_len;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001614 u16 count;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001615 int i, err;
1616
1617 BT_DBG("");
1618
Szymon Janc4e51eae2011-02-25 19:05:48 +01001619 hdev = hci_dev_get(index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001620 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001621 return cmd_status(sk, index, MGMT_OP_GET_CONNECTIONS,
1622 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001623
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001624 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001625
1626 count = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02001627 list_for_each_entry(c, &hdev->conn_hash.list, list) {
1628 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
1629 count++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001630 }
1631
Johan Hedberg4c659c32011-11-07 23:13:39 +02001632 rp_len = sizeof(*rp) + (count * sizeof(struct mgmt_addr_info));
Johan Hedberga38528f2011-01-22 06:46:43 +02001633 rp = kmalloc(rp_len, GFP_ATOMIC);
1634 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02001635 err = -ENOMEM;
1636 goto unlock;
1637 }
1638
Johan Hedberg2784eb42011-01-21 13:56:35 +02001639 put_unaligned_le16(count, &rp->conn_count);
1640
Johan Hedberg2784eb42011-01-21 13:56:35 +02001641 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001642 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02001643 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
1644 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001645 bacpy(&rp->addr[i].bdaddr, &c->dst);
Johan Hedberg48264f02011-11-09 13:58:58 +02001646 rp->addr[i].type = link_to_mgmt(c->type, c->dst_type);
Johan Hedberg4c659c32011-11-07 23:13:39 +02001647 if (rp->addr[i].type == MGMT_ADDR_INVALID)
1648 continue;
1649 i++;
1650 }
1651
1652 /* Recalculate length in case of filtered SCO connections, etc */
1653 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02001654
Johan Hedbergaee9b2182012-02-18 15:07:59 +02001655 err = cmd_complete(sk, index, MGMT_OP_GET_CONNECTIONS, 0, rp, rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001656
1657unlock:
Johan Hedberga38528f2011-01-22 06:46:43 +02001658 kfree(rp);
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001659 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001660 hci_dev_put(hdev);
1661 return err;
1662}
1663
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001664static int send_pin_code_neg_reply(struct sock *sk, u16 index,
1665 struct hci_dev *hdev, struct mgmt_cp_pin_code_neg_reply *cp)
1666{
1667 struct pending_cmd *cmd;
1668 int err;
1669
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001670 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001671 sizeof(*cp));
1672 if (!cmd)
1673 return -ENOMEM;
1674
Johan Hedbergd8457692012-02-17 14:24:57 +02001675 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
1676 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001677 if (err < 0)
1678 mgmt_pending_remove(cmd);
1679
1680 return err;
1681}
1682
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001683static int pin_code_reply(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001684{
1685 struct hci_dev *hdev;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001686 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001687 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001688 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03001689 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001690 int err;
1691
1692 BT_DBG("");
1693
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001694 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001695 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1696 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001697
Szymon Janc4e51eae2011-02-25 19:05:48 +01001698 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001699 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001700 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1701 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001702
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001703 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001704
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001705 if (!hdev_is_powered(hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001706 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1707 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001708 goto failed;
1709 }
1710
Johan Hedbergd8457692012-02-17 14:24:57 +02001711 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001712 if (!conn) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001713 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1714 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001715 goto failed;
1716 }
1717
1718 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02001719 struct mgmt_cp_pin_code_neg_reply ncp;
1720
1721 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001722
1723 BT_ERR("PIN code is not 16 bytes long");
1724
1725 err = send_pin_code_neg_reply(sk, index, hdev, &ncp);
1726 if (err >= 0)
1727 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001728 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001729
1730 goto failed;
1731 }
1732
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001733 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data,
1734 len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001735 if (!cmd) {
1736 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001737 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001738 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02001739
Johan Hedbergd8457692012-02-17 14:24:57 +02001740 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001741 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02001742 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02001743
1744 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
1745 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001746 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001747
1748failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001749 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001750 hci_dev_put(hdev);
1751
1752 return err;
1753}
1754
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001755static int pin_code_neg_reply(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001756{
1757 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001758 struct mgmt_cp_pin_code_neg_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001759 int err;
1760
1761 BT_DBG("");
1762
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001763 if (len != sizeof(*cp))
1764 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001765 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001766
Szymon Janc4e51eae2011-02-25 19:05:48 +01001767 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001768 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001769 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001770 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001771
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001772 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001773
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001774 if (!hdev_is_powered(hdev)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001775 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001776 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001777 goto failed;
1778 }
1779
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001780 err = send_pin_code_neg_reply(sk, index, hdev, cp);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001781
1782failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001783 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001784 hci_dev_put(hdev);
1785
1786 return err;
1787}
1788
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001789static int set_io_capability(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001790{
1791 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001792 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001793
1794 BT_DBG("");
1795
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001796 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001797 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY,
1798 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001799
Szymon Janc4e51eae2011-02-25 19:05:48 +01001800 hdev = hci_dev_get(index);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001801 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001802 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY,
1803 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001804
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001805 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001806
1807 hdev->io_capability = cp->io_capability;
1808
1809 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Szymon Jancb8534e02011-03-01 16:55:34 +01001810 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001811
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001812 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001813 hci_dev_put(hdev);
1814
Johan Hedbergaee9b2182012-02-18 15:07:59 +02001815 return cmd_complete(sk, index, MGMT_OP_SET_IO_CAPABILITY, 0, NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001816}
1817
Johan Hedberge9a416b2011-02-19 12:05:56 -03001818static inline struct pending_cmd *find_pairing(struct hci_conn *conn)
1819{
1820 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001821 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001822
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001823 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03001824 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
1825 continue;
1826
Johan Hedberge9a416b2011-02-19 12:05:56 -03001827 if (cmd->user_data != conn)
1828 continue;
1829
1830 return cmd;
1831 }
1832
1833 return NULL;
1834}
1835
1836static void pairing_complete(struct pending_cmd *cmd, u8 status)
1837{
1838 struct mgmt_rp_pair_device rp;
1839 struct hci_conn *conn = cmd->user_data;
1840
Johan Hedbergba4e5642011-11-11 00:07:34 +02001841 bacpy(&rp.addr.bdaddr, &conn->dst);
1842 rp.addr.type = link_to_mgmt(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001843
Johan Hedbergaee9b2182012-02-18 15:07:59 +02001844 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, status,
1845 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001846
1847 /* So we don't get further callbacks for this connection */
1848 conn->connect_cfm_cb = NULL;
1849 conn->security_cfm_cb = NULL;
1850 conn->disconn_cfm_cb = NULL;
1851
1852 hci_conn_put(conn);
1853
Johan Hedberga664b5b2011-02-19 12:06:02 -03001854 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001855}
1856
1857static void pairing_complete_cb(struct hci_conn *conn, u8 status)
1858{
1859 struct pending_cmd *cmd;
1860
1861 BT_DBG("status %u", status);
1862
Johan Hedberg56e5cb82011-11-08 20:40:16 +02001863 cmd = find_pairing(conn);
1864 if (!cmd)
1865 BT_DBG("Unable to find a pending command");
1866 else
Johan Hedberge2113262012-02-18 15:20:03 +02001867 pairing_complete(cmd, mgmt_status(status));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001868}
1869
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001870static int pair_device(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001871{
1872 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001873 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02001874 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001875 struct pending_cmd *cmd;
1876 u8 sec_level, auth_type;
1877 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001878 int err;
1879
1880 BT_DBG("");
1881
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001882 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001883 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE,
1884 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001885
Szymon Janc4e51eae2011-02-25 19:05:48 +01001886 hdev = hci_dev_get(index);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001887 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001888 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE,
1889 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001890
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001891 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001892
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001893 sec_level = BT_SECURITY_MEDIUM;
1894 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001895 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001896 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03001897 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001898
Johan Hedbergba4e5642011-11-11 00:07:34 +02001899 if (cp->addr.type == MGMT_ADDR_BREDR)
1900 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr, sec_level,
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001901 auth_type);
1902 else
Johan Hedbergba4e5642011-11-11 00:07:34 +02001903 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr, sec_level,
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001904 auth_type);
1905
Johan Hedberg1425acb2011-11-11 00:07:35 +02001906 memset(&rp, 0, sizeof(rp));
1907 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1908 rp.addr.type = cp->addr.type;
1909
Ville Tervo30e76272011-02-22 16:10:53 -03001910 if (IS_ERR(conn)) {
Johan Hedberge2113262012-02-18 15:20:03 +02001911 err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE,
1912 MGMT_STATUS_CONNECT_FAILED,
1913 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001914 goto unlock;
1915 }
1916
1917 if (conn->connect_cfm_cb) {
1918 hci_conn_put(conn);
Johan Hedberge2113262012-02-18 15:20:03 +02001919 err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE,
1920 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001921 goto unlock;
1922 }
1923
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001924 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001925 if (!cmd) {
1926 err = -ENOMEM;
1927 hci_conn_put(conn);
1928 goto unlock;
1929 }
1930
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001931 /* For LE, just connecting isn't a proof that the pairing finished */
Johan Hedbergba4e5642011-11-11 00:07:34 +02001932 if (cp->addr.type == MGMT_ADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001933 conn->connect_cfm_cb = pairing_complete_cb;
1934
Johan Hedberge9a416b2011-02-19 12:05:56 -03001935 conn->security_cfm_cb = pairing_complete_cb;
1936 conn->disconn_cfm_cb = pairing_complete_cb;
1937 conn->io_capability = cp->io_cap;
1938 cmd->user_data = conn;
1939
1940 if (conn->state == BT_CONNECTED &&
1941 hci_conn_security(conn, sec_level, auth_type))
1942 pairing_complete(cmd, 0);
1943
1944 err = 0;
1945
1946unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001947 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001948 hci_dev_put(hdev);
1949
1950 return err;
1951}
1952
Johan Hedberg28424702012-02-02 04:02:29 +02001953static int cancel_pair_device(struct sock *sk, u16 index,
1954 unsigned char *data, u16 len)
1955{
1956 struct mgmt_addr_info *addr = (void *) data;
1957 struct hci_dev *hdev;
1958 struct pending_cmd *cmd;
1959 struct hci_conn *conn;
1960 int err;
1961
1962 BT_DBG("");
1963
1964 if (len != sizeof(*addr))
1965 return cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
1966 MGMT_STATUS_INVALID_PARAMS);
1967
1968 hdev = hci_dev_get(index);
1969 if (!hdev)
1970 return cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
1971 MGMT_STATUS_INVALID_PARAMS);
1972
1973 hci_dev_lock(hdev);
1974
1975 cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
1976 if (!cmd) {
1977 err = cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
1978 MGMT_STATUS_INVALID_PARAMS);
1979 goto unlock;
1980 }
1981
1982 conn = cmd->user_data;
1983
1984 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
1985 err = cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
1986 MGMT_STATUS_INVALID_PARAMS);
1987 goto unlock;
1988 }
1989
1990 pairing_complete(cmd, MGMT_STATUS_CANCELLED);
1991
Johan Hedbergaee9b2182012-02-18 15:07:59 +02001992 err = cmd_complete(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE, 0, addr,
Johan Hedberg28424702012-02-02 04:02:29 +02001993 sizeof(*addr));
1994unlock:
1995 hci_dev_unlock(hdev);
1996 hci_dev_put(hdev);
1997
1998 return err;
1999}
2000
Brian Gix0df4c182011-11-16 13:53:13 -08002001static int user_pairing_resp(struct sock *sk, u16 index, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02002002 u8 type, u16 mgmt_op, u16 hci_op,
2003 __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03002004{
Johan Hedberga5c29682011-02-19 12:05:57 -03002005 struct pending_cmd *cmd;
2006 struct hci_dev *hdev;
Brian Gix0df4c182011-11-16 13:53:13 -08002007 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03002008 int err;
2009
Szymon Janc4e51eae2011-02-25 19:05:48 +01002010 hdev = hci_dev_get(index);
Johan Hedberga5c29682011-02-19 12:05:57 -03002011 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002012 return cmd_status(sk, index, mgmt_op,
2013 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga5c29682011-02-19 12:05:57 -03002014
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002015 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02002016
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002017 if (!hdev_is_powered(hdev)) {
Brian Gix0df4c182011-11-16 13:53:13 -08002018 err = cmd_status(sk, index, mgmt_op, MGMT_STATUS_NOT_POWERED);
2019 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002020 }
2021
Johan Hedberg272d90d2012-02-09 15:26:12 +02002022 if (type == MGMT_ADDR_BREDR)
2023 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, bdaddr);
2024 else
Brian Gix47c15e22011-11-16 13:53:14 -08002025 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, bdaddr);
Brian Gix47c15e22011-11-16 13:53:14 -08002026
Johan Hedberg272d90d2012-02-09 15:26:12 +02002027 if (!conn) {
2028 err = cmd_status(sk, index, mgmt_op,
2029 MGMT_STATUS_NOT_CONNECTED);
2030 goto done;
2031 }
2032
2033 if (type == MGMT_ADDR_LE_PUBLIC || type == MGMT_ADDR_LE_RANDOM) {
Brian Gix47c15e22011-11-16 13:53:14 -08002034 /* Continue with pairing via SMP */
Brian Gix5fe57d92011-12-21 16:12:13 -08002035 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix47c15e22011-11-16 13:53:14 -08002036
Brian Gix5fe57d92011-12-21 16:12:13 -08002037 if (!err)
2038 err = cmd_status(sk, index, mgmt_op,
2039 MGMT_STATUS_SUCCESS);
2040 else
2041 err = cmd_status(sk, index, mgmt_op,
2042 MGMT_STATUS_FAILED);
2043
Brian Gix47c15e22011-11-16 13:53:14 -08002044 goto done;
2045 }
2046
Brian Gix0df4c182011-11-16 13:53:13 -08002047 cmd = mgmt_pending_add(sk, mgmt_op, hdev, bdaddr, sizeof(*bdaddr));
Johan Hedberga5c29682011-02-19 12:05:57 -03002048 if (!cmd) {
2049 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08002050 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002051 }
2052
Brian Gix0df4c182011-11-16 13:53:13 -08002053 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08002054 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
2055 struct hci_cp_user_passkey_reply cp;
2056
2057 bacpy(&cp.bdaddr, bdaddr);
2058 cp.passkey = passkey;
2059 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
2060 } else
2061 err = hci_send_cmd(hdev, hci_op, sizeof(*bdaddr), bdaddr);
2062
Johan Hedberga664b5b2011-02-19 12:06:02 -03002063 if (err < 0)
2064 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002065
Brian Gix0df4c182011-11-16 13:53:13 -08002066done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002067 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002068 hci_dev_put(hdev);
2069
2070 return err;
2071}
2072
Brian Gix0df4c182011-11-16 13:53:13 -08002073static int user_confirm_reply(struct sock *sk, u16 index, void *data, u16 len)
2074{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002075 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002076
2077 BT_DBG("");
2078
2079 if (len != sizeof(*cp))
2080 return cmd_status(sk, index, MGMT_OP_USER_CONFIRM_REPLY,
2081 MGMT_STATUS_INVALID_PARAMS);
2082
Johan Hedberg272d90d2012-02-09 15:26:12 +02002083 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
2084 MGMT_OP_USER_CONFIRM_REPLY,
2085 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002086}
2087
2088static int user_confirm_neg_reply(struct sock *sk, u16 index, void *data,
2089 u16 len)
2090{
Johan Hedbergc9c26592011-12-15 00:47:41 +02002091 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002092
2093 BT_DBG("");
2094
2095 if (len != sizeof(*cp))
2096 return cmd_status(sk, index, MGMT_OP_USER_CONFIRM_NEG_REPLY,
2097 MGMT_STATUS_INVALID_PARAMS);
2098
Johan Hedberg272d90d2012-02-09 15:26:12 +02002099 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
2100 MGMT_OP_USER_CONFIRM_NEG_REPLY,
2101 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002102}
2103
Brian Gix604086b2011-11-23 08:28:33 -08002104static int user_passkey_reply(struct sock *sk, u16 index, void *data, u16 len)
2105{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002106 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002107
2108 BT_DBG("");
2109
2110 if (len != sizeof(*cp))
2111 return cmd_status(sk, index, MGMT_OP_USER_PASSKEY_REPLY,
2112 EINVAL);
2113
Johan Hedberg272d90d2012-02-09 15:26:12 +02002114 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
2115 MGMT_OP_USER_PASSKEY_REPLY,
2116 HCI_OP_USER_PASSKEY_REPLY,
2117 cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08002118}
2119
2120static int user_passkey_neg_reply(struct sock *sk, u16 index, void *data,
2121 u16 len)
2122{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002123 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002124
2125 BT_DBG("");
2126
2127 if (len != sizeof(*cp))
2128 return cmd_status(sk, index, MGMT_OP_USER_PASSKEY_NEG_REPLY,
2129 EINVAL);
2130
Johan Hedberg272d90d2012-02-09 15:26:12 +02002131 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
2132 MGMT_OP_USER_PASSKEY_NEG_REPLY,
2133 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08002134}
2135
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002136static int set_local_name(struct sock *sk, u16 index, void *data,
Johan Hedbergb312b1612011-03-16 14:29:37 +02002137 u16 len)
2138{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002139 struct mgmt_cp_set_local_name *mgmt_cp = data;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002140 struct hci_cp_write_local_name hci_cp;
2141 struct hci_dev *hdev;
2142 struct pending_cmd *cmd;
2143 int err;
2144
2145 BT_DBG("");
2146
2147 if (len != sizeof(*mgmt_cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02002148 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME,
2149 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002150
2151 hdev = hci_dev_get(index);
2152 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002153 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME,
2154 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002155
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002156 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002157
Johan Hedbergb5235a62012-02-21 14:32:24 +02002158 if (!hdev_is_powered(hdev)) {
2159 err = cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME,
2160 MGMT_STATUS_NOT_POWERED);
2161 goto failed;
2162 }
2163
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002164 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data,
2165 len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002166 if (!cmd) {
2167 err = -ENOMEM;
2168 goto failed;
2169 }
2170
2171 memcpy(hci_cp.name, mgmt_cp->name, sizeof(hci_cp.name));
2172 err = hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(hci_cp),
2173 &hci_cp);
2174 if (err < 0)
2175 mgmt_pending_remove(cmd);
2176
2177failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002178 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002179 hci_dev_put(hdev);
2180
2181 return err;
2182}
2183
Szymon Jancc35938b2011-03-22 13:12:21 +01002184static int read_local_oob_data(struct sock *sk, u16 index)
2185{
2186 struct hci_dev *hdev;
2187 struct pending_cmd *cmd;
2188 int err;
2189
2190 BT_DBG("hci%u", index);
2191
2192 hdev = hci_dev_get(index);
2193 if (!hdev)
2194 return cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002195 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancc35938b2011-03-22 13:12:21 +01002196
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002197 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002198
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002199 if (!hdev_is_powered(hdev)) {
Szymon Jancc35938b2011-03-22 13:12:21 +01002200 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002201 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002202 goto unlock;
2203 }
2204
2205 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
2206 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002207 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002208 goto unlock;
2209 }
2210
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002211 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02002212 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2213 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01002214 goto unlock;
2215 }
2216
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002217 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01002218 if (!cmd) {
2219 err = -ENOMEM;
2220 goto unlock;
2221 }
2222
2223 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
2224 if (err < 0)
2225 mgmt_pending_remove(cmd);
2226
2227unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002228 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002229 hci_dev_put(hdev);
2230
2231 return err;
2232}
2233
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002234static int add_remote_oob_data(struct sock *sk, u16 index, void *data,
2235 u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002236{
2237 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002238 struct mgmt_cp_add_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002239 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002240 int err;
2241
2242 BT_DBG("hci%u ", index);
2243
2244 if (len != sizeof(*cp))
2245 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002246 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01002247
2248 hdev = hci_dev_get(index);
2249 if (!hdev)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002250 return cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
2251 MGMT_STATUS_INVALID_PARAMS,
2252 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002253
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002254 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002255
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002256 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, cp->hash,
Szymon Janc2763eda2011-03-22 13:12:22 +01002257 cp->randomizer);
2258 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002259 status = MGMT_STATUS_FAILED;
Szymon Janc2763eda2011-03-22 13:12:22 +01002260 else
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002261 status = 0;
2262
2263 err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, status,
2264 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002265
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002266 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002267 hci_dev_put(hdev);
2268
2269 return err;
2270}
2271
2272static int remove_remote_oob_data(struct sock *sk, u16 index,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002273 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002274{
2275 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002276 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002277 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002278 int err;
2279
2280 BT_DBG("hci%u ", index);
2281
2282 if (len != sizeof(*cp))
2283 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002284 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01002285
2286 hdev = hci_dev_get(index);
2287 if (!hdev)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002288 return cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2289 MGMT_STATUS_INVALID_PARAMS,
2290 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002291
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002292 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002293
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002294 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr);
Szymon Janc2763eda2011-03-22 13:12:22 +01002295 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002296 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01002297 else
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002298 status = 0;
2299
2300 err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA, status,
2301 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002302
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002303 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002304 hci_dev_put(hdev);
2305
2306 return err;
2307}
2308
Andre Guedes5e0452c2012-02-17 20:39:38 -03002309static int discovery(struct hci_dev *hdev)
2310{
2311 int err;
2312
2313 if (lmp_host_le_capable(hdev)) {
2314 if (lmp_bredr_capable(hdev)) {
2315 err = hci_le_scan(hdev, LE_SCAN_TYPE,
2316 LE_SCAN_INT, LE_SCAN_WIN,
2317 LE_SCAN_TIMEOUT_BREDR_LE);
2318 } else {
2319 hdev->discovery.type = DISCOV_TYPE_LE;
2320 err = hci_le_scan(hdev, LE_SCAN_TYPE,
2321 LE_SCAN_INT, LE_SCAN_WIN,
2322 LE_SCAN_TIMEOUT_LE_ONLY);
2323 }
2324 } else {
2325 hdev->discovery.type = DISCOV_TYPE_BREDR;
2326 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
2327 }
2328
2329 return err;
2330}
2331
2332int mgmt_interleaved_discovery(struct hci_dev *hdev)
2333{
2334 int err;
2335
2336 BT_DBG("%s", hdev->name);
2337
2338 hci_dev_lock(hdev);
2339
2340 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR_LE);
2341 if (err < 0)
2342 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2343
2344 hci_dev_unlock(hdev);
2345
2346 return err;
2347}
2348
Johan Hedberg450dfda2011-11-12 11:58:22 +02002349static int start_discovery(struct sock *sk, u16 index,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002350 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002351{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002352 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002353 struct pending_cmd *cmd;
2354 struct hci_dev *hdev;
2355 int err;
2356
2357 BT_DBG("hci%u", index);
2358
Johan Hedberg450dfda2011-11-12 11:58:22 +02002359 if (len != sizeof(*cp))
2360 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2361 MGMT_STATUS_INVALID_PARAMS);
2362
Johan Hedberg14a53662011-04-27 10:29:56 -04002363 hdev = hci_dev_get(index);
2364 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002365 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2366 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg14a53662011-04-27 10:29:56 -04002367
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002368 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002369
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002370 if (!hdev_is_powered(hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02002371 err = cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2372 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02002373 goto failed;
2374 }
2375
Johan Hedbergff9ef572012-01-04 14:23:45 +02002376 if (hdev->discovery.state != DISCOVERY_STOPPED) {
2377 err = cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2378 MGMT_STATUS_BUSY);
2379 goto failed;
2380 }
2381
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002382 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002383 if (!cmd) {
2384 err = -ENOMEM;
2385 goto failed;
2386 }
2387
Andre Guedes4aab14e2012-02-17 20:39:36 -03002388 hdev->discovery.type = cp->type;
2389
2390 switch (hdev->discovery.type) {
Andre Guedesf39799f2012-02-17 20:39:35 -03002391 case DISCOV_TYPE_BREDR:
Andre Guedes3fd24152012-02-03 17:48:01 -03002392 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
Andre Guedesf39799f2012-02-17 20:39:35 -03002393 break;
2394
2395 case DISCOV_TYPE_LE:
Andre Guedes3fd24152012-02-03 17:48:01 -03002396 err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT,
2397 LE_SCAN_WIN, LE_SCAN_TIMEOUT_LE_ONLY);
Andre Guedesf39799f2012-02-17 20:39:35 -03002398 break;
2399
Andre Guedes5e0452c2012-02-17 20:39:38 -03002400 case DISCOV_TYPE_INTERLEAVED:
2401 err = discovery(hdev);
2402 break;
2403
Andre Guedesf39799f2012-02-17 20:39:35 -03002404 default:
Andre Guedes3fd24152012-02-03 17:48:01 -03002405 err = -EINVAL;
Andre Guedesf39799f2012-02-17 20:39:35 -03002406 }
Andre Guedes3fd24152012-02-03 17:48:01 -03002407
Johan Hedberg14a53662011-04-27 10:29:56 -04002408 if (err < 0)
2409 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002410 else
2411 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002412
2413failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002414 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002415 hci_dev_put(hdev);
2416
2417 return err;
2418}
2419
Johan Hedbergd9306502012-02-20 23:25:18 +02002420static int stop_discovery(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002421{
Johan Hedbergd9306502012-02-20 23:25:18 +02002422 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002423 struct hci_dev *hdev;
2424 struct pending_cmd *cmd;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002425 struct hci_cp_remote_name_req_cancel cp;
2426 struct inquiry_entry *e;
Johan Hedberg14a53662011-04-27 10:29:56 -04002427 int err;
2428
2429 BT_DBG("hci%u", index);
2430
Johan Hedbergd9306502012-02-20 23:25:18 +02002431 if (len != sizeof(*mgmt_cp))
2432 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY,
2433 MGMT_STATUS_INVALID_PARAMS);
2434
Johan Hedberg14a53662011-04-27 10:29:56 -04002435 hdev = hci_dev_get(index);
2436 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002437 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY,
2438 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg14a53662011-04-27 10:29:56 -04002439
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002440 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002441
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002442 if (!hci_discovery_active(hdev)) {
Johan Hedbergd9306502012-02-20 23:25:18 +02002443 err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY,
2444 MGMT_STATUS_REJECTED,
2445 &mgmt_cp->type, sizeof(mgmt_cp->type));
2446 goto unlock;
2447 }
2448
2449 if (hdev->discovery.type != mgmt_cp->type) {
2450 err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY,
2451 MGMT_STATUS_INVALID_PARAMS,
2452 &mgmt_cp->type, sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002453 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02002454 }
2455
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002456 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002457 if (!cmd) {
2458 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002459 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04002460 }
2461
Andre Guedes343f9352012-02-17 20:39:37 -03002462 if (hdev->discovery.state == DISCOVERY_FINDING) {
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002463 err = hci_cancel_inquiry(hdev);
2464 if (err < 0)
2465 mgmt_pending_remove(cmd);
2466 else
2467 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
2468 goto unlock;
2469 }
2470
2471 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY, NAME_PENDING);
2472 if (!e) {
2473 mgmt_pending_remove(cmd);
Johan Hedbergaee9b2182012-02-18 15:07:59 +02002474 err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY, 0,
Johan Hedbergd9306502012-02-20 23:25:18 +02002475 &mgmt_cp->type, sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002476 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2477 goto unlock;
2478 }
2479
2480 bacpy(&cp.bdaddr, &e->data.bdaddr);
2481 err = hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ_CANCEL,
2482 sizeof(cp), &cp);
Johan Hedberg14a53662011-04-27 10:29:56 -04002483 if (err < 0)
2484 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002485 else
2486 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002487
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002488unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002489 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002490 hci_dev_put(hdev);
2491
2492 return err;
2493}
2494
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002495static int confirm_name(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02002496{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002497 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002498 struct inquiry_entry *e;
2499 struct hci_dev *hdev;
2500 int err;
2501
2502 BT_DBG("hci%u", index);
2503
2504 if (len != sizeof(*cp))
2505 return cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2506 MGMT_STATUS_INVALID_PARAMS);
2507
2508 hdev = hci_dev_get(index);
2509 if (!hdev)
2510 return cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2511 MGMT_STATUS_INVALID_PARAMS);
2512
2513 hci_dev_lock(hdev);
2514
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002515 if (!hci_discovery_active(hdev)) {
2516 err = cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2517 MGMT_STATUS_FAILED);
2518 goto failed;
2519 }
2520
Johan Hedberga198e7b2012-02-17 14:27:06 +02002521 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002522 if (!e) {
2523 err = cmd_status (sk, index, MGMT_OP_CONFIRM_NAME,
2524 MGMT_STATUS_INVALID_PARAMS);
2525 goto failed;
2526 }
2527
2528 if (cp->name_known) {
2529 e->name_state = NAME_KNOWN;
2530 list_del(&e->list);
2531 } else {
2532 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e202012-01-09 00:53:02 +02002533 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002534 }
2535
2536 err = 0;
2537
2538failed:
2539 hci_dev_unlock(hdev);
2540
2541 return err;
2542}
2543
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002544static int block_device(struct sock *sk, u16 index, void *data, u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002545{
2546 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002547 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002548 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03002549 int err;
2550
2551 BT_DBG("hci%u", index);
2552
Antti Julku7fbec222011-06-15 12:01:15 +03002553 if (len != sizeof(*cp))
2554 return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002555 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002556
2557 hdev = hci_dev_get(index);
2558 if (!hdev)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002559 return cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE,
2560 MGMT_STATUS_INVALID_PARAMS,
2561 &cp->addr, sizeof(cp->addr));
Antti Julku7fbec222011-06-15 12:01:15 +03002562
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002563 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002564
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002565 err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002566 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002567 status = MGMT_STATUS_FAILED;
Antti Julku7fbec222011-06-15 12:01:15 +03002568 else
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002569 status = 0;
2570
2571 err = cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE, status,
2572 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03002573
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002574 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002575 hci_dev_put(hdev);
2576
2577 return err;
2578}
2579
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002580static int unblock_device(struct sock *sk, u16 index, void *data, u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002581{
2582 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002583 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002584 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03002585 int err;
2586
2587 BT_DBG("hci%u", index);
2588
Antti Julku7fbec222011-06-15 12:01:15 +03002589 if (len != sizeof(*cp))
2590 return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002591 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002592
2593 hdev = hci_dev_get(index);
2594 if (!hdev)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002595 return cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE,
2596 MGMT_STATUS_INVALID_PARAMS,
2597 &cp->addr, sizeof(cp->addr));
Antti Julku7fbec222011-06-15 12:01:15 +03002598
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002599 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002600
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002601 err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002602 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002603 status = MGMT_STATUS_INVALID_PARAMS;
Antti Julku7fbec222011-06-15 12:01:15 +03002604 else
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002605 status = 0;
2606
2607 err = cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE, status,
2608 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03002609
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002610 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002611 hci_dev_put(hdev);
2612
2613 return err;
2614}
2615
Antti Julkuf6422ec2011-06-22 13:11:56 +03002616static int set_fast_connectable(struct sock *sk, u16 index,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002617 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03002618{
2619 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002620 struct mgmt_mode *cp = data;
Antti Julkuf6422ec2011-06-22 13:11:56 +03002621 struct hci_cp_write_page_scan_activity acp;
2622 u8 type;
2623 int err;
2624
2625 BT_DBG("hci%u", index);
2626
2627 if (len != sizeof(*cp))
2628 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002629 MGMT_STATUS_INVALID_PARAMS);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002630
2631 hdev = hci_dev_get(index);
2632 if (!hdev)
2633 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002634 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg5400c042012-02-21 16:40:33 +02002635 if (!hdev_is_powered(hdev))
2636 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
2637 MGMT_STATUS_NOT_POWERED);
2638
2639 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
2640 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
2641 MGMT_STATUS_REJECTED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002642
2643 hci_dev_lock(hdev);
2644
Johan Hedbergf7c68692011-12-15 00:47:36 +02002645 if (cp->val) {
Antti Julkuf6422ec2011-06-22 13:11:56 +03002646 type = PAGE_SCAN_TYPE_INTERLACED;
2647 acp.interval = 0x0024; /* 22.5 msec page scan interval */
2648 } else {
2649 type = PAGE_SCAN_TYPE_STANDARD; /* default */
2650 acp.interval = 0x0800; /* default 1.28 sec page scan */
2651 }
2652
2653 acp.window = 0x0012; /* default 11.25 msec page scan window */
2654
2655 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
2656 sizeof(acp), &acp);
2657 if (err < 0) {
2658 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002659 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002660 goto done;
2661 }
2662
2663 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
2664 if (err < 0) {
2665 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002666 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002667 goto done;
2668 }
2669
Johan Hedbergaee9b2182012-02-18 15:07:59 +02002670 err = cmd_complete(sk, index, MGMT_OP_SET_FAST_CONNECTABLE, 0,
2671 NULL, 0);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002672done:
2673 hci_dev_unlock(hdev);
2674 hci_dev_put(hdev);
2675
2676 return err;
2677}
2678
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002679static int load_long_term_keys(struct sock *sk, u16 index,
2680 void *cp_data, u16 len)
2681{
2682 struct hci_dev *hdev;
2683 struct mgmt_cp_load_long_term_keys *cp = cp_data;
2684 u16 key_count, expected_len;
2685 int i;
2686
2687 if (len < sizeof(*cp))
2688 return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS,
2689 EINVAL);
2690
2691 key_count = get_unaligned_le16(&cp->key_count);
2692
2693 expected_len = sizeof(*cp) + key_count *
2694 sizeof(struct mgmt_ltk_info);
2695 if (expected_len != len) {
2696 BT_ERR("load_keys: expected %u bytes, got %u bytes",
2697 len, expected_len);
2698 return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS,
2699 EINVAL);
2700 }
2701
2702 hdev = hci_dev_get(index);
2703 if (!hdev)
2704 return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS,
2705 ENODEV);
2706
2707 BT_DBG("hci%u key_count %u", index, key_count);
2708
2709 hci_dev_lock(hdev);
2710
2711 hci_smp_ltks_clear(hdev);
2712
2713 for (i = 0; i < key_count; i++) {
2714 struct mgmt_ltk_info *key = &cp->keys[i];
2715 u8 type;
2716
2717 if (key->master)
2718 type = HCI_SMP_LTK;
2719 else
2720 type = HCI_SMP_LTK_SLAVE;
2721
2722 hci_add_ltk(hdev, &key->addr.bdaddr, key->addr.type,
2723 type, 0, key->authenticated, key->val,
2724 key->enc_size, key->ediv, key->rand);
2725 }
2726
2727 hci_dev_unlock(hdev);
2728 hci_dev_put(hdev);
2729
2730 return 0;
2731}
2732
Johan Hedberg03811012010-12-08 00:21:06 +02002733int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
2734{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002735 void *buf;
2736 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02002737 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002738 u16 opcode, index, len;
Johan Hedberg03811012010-12-08 00:21:06 +02002739 int err;
2740
2741 BT_DBG("got %zu bytes", msglen);
2742
2743 if (msglen < sizeof(*hdr))
2744 return -EINVAL;
2745
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03002746 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02002747 if (!buf)
2748 return -ENOMEM;
2749
2750 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
2751 err = -EFAULT;
2752 goto done;
2753 }
2754
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002755 hdr = buf;
Johan Hedberg03811012010-12-08 00:21:06 +02002756 opcode = get_unaligned_le16(&hdr->opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002757 index = get_unaligned_le16(&hdr->index);
Johan Hedberg03811012010-12-08 00:21:06 +02002758 len = get_unaligned_le16(&hdr->len);
2759
2760 if (len != msglen - sizeof(*hdr)) {
2761 err = -EINVAL;
2762 goto done;
2763 }
2764
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002765 cp = buf + sizeof(*hdr);
2766
Johan Hedberg03811012010-12-08 00:21:06 +02002767 switch (opcode) {
Johan Hedberg02d98122010-12-13 21:07:04 +02002768 case MGMT_OP_READ_VERSION:
2769 err = read_version(sk);
2770 break;
Johan Hedberge70bb2e2012-02-13 16:59:33 +02002771 case MGMT_OP_READ_COMMANDS:
2772 err = read_commands(sk);
2773 break;
Johan Hedbergfaba42e2010-12-13 21:07:05 +02002774 case MGMT_OP_READ_INDEX_LIST:
2775 err = read_index_list(sk);
2776 break;
Johan Hedbergf7b64e62010-12-13 21:07:06 +02002777 case MGMT_OP_READ_INFO:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002778 err = read_controller_info(sk, index);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02002779 break;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002780 case MGMT_OP_SET_POWERED:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002781 err = set_powered(sk, index, cp, len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002782 break;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002783 case MGMT_OP_SET_DISCOVERABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002784 err = set_discoverable(sk, index, cp, len);
Johan Hedberg73f22f62010-12-29 16:00:25 +02002785 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002786 case MGMT_OP_SET_CONNECTABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002787 err = set_connectable(sk, index, cp, len);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002788 break;
Johan Hedbergf7c68692011-12-15 00:47:36 +02002789 case MGMT_OP_SET_FAST_CONNECTABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002790 err = set_fast_connectable(sk, index, cp, len);
Johan Hedbergf7c68692011-12-15 00:47:36 +02002791 break;
Johan Hedbergc542a062011-01-26 13:11:03 +02002792 case MGMT_OP_SET_PAIRABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002793 err = set_pairable(sk, index, cp, len);
Johan Hedbergc542a062011-01-26 13:11:03 +02002794 break;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02002795 case MGMT_OP_SET_LINK_SECURITY:
2796 err = set_link_security(sk, index, cp, len);
2797 break;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02002798 case MGMT_OP_SET_SSP:
2799 err = set_ssp(sk, index, cp, len);
2800 break;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02002801 case MGMT_OP_SET_HS:
2802 err = set_hs(sk, index, cp, len);
2803 break;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002804 case MGMT_OP_ADD_UUID:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002805 err = add_uuid(sk, index, cp, len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002806 break;
2807 case MGMT_OP_REMOVE_UUID:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002808 err = remove_uuid(sk, index, cp, len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002809 break;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002810 case MGMT_OP_SET_DEV_CLASS:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002811 err = set_dev_class(sk, index, cp, len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002812 break;
Johan Hedberg86742e12011-11-07 23:13:38 +02002813 case MGMT_OP_LOAD_LINK_KEYS:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002814 err = load_link_keys(sk, index, cp, len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002815 break;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002816 case MGMT_OP_DISCONNECT:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002817 err = disconnect(sk, index, cp, len);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002818 break;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002819 case MGMT_OP_GET_CONNECTIONS:
Szymon Janc8ce62842011-03-01 16:55:32 +01002820 err = get_connections(sk, index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002821 break;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002822 case MGMT_OP_PIN_CODE_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002823 err = pin_code_reply(sk, index, cp, len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002824 break;
2825 case MGMT_OP_PIN_CODE_NEG_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002826 err = pin_code_neg_reply(sk, index, cp, len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002827 break;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002828 case MGMT_OP_SET_IO_CAPABILITY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002829 err = set_io_capability(sk, index, cp, len);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002830 break;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002831 case MGMT_OP_PAIR_DEVICE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002832 err = pair_device(sk, index, cp, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002833 break;
Johan Hedberg28424702012-02-02 04:02:29 +02002834 case MGMT_OP_CANCEL_PAIR_DEVICE:
2835 err = cancel_pair_device(sk, index, buf + sizeof(*hdr), len);
2836 break;
Johan Hedberg124f6e32012-02-09 13:50:12 +02002837 case MGMT_OP_UNPAIR_DEVICE:
2838 err = unpair_device(sk, index, cp, len);
2839 break;
Johan Hedberga5c29682011-02-19 12:05:57 -03002840 case MGMT_OP_USER_CONFIRM_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002841 err = user_confirm_reply(sk, index, cp, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03002842 break;
2843 case MGMT_OP_USER_CONFIRM_NEG_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002844 err = user_confirm_neg_reply(sk, index, cp, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03002845 break;
Brian Gix604086b2011-11-23 08:28:33 -08002846 case MGMT_OP_USER_PASSKEY_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002847 err = user_passkey_reply(sk, index, cp, len);
Brian Gix604086b2011-11-23 08:28:33 -08002848 break;
2849 case MGMT_OP_USER_PASSKEY_NEG_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002850 err = user_passkey_neg_reply(sk, index, cp, len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002851 break;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002852 case MGMT_OP_SET_LOCAL_NAME:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002853 err = set_local_name(sk, index, cp, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002854 break;
Szymon Jancc35938b2011-03-22 13:12:21 +01002855 case MGMT_OP_READ_LOCAL_OOB_DATA:
2856 err = read_local_oob_data(sk, index);
2857 break;
Szymon Janc2763eda2011-03-22 13:12:22 +01002858 case MGMT_OP_ADD_REMOTE_OOB_DATA:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002859 err = add_remote_oob_data(sk, index, cp, len);
Szymon Janc2763eda2011-03-22 13:12:22 +01002860 break;
2861 case MGMT_OP_REMOVE_REMOTE_OOB_DATA:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002862 err = remove_remote_oob_data(sk, index, cp, len);
Szymon Janc2763eda2011-03-22 13:12:22 +01002863 break;
Johan Hedberg14a53662011-04-27 10:29:56 -04002864 case MGMT_OP_START_DISCOVERY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002865 err = start_discovery(sk, index, cp, len);
Johan Hedberg14a53662011-04-27 10:29:56 -04002866 break;
2867 case MGMT_OP_STOP_DISCOVERY:
Johan Hedbergd9306502012-02-20 23:25:18 +02002868 err = stop_discovery(sk, index, cp, len);
Johan Hedberg14a53662011-04-27 10:29:56 -04002869 break;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002870 case MGMT_OP_CONFIRM_NAME:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002871 err = confirm_name(sk, index, cp, len);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002872 break;
Antti Julku7fbec222011-06-15 12:01:15 +03002873 case MGMT_OP_BLOCK_DEVICE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002874 err = block_device(sk, index, cp, len);
Antti Julku7fbec222011-06-15 12:01:15 +03002875 break;
2876 case MGMT_OP_UNBLOCK_DEVICE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002877 err = unblock_device(sk, index, cp, len);
Antti Julku7fbec222011-06-15 12:01:15 +03002878 break;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002879 case MGMT_OP_LOAD_LONG_TERM_KEYS:
2880 err = load_long_term_keys(sk, index, cp, len);
2881 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002882 default:
Johan Hedberg72a734e2010-12-30 00:38:22 +02002883 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02002884 err = cmd_status(sk, index, opcode,
2885 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002886 break;
2887 }
Johan Hedberg72a734e2010-12-30 00:38:22 +02002888
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002889 if (err < 0)
Johan Hedberg72a734e2010-12-30 00:38:22 +02002890 goto done;
2891
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002892 err = msglen;
2893
2894done:
2895 kfree(buf);
2896 return err;
2897}
2898
Johan Hedbergb24752f2011-11-03 14:40:33 +02002899static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
2900{
2901 u8 *status = data;
2902
2903 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
2904 mgmt_pending_remove(cmd);
2905}
2906
Johan Hedberg744cf192011-11-08 20:40:14 +02002907int mgmt_index_added(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +02002908{
Johan Hedberg744cf192011-11-08 20:40:14 +02002909 return mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02002910}
2911
Johan Hedberg744cf192011-11-08 20:40:14 +02002912int mgmt_index_removed(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +02002913{
Johan Hedbergb24752f2011-11-03 14:40:33 +02002914 u8 status = ENODEV;
2915
Johan Hedberg744cf192011-11-08 20:40:14 +02002916 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002917
Johan Hedberg744cf192011-11-08 20:40:14 +02002918 return mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02002919}
2920
2921struct cmd_lookup {
Johan Hedberg03811012010-12-08 00:21:06 +02002922 struct sock *sk;
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002923 struct hci_dev *hdev;
Johan Hedberg03811012010-12-08 00:21:06 +02002924};
2925
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002926static void settings_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberg03811012010-12-08 00:21:06 +02002927{
Johan Hedberg03811012010-12-08 00:21:06 +02002928 struct cmd_lookup *match = data;
2929
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002930 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02002931
2932 list_del(&cmd->list);
2933
2934 if (match->sk == NULL) {
2935 match->sk = cmd->sk;
2936 sock_hold(match->sk);
2937 }
2938
2939 mgmt_pending_free(cmd);
2940}
2941
Johan Hedberg744cf192011-11-08 20:40:14 +02002942int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg03811012010-12-08 00:21:06 +02002943{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002944 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002945 int err;
Johan Hedberg03811012010-12-08 00:21:06 +02002946
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002947 if (!test_bit(HCI_MGMT, &hdev->dev_flags))
2948 return 0;
2949
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002950 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
Johan Hedberg03811012010-12-08 00:21:06 +02002951
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002952 if (powered) {
2953 u8 scan = 0;
2954
2955 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
2956 scan |= SCAN_PAGE;
2957 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
2958 scan |= SCAN_INQUIRY;
2959
2960 if (scan)
2961 hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
2962 } else {
Johan Hedbergb24752f2011-11-03 14:40:33 +02002963 u8 status = ENETDOWN;
Johan Hedberg744cf192011-11-08 20:40:14 +02002964 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002965 }
2966
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02002967 err = new_settings(hdev, match.sk);
Johan Hedberg03811012010-12-08 00:21:06 +02002968
2969 if (match.sk)
2970 sock_put(match.sk);
2971
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002972 return err;
Johan Hedberg03811012010-12-08 00:21:06 +02002973}
2974
Johan Hedberg744cf192011-11-08 20:40:14 +02002975int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg03811012010-12-08 00:21:06 +02002976{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002977 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002978 bool changed = false;
2979 int err = 0;
Johan Hedberg03811012010-12-08 00:21:06 +02002980
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002981 if (discoverable) {
2982 if (!test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
2983 changed = true;
2984 } else {
2985 if (test_and_clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
2986 changed = true;
2987 }
Johan Hedberg03811012010-12-08 00:21:06 +02002988
Johan Hedberged9b5f22012-02-21 20:47:06 +02002989 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp,
2990 &match);
2991
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02002992 if (changed)
2993 err = new_settings(hdev, match.sk);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002994
Johan Hedberg03811012010-12-08 00:21:06 +02002995 if (match.sk)
2996 sock_put(match.sk);
2997
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002998 return err;
Johan Hedberg03811012010-12-08 00:21:06 +02002999}
3000
Johan Hedberg744cf192011-11-08 20:40:14 +02003001int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg03811012010-12-08 00:21:06 +02003002{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02003003 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003004 bool changed = false;
3005 int err = 0;
Johan Hedberg03811012010-12-08 00:21:06 +02003006
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003007 if (connectable) {
3008 if (!test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3009 changed = true;
3010 } else {
3011 if (test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3012 changed = true;
3013 }
Johan Hedberg03811012010-12-08 00:21:06 +02003014
Johan Hedberged9b5f22012-02-21 20:47:06 +02003015 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev, settings_rsp,
3016 &match);
3017
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003018 if (changed)
3019 err = new_settings(hdev, match.sk);
Johan Hedberg03811012010-12-08 00:21:06 +02003020
3021 if (match.sk)
3022 sock_put(match.sk);
3023
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003024 return err;
Johan Hedberg03811012010-12-08 00:21:06 +02003025}
3026
Johan Hedberg744cf192011-11-08 20:40:14 +02003027int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003028{
Johan Hedbergca69b792011-11-11 18:10:00 +02003029 u8 mgmt_err = mgmt_status(status);
3030
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003031 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02003032 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Johan Hedbergca69b792011-11-11 18:10:00 +02003033 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003034
3035 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02003036 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Johan Hedbergca69b792011-11-11 18:10:00 +02003037 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003038
3039 return 0;
3040}
3041
Johan Hedberg744cf192011-11-08 20:40:14 +02003042int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
3043 u8 persistent)
Johan Hedberg03811012010-12-08 00:21:06 +02003044{
Johan Hedberg86742e12011-11-07 23:13:38 +02003045 struct mgmt_ev_new_link_key ev;
Johan Hedberg03811012010-12-08 00:21:06 +02003046
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003047 memset(&ev, 0, sizeof(ev));
Johan Hedberg03811012010-12-08 00:21:06 +02003048
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003049 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02003050 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
3051 ev.key.addr.type = MGMT_ADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003052 ev.key.type = key->type;
3053 memcpy(ev.key.val, key->val, 16);
3054 ev.key.pin_len = key->pin_len;
Johan Hedberg03811012010-12-08 00:21:06 +02003055
Johan Hedberg744cf192011-11-08 20:40:14 +02003056 return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02003057}
Johan Hedbergf7520542011-01-20 12:34:39 +02003058
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003059int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
3060{
3061 struct mgmt_ev_new_long_term_key ev;
3062
3063 memset(&ev, 0, sizeof(ev));
3064
3065 ev.store_hint = persistent;
3066 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
3067 ev.key.addr.type = key->bdaddr_type;
3068 ev.key.authenticated = key->authenticated;
3069 ev.key.enc_size = key->enc_size;
3070 ev.key.ediv = key->ediv;
3071
3072 if (key->type == HCI_SMP_LTK)
3073 ev.key.master = 1;
3074
3075 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
3076 memcpy(ev.key.val, key->val, sizeof(key->val));
3077
3078 return mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev,
3079 &ev, sizeof(ev), NULL);
3080}
3081
Johan Hedbergafc747a2012-01-15 18:11:07 +02003082int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Johan Hedbergb644ba32012-01-17 21:48:47 +02003083 u8 addr_type, u8 *name, u8 name_len,
3084 u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02003085{
Johan Hedbergb644ba32012-01-17 21:48:47 +02003086 char buf[512];
3087 struct mgmt_ev_device_connected *ev = (void *) buf;
3088 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02003089
Johan Hedbergb644ba32012-01-17 21:48:47 +02003090 bacpy(&ev->addr.bdaddr, bdaddr);
3091 ev->addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02003092
Johan Hedbergb644ba32012-01-17 21:48:47 +02003093 if (name_len > 0)
3094 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
3095 name, name_len);
3096
3097 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
3098 eir_len = eir_append_data(&ev->eir[eir_len], eir_len,
3099 EIR_CLASS_OF_DEV, dev_class, 3);
3100
3101 put_unaligned_le16(eir_len, &ev->eir_len);
3102
3103 return mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
3104 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02003105}
3106
Johan Hedberg8962ee72011-01-20 12:40:27 +02003107static void disconnect_rsp(struct pending_cmd *cmd, void *data)
3108{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01003109 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003110 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02003111 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003112
Johan Hedberg88c3df12012-02-09 14:27:38 +02003113 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3114 rp.addr.type = cp->addr.type;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003115
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003116 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, 0, &rp,
3117 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003118
3119 *sk = cmd->sk;
3120 sock_hold(*sk);
3121
Johan Hedberga664b5b2011-02-19 12:06:02 -03003122 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003123}
3124
Johan Hedberg124f6e32012-02-09 13:50:12 +02003125static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02003126{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003127 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02003128 struct mgmt_cp_unpair_device *cp = cmd->param;
3129 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02003130
3131 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02003132 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3133 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02003134
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003135 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
3136
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003137 cmd_complete(cmd->sk, cmd->index, cmd->opcode, 0, &rp, sizeof(rp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02003138
3139 mgmt_pending_remove(cmd);
3140}
3141
Johan Hedbergafc747a2012-01-15 18:11:07 +02003142int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
3143 u8 link_type, u8 addr_type)
Johan Hedbergf7520542011-01-20 12:34:39 +02003144{
Johan Hedberg4c659c32011-11-07 23:13:39 +02003145 struct mgmt_addr_info ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003146 struct sock *sk = NULL;
3147 int err;
3148
Johan Hedberg744cf192011-11-08 20:40:14 +02003149 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02003150
Johan Hedbergf7520542011-01-20 12:34:39 +02003151 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02003152 ev.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02003153
Johan Hedbergafc747a2012-01-15 18:11:07 +02003154 err = mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev),
3155 sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003156
3157 if (sk)
3158 sock_put(sk);
3159
Johan Hedberg124f6e32012-02-09 13:50:12 +02003160 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003161 hdev);
Johan Hedberga8a1d192011-11-10 15:54:38 +02003162
Johan Hedberg8962ee72011-01-20 12:40:27 +02003163 return err;
3164}
3165
Johan Hedberg88c3df12012-02-09 14:27:38 +02003166int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
3167 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02003168{
Johan Hedberg88c3df12012-02-09 14:27:38 +02003169 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003170 struct pending_cmd *cmd;
3171 int err;
3172
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003173 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003174 if (!cmd)
3175 return -ENOENT;
3176
Johan Hedberg88c3df12012-02-09 14:27:38 +02003177 bacpy(&rp.addr.bdaddr, bdaddr);
3178 rp.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02003179
Johan Hedberg88c3df12012-02-09 14:27:38 +02003180 err = cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003181 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003182
Johan Hedberga664b5b2011-02-19 12:06:02 -03003183 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003184
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003185 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
3186 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003187 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02003188}
Johan Hedberg17d5c042011-01-22 06:09:08 +02003189
Johan Hedberg48264f02011-11-09 13:58:58 +02003190int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
3191 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02003192{
3193 struct mgmt_ev_connect_failed ev;
3194
Johan Hedberg4c659c32011-11-07 23:13:39 +02003195 bacpy(&ev.addr.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02003196 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003197 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003198
Johan Hedberg744cf192011-11-08 20:40:14 +02003199 return mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003200}
Johan Hedberg980e1a52011-01-22 06:10:07 +02003201
Johan Hedberg744cf192011-11-08 20:40:14 +02003202int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003203{
3204 struct mgmt_ev_pin_code_request ev;
3205
Johan Hedbergd8457692012-02-17 14:24:57 +02003206 bacpy(&ev.addr.bdaddr, bdaddr);
3207 ev.addr.type = MGMT_ADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02003208 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003209
Johan Hedberg744cf192011-11-08 20:40:14 +02003210 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01003211 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003212}
3213
Johan Hedberg744cf192011-11-08 20:40:14 +02003214int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3215 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003216{
3217 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003218 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003219 int err;
3220
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003221 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003222 if (!cmd)
3223 return -ENOENT;
3224
Johan Hedbergd8457692012-02-17 14:24:57 +02003225 bacpy(&rp.addr.bdaddr, bdaddr);
3226 rp.addr.type = MGMT_ADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003227
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003228 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
3229 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003230
Johan Hedberga664b5b2011-02-19 12:06:02 -03003231 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003232
3233 return err;
3234}
3235
Johan Hedberg744cf192011-11-08 20:40:14 +02003236int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3237 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003238{
3239 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003240 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003241 int err;
3242
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003243 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003244 if (!cmd)
3245 return -ENOENT;
3246
Johan Hedbergd8457692012-02-17 14:24:57 +02003247 bacpy(&rp.addr.bdaddr, bdaddr);
3248 rp.addr.type = MGMT_ADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003249
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003250 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
3251 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003252
Johan Hedberga664b5b2011-02-19 12:06:02 -03003253 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003254
3255 return err;
3256}
Johan Hedberga5c29682011-02-19 12:05:57 -03003257
Johan Hedberg744cf192011-11-08 20:40:14 +02003258int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003259 u8 link_type, u8 addr_type, __le32 value,
3260 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03003261{
3262 struct mgmt_ev_user_confirm_request ev;
3263
Johan Hedberg744cf192011-11-08 20:40:14 +02003264 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03003265
Johan Hedberg272d90d2012-02-09 15:26:12 +02003266 bacpy(&ev.addr.bdaddr, bdaddr);
3267 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07003268 ev.confirm_hint = confirm_hint;
Johan Hedberga5c29682011-02-19 12:05:57 -03003269 put_unaligned_le32(value, &ev.value);
3270
Johan Hedberg744cf192011-11-08 20:40:14 +02003271 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01003272 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03003273}
3274
Johan Hedberg272d90d2012-02-09 15:26:12 +02003275int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
3276 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08003277{
3278 struct mgmt_ev_user_passkey_request ev;
3279
3280 BT_DBG("%s", hdev->name);
3281
Johan Hedberg272d90d2012-02-09 15:26:12 +02003282 bacpy(&ev.addr.bdaddr, bdaddr);
3283 ev.addr.type = link_to_mgmt(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08003284
3285 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
3286 NULL);
3287}
3288
Brian Gix0df4c182011-11-16 13:53:13 -08003289static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003290 u8 link_type, u8 addr_type, u8 status,
3291 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03003292{
3293 struct pending_cmd *cmd;
3294 struct mgmt_rp_user_confirm_reply rp;
3295 int err;
3296
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003297 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03003298 if (!cmd)
3299 return -ENOENT;
3300
Johan Hedberg272d90d2012-02-09 15:26:12 +02003301 bacpy(&rp.addr.bdaddr, bdaddr);
3302 rp.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003303 err = cmd_complete(cmd->sk, hdev->id, opcode, mgmt_status(status),
3304 &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03003305
Johan Hedberga664b5b2011-02-19 12:06:02 -03003306 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03003307
3308 return err;
3309}
3310
Johan Hedberg744cf192011-11-08 20:40:14 +02003311int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003312 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003313{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003314 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3315 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003316}
3317
Johan Hedberg272d90d2012-02-09 15:26:12 +02003318int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3319 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003320{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003321 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3322 status, MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003323}
Johan Hedberg2a611692011-02-19 12:06:00 -03003324
Brian Gix604086b2011-11-23 08:28:33 -08003325int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003326 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003327{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003328 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3329 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003330}
3331
Johan Hedberg272d90d2012-02-09 15:26:12 +02003332int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3333 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003334{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003335 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3336 status, MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003337}
3338
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003339int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
3340 u8 addr_type, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03003341{
3342 struct mgmt_ev_auth_failed ev;
3343
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003344 bacpy(&ev.addr.bdaddr, bdaddr);
3345 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003346 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03003347
Johan Hedberg744cf192011-11-08 20:40:14 +02003348 return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03003349}
Johan Hedbergb312b1612011-03-16 14:29:37 +02003350
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003351int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
3352{
3353 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg47990ea2012-02-22 11:58:37 +02003354 bool changed = false;
3355 int err = 0;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003356
3357 if (status) {
3358 u8 mgmt_err = mgmt_status(status);
3359 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
3360 cmd_status_rsp, &mgmt_err);
3361 return 0;
3362 }
3363
Johan Hedberg47990ea2012-02-22 11:58:37 +02003364 if (test_bit(HCI_AUTH, &hdev->flags)) {
3365 if (!test_and_set_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
3366 changed = true;
3367 } else {
3368 if (test_and_clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
3369 changed = true;
3370 }
3371
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003372 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
3373 &match);
3374
Johan Hedberg47990ea2012-02-22 11:58:37 +02003375 if (changed)
3376 err = new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003377
3378 if (match.sk)
3379 sock_put(match.sk);
3380
3381 return err;
3382}
3383
Johan Hedbergcacaf522012-02-21 00:52:42 +02003384static int clear_eir(struct hci_dev *hdev)
3385{
3386 struct hci_cp_write_eir cp;
3387
3388 if (!(hdev->features[6] & LMP_EXT_INQ))
3389 return 0;
3390
3391 memset(&cp, 0, sizeof(cp));
3392
3393 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
3394}
3395
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003396int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 status)
3397{
3398 struct cmd_lookup match = { NULL, hdev };
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003399 int err;
3400
3401 if (status) {
3402 u8 mgmt_err = mgmt_status(status);
3403 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev,
3404 cmd_status_rsp, &mgmt_err);
3405 return 0;
3406 }
3407
3408 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
3409
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003410 err = new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003411
Johan Hedbergcacaf522012-02-21 00:52:42 +02003412 if (match.sk) {
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003413 sock_put(match.sk);
3414
Johan Hedbergcacaf522012-02-21 00:52:42 +02003415 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3416 update_eir(hdev);
3417 else
3418 clear_eir(hdev);
3419 }
3420
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003421 return err;
3422}
3423
Johan Hedberg744cf192011-11-08 20:40:14 +02003424int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02003425{
3426 struct pending_cmd *cmd;
3427 struct mgmt_cp_set_local_name ev;
3428 int err;
3429
3430 memset(&ev, 0, sizeof(ev));
3431 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
3432
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003433 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003434 if (!cmd)
3435 goto send_event;
3436
3437 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02003438 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
Johan Hedbergca69b792011-11-11 18:10:00 +02003439 mgmt_status(status));
Johan Hedbergb312b1612011-03-16 14:29:37 +02003440 goto failed;
3441 }
3442
Johan Hedberg744cf192011-11-08 20:40:14 +02003443 update_eir(hdev);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03003444
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003445 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0, &ev,
Johan Hedbergb312b1612011-03-16 14:29:37 +02003446 sizeof(ev));
3447 if (err < 0)
3448 goto failed;
3449
3450send_event:
Johan Hedberg744cf192011-11-08 20:40:14 +02003451 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
Johan Hedbergb312b1612011-03-16 14:29:37 +02003452 cmd ? cmd->sk : NULL);
3453
3454failed:
3455 if (cmd)
3456 mgmt_pending_remove(cmd);
3457 return err;
3458}
Szymon Jancc35938b2011-03-22 13:12:21 +01003459
Johan Hedberg744cf192011-11-08 20:40:14 +02003460int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
3461 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01003462{
3463 struct pending_cmd *cmd;
3464 int err;
3465
Johan Hedberg744cf192011-11-08 20:40:14 +02003466 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01003467
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003468 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003469 if (!cmd)
3470 return -ENOENT;
3471
3472 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02003473 err = cmd_status(cmd->sk, hdev->id,
Johan Hedbergca69b792011-11-11 18:10:00 +02003474 MGMT_OP_READ_LOCAL_OOB_DATA,
3475 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01003476 } else {
3477 struct mgmt_rp_read_local_oob_data rp;
3478
3479 memcpy(rp.hash, hash, sizeof(rp.hash));
3480 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
3481
Johan Hedberg744cf192011-11-08 20:40:14 +02003482 err = cmd_complete(cmd->sk, hdev->id,
3483 MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003484 0, &rp, sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01003485 }
3486
3487 mgmt_pending_remove(cmd);
3488
3489 return err;
3490}
Johan Hedberge17acd42011-03-30 23:57:16 +03003491
Johan Hedberg48264f02011-11-09 13:58:58 +02003492int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Johan Hedberg561aafb2012-01-04 13:31:59 +02003493 u8 addr_type, u8 *dev_class, s8 rssi,
Johan Hedberge319d2e2012-01-15 19:51:59 +02003494 u8 cfm_name, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03003495{
Johan Hedberge319d2e2012-01-15 19:51:59 +02003496 char buf[512];
3497 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02003498 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03003499
Johan Hedberg1dc06092012-01-15 21:01:23 +02003500 /* Leave 5 bytes for a potential CoD field */
3501 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Andre Guedes7d262f82012-01-10 18:20:49 -03003502 return -EINVAL;
3503
Johan Hedberg1dc06092012-01-15 21:01:23 +02003504 memset(buf, 0, sizeof(buf));
3505
Johan Hedberge319d2e2012-01-15 19:51:59 +02003506 bacpy(&ev->addr.bdaddr, bdaddr);
3507 ev->addr.type = link_to_mgmt(link_type, addr_type);
3508 ev->rssi = rssi;
3509 ev->confirm_name = cfm_name;
Johan Hedberge17acd42011-03-30 23:57:16 +03003510
Johan Hedberg1dc06092012-01-15 21:01:23 +02003511 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02003512 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03003513
Johan Hedberg1dc06092012-01-15 21:01:23 +02003514 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
3515 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
3516 dev_class, 3);
3517
3518 put_unaligned_le16(eir_len, &ev->eir_len);
3519
3520 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03003521
Johan Hedberge319d2e2012-01-15 19:51:59 +02003522 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03003523}
Johan Hedberga88a9652011-03-30 13:18:12 +03003524
Johan Hedbergb644ba32012-01-17 21:48:47 +02003525int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
3526 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03003527{
Johan Hedbergb644ba32012-01-17 21:48:47 +02003528 struct mgmt_ev_device_found *ev;
3529 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
3530 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03003531
Johan Hedbergb644ba32012-01-17 21:48:47 +02003532 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03003533
Johan Hedbergb644ba32012-01-17 21:48:47 +02003534 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03003535
Johan Hedbergb644ba32012-01-17 21:48:47 +02003536 bacpy(&ev->addr.bdaddr, bdaddr);
3537 ev->addr.type = link_to_mgmt(link_type, addr_type);
3538 ev->rssi = rssi;
3539
3540 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
3541 name_len);
3542
3543 put_unaligned_le16(eir_len, &ev->eir_len);
3544
Johan Hedberg053c7e02012-02-04 00:06:00 +02003545 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev,
3546 sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03003547}
Johan Hedberg314b2382011-04-27 10:29:57 -04003548
Andre Guedes7a135102011-11-09 17:14:25 -03003549int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
Johan Hedberg164a6e72011-11-01 17:06:44 +02003550{
3551 struct pending_cmd *cmd;
Johan Hedbergf808e162012-02-19 12:52:07 +02003552 u8 type;
Johan Hedberg164a6e72011-11-01 17:06:44 +02003553 int err;
3554
Andre Guedes203159d2012-02-13 15:41:01 -03003555 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3556
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003557 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003558 if (!cmd)
3559 return -ENOENT;
3560
Johan Hedbergf808e162012-02-19 12:52:07 +02003561 type = hdev->discovery.type;
3562
3563 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
3564 &type, sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02003565 mgmt_pending_remove(cmd);
3566
3567 return err;
3568}
3569
Andre Guedese6d465c2011-11-09 17:14:26 -03003570int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
3571{
3572 struct pending_cmd *cmd;
3573 int err;
3574
3575 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
3576 if (!cmd)
3577 return -ENOENT;
3578
Johan Hedbergd9306502012-02-20 23:25:18 +02003579 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
3580 &hdev->discovery.type,
3581 sizeof(hdev->discovery.type));
Johan Hedberg03811012010-12-08 00:21:06 +02003582 mgmt_pending_remove(cmd);
3583
3584 return err;
3585}
Johan Hedberg314b2382011-04-27 10:29:57 -04003586
Johan Hedberg744cf192011-11-08 20:40:14 +02003587int mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04003588{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02003589 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02003590 struct pending_cmd *cmd;
3591
Andre Guedes343fb142011-11-22 17:14:19 -03003592 BT_DBG("%s discovering %u", hdev->name, discovering);
3593
Johan Hedberg164a6e72011-11-01 17:06:44 +02003594 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003595 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003596 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003597 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003598
3599 if (cmd != NULL) {
Johan Hedbergf808e162012-02-19 12:52:07 +02003600 u8 type = hdev->discovery.type;
3601
Johan Hedbergd9306502012-02-20 23:25:18 +02003602 cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0,
Johan Hedbergf808e162012-02-19 12:52:07 +02003603 &type, sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02003604 mgmt_pending_remove(cmd);
3605 }
3606
Johan Hedbergf963e8e2012-02-20 23:30:44 +02003607 memset(&ev, 0, sizeof(ev));
3608 ev.type = hdev->discovery.type;
3609 ev.discovering = discovering;
3610
3611 return mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04003612}
Antti Julku5e762442011-08-25 16:48:02 +03003613
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003614int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003615{
3616 struct pending_cmd *cmd;
3617 struct mgmt_ev_device_blocked ev;
3618
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003619 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003620
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003621 bacpy(&ev.addr.bdaddr, bdaddr);
3622 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003623
Johan Hedberg744cf192011-11-08 20:40:14 +02003624 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
3625 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003626}
3627
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003628int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003629{
3630 struct pending_cmd *cmd;
3631 struct mgmt_ev_device_unblocked ev;
3632
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003633 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003634
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003635 bacpy(&ev.addr.bdaddr, bdaddr);
3636 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003637
Johan Hedberg744cf192011-11-08 20:40:14 +02003638 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
3639 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003640}
Marcel Holtmannd7b7e792012-02-20 21:47:49 +01003641
3642module_param(enable_hs, bool, 0644);
3643MODULE_PARM_DESC(enable_hs, "Enable High Speed support");
3644
3645module_param(enable_le, bool, 0644);
3646MODULE_PARM_DESC(enable_le, "Enable Low Energy support");